Files
teatea-pension/.trellis/tasks/archive/2026-07/07-02-care-service-workspace/design.md

5.6 KiB

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