192 lines
5.6 KiB
Markdown
192 lines
5.6 KiB
Markdown
# Health Care Admin Page Design
|
|
|
|
## Summary
|
|
|
|
Add a dedicated management route under `/settings/health` for persisted elder health data. This keeps operational navigation (`/health`) separate from backend data administration, matching the user's direction to split the management surface into its own page.
|
|
|
|
## Route Boundary
|
|
|
|
- Unscoped route: `app/(app)/app/settings/health/page.tsx`
|
|
- Scoped route: `app/(app)/app/[organizationSlug]/settings/health/page.tsx`
|
|
- Optional redirect source: none in MVP. `/app/health` stays independent.
|
|
- Navigation: add a management item under `管理系统`.
|
|
- Breadcrumbs: add `"/settings/health": "健康数据管理"`.
|
|
|
|
The page should follow existing settings pages:
|
|
|
|
1. Server Component loads `getCurrentAuthContext()`.
|
|
2. Redirect unauthenticated users to `/login`.
|
|
3. Redirect users without `health:read` back to a safe workspace route.
|
|
4. Load persisted initial data through server helpers.
|
|
5. Render a focused Client Component for filtering and mutation UI.
|
|
|
|
## Data Model
|
|
|
|
All tables use `organizationId` for tenant scope and `createdAt` / `updatedAt` timestamps.
|
|
|
|
### `health_profiles`
|
|
|
|
- `id`
|
|
- `organizationId`
|
|
- `elderId`
|
|
- `allergyNotes`
|
|
- `medicalHistory`
|
|
- `medicationNotes`
|
|
- `careRestrictions`
|
|
- `emergencyNotes`
|
|
- `createdAt`
|
|
- `updatedAt`
|
|
|
|
Constraint: unique `(organizationId, elderId)` so each elder has one admin health profile.
|
|
|
|
### `vital_records`
|
|
|
|
- `id`
|
|
- `organizationId`
|
|
- `elderId`
|
|
- `recordedAt`
|
|
- `source`: `manual | device | import`
|
|
- `systolicBp`
|
|
- `diastolicBp`
|
|
- `heartRate`
|
|
- `temperatureTenths`
|
|
- `spo2`
|
|
- `bloodGlucoseTenths`
|
|
- `weightTenths`
|
|
- `notes`
|
|
- `createdByAccountId`
|
|
- `createdAt`
|
|
- `updatedAt`
|
|
|
|
Integer tenths avoid PostgreSQL numeric string handling for MVP decimal values.
|
|
|
|
### `chronic_conditions`
|
|
|
|
- `id`
|
|
- `organizationId`
|
|
- `elderId`
|
|
- `name`
|
|
- `status`: `active | controlled | resolved`
|
|
- `diagnosedAt`
|
|
- `treatmentNotes`
|
|
- `followUpNotes`
|
|
- `createdAt`
|
|
- `updatedAt`
|
|
|
|
### `health_anomaly_reviews`
|
|
|
|
- `id`
|
|
- `organizationId`
|
|
- `elderId`
|
|
- `vitalRecordId`
|
|
- `severity`: `info | warning | critical`
|
|
- `status`: `pending | reviewed | resolved`
|
|
- `title`
|
|
- `description`
|
|
- `reviewedByAccountId`
|
|
- `reviewedAt`
|
|
- `resolutionNotes`
|
|
- `createdAt`
|
|
- `updatedAt`
|
|
|
|
`vitalRecordId` is nullable so reviews can also be created directly against an elder health concern.
|
|
|
|
## Server Helpers
|
|
|
|
Create `modules/health/`:
|
|
|
|
- `modules/health/types.ts`
|
|
- shared enum values, labels, API DTO types, and validators.
|
|
- `modules/health/server/operations.ts`
|
|
- `listHealthAdminData(organizationId: string)`
|
|
- `upsertHealthProfile(...)`
|
|
- `createVitalRecord(...)`
|
|
- `createChronicCondition(...)`
|
|
- `updateHealthReview(...)`
|
|
- `modules/health/components/HealthAdminClient.tsx`
|
|
- client-side tabs, filters, dialogs/forms, optimistic-free refresh.
|
|
|
|
Server reads should batch queries by organization and join elders once. Avoid per-elder database calls.
|
|
|
|
## API Design
|
|
|
|
MVP route handlers:
|
|
|
|
- `GET /api/health/admin`
|
|
- permission: `health:read`
|
|
- returns metrics, elders, profiles, recent vitals, chronic conditions, reviews.
|
|
- `PUT /api/health/profiles/[elderId]`
|
|
- permission: `health:manage`
|
|
- validates elder belongs to active organization.
|
|
- upserts one profile.
|
|
- `POST /api/health/vitals`
|
|
- permission: `health:manage`
|
|
- validates elder belongs to active organization.
|
|
- creates vital record.
|
|
- may create a pending review if values exceed MVP thresholds.
|
|
- `POST /api/health/chronic-conditions`
|
|
- permission: `health:manage`
|
|
- validates elder belongs to active organization.
|
|
- creates chronic condition.
|
|
- `PATCH /api/health/reviews/[id]`
|
|
- permission: `health:manage`
|
|
- validates review belongs to active organization.
|
|
- updates status and review metadata.
|
|
|
|
All responses use `ApiResult`.
|
|
|
|
## Permission Design
|
|
|
|
Update `modules/core/types.ts` and `modules/core/server/permissions.ts`:
|
|
|
|
- Add `health:read`
|
|
- Add `health:manage`
|
|
- Add permission definitions in category `健康`
|
|
- Grant defaults:
|
|
- `org_admin`: read/manage
|
|
- `manager`: read/manage
|
|
- `caregiver`: read/manage unless user chooses stricter admin-only behavior
|
|
- `viewer`: read
|
|
|
|
This avoids overloading `elder:update` for a separate health management page.
|
|
|
|
## UI Design
|
|
|
|
The page should look like an internal management console:
|
|
|
|
- Header: `健康数据管理`, short description, manage badge if allowed.
|
|
- Metrics: elders with profiles, vitals today, active chronic conditions, pending reviews.
|
|
- Tabs:
|
|
- `健康档案`: elder list with profile completeness and edit dialog.
|
|
- `生命体征`: recent vitals table and add-vital dialog.
|
|
- `慢病记录`: condition table and add-condition dialog.
|
|
- `异常复核`: pending/reviewed/resolved queue with review action.
|
|
- Filters: elder search, status/severity select, source select where useful.
|
|
|
|
Keep tables and cards dense; no landing-page composition.
|
|
|
|
## Compatibility And Rollback
|
|
|
|
- Existing `/app/health` remains unchanged in MVP, limiting frontend blast radius.
|
|
- New tables are additive; rollback is dropping the generated health tables/enums and removing nav/API/page files.
|
|
- Existing seed file has uncommitted work. Implementation must read and preserve user changes in `modules/core/server/default-workspace-data.ts` before adding health seed rows.
|
|
|
|
## Validation
|
|
|
|
Required:
|
|
|
|
- `pnpm db:generate`
|
|
- Review generated SQL in `drizzle/`
|
|
- `pnpm lint`
|
|
- `pnpm type-check`
|
|
- `pnpm build`
|
|
|
|
Manual checks:
|
|
|
|
- login as authorized user and open `/app/{slug}/settings/health`
|
|
- create/update a health profile
|
|
- create a vital record
|
|
- create or review an abnormal item
|
|
- verify reload persists records
|
|
- verify mutation with insufficient permission returns `403`
|