feat: build collaboration workspaces
This commit is contained in:
@@ -251,6 +251,73 @@ return jsonSuccess("健康数据已加载", data);
|
||||
|
||||
#### Correct
|
||||
|
||||
## Scenario: Collaboration Module Data Management
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: changing 设备运维, 公告通知, 规则预警, or 家属服务 pages, APIs, seed data, or schema.
|
||||
- Applies because these modules are real Drizzle/PostgreSQL-backed collaboration workspaces, not reserved/static module pages.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- `GET /api/devices/assets`, `POST /api/devices/assets`, `PATCH|DELETE /api/devices/assets/[id]`
|
||||
- `POST /api/devices/tickets`, `PATCH|DELETE /api/devices/tickets/[id]`
|
||||
- `GET|POST /api/notices`, `POST|PATCH|DELETE /api/notices/[id]`
|
||||
- `GET|POST /api/alerts/rules`, `PATCH|DELETE /api/alerts/rules/[id]`
|
||||
- `POST /api/alerts/triggers`, `PATCH|DELETE /api/alerts/triggers/[id]`
|
||||
- `GET|POST /api/family/contacts`, `PATCH|DELETE /api/family/contacts/[id]`
|
||||
- `POST /api/family/visits`, `PATCH|DELETE /api/family/visits/[id]`
|
||||
- `POST /api/family/feedback`, `PATCH|DELETE /api/family/feedback/[id]`
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Reads require module read permission: `device:read`, `notice:read`, `alert:read`, or `family:read`.
|
||||
- Mutations require module manage permission: `device:manage`, `notice:manage`, `alert:manage`, or `family:manage`.
|
||||
- All records must be scoped by active `organizationId`; updates/deletes must filter by both `id` and `organizationId`.
|
||||
- Read APIs return `{ success: true, reason, data }` where `data` is the module workspace DTO.
|
||||
- Mutation APIs return the changed resource under a resource-specific key and write an audit log after successful persistence.
|
||||
- Seed demo rows only inside `seedDefaultWorkspaceData(organizationId)` and connect them to real seeded elders/devices/rules where applicable.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Missing session or permission -> response from `requirePermission`; domain helper must not be called.
|
||||
- Missing active organization -> `400` with a Chinese reason asking the user to select an organization.
|
||||
- Invalid enum, empty required title/name/content, invalid date -> `400`.
|
||||
- Cross-organization or missing referenced record -> `404` with entity-specific reason.
|
||||
- Insert/update returning no row -> structured mutation failure with status `500` or `404`.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: Server page checks read permission, loads persisted workspace data, and passes serializable DTOs to a Client Component.
|
||||
- Good: Client refreshes by calling the module read API after mutations.
|
||||
- Good: notice read receipts use `POST /api/notices/[id]` with read permission; create/update/delete use manage permission.
|
||||
- Base: alert rules and triggers are manually managed in v1; no background rule engine is implied.
|
||||
- Bad: rendering fake collaboration counters or rows on reserved pages after these modules have real tables.
|
||||
- Bad: updating a record by `id` alone without the active organization filter.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- `pnpm db:generate`, then review SQL for additive collaboration enums/tables/indexes/FKs.
|
||||
- `pnpm lint`, `pnpm type-check`, `pnpm test`, and `pnpm build`.
|
||||
- API route tests should cover permission denial, missing active organization, successful create/update audit, and missing/cross-organization mutation failures.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```ts
|
||||
await database.update(alertTriggers).set({ status }).where(eq(alertTriggers.id, id));
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```ts
|
||||
await database
|
||||
.update(alertTriggers)
|
||||
.set({ status, updatedAt: new Date() })
|
||||
.where(and(eq(alertTriggers.id, id), eq(alertTriggers.organizationId, organizationId)));
|
||||
```
|
||||
|
||||
```ts
|
||||
const data = await listHealthAdminData(organizationId);
|
||||
return jsonSuccess("健康数据已加载", { data });
|
||||
|
||||
Reference in New Issue
Block a user