# patient-records — the care plan and visit records

> Client seam `client/src/services/patientRecords/` · `USE_PATIENT_RECORDS_MOCK = true` (**mock is primary**) · 5 server ops
> Last verified: 2026-07-30 against commit `d3ec723` and swagger.v1.json (2026-07-29).

The clinical content: a family-owned **care plan** (medications, routine, tasks) and the **append-only**
visit records nurses write against it. The patient rows themselves are [patients.md](patients.md).

## Endpoints

| Method | Path | Verdict |
| --- | --- | --- |
| GET | `/api/v1/patients/{patientId}/care_record` | wired — the care plan |
| PUT | `/api/v1/patients/{patientId}/care_record` | wired — **the only `PUT` in the API** |
| GET | `/api/v1/patients/{patientId}/care_records` | wired · paginated (**`page`/`pageSize`**) — visit history |
| POST | `/api/v1/patients/{patientId}/care_records` | wired — a nurse writes one visit record |
| GET | `/api/v1/patients/{patientId}/record_access` | wired — **ask before you read** |

All `[Authorize]`. **No phantoms — every route the client calls exists.** The seam is mocked for UI
completeness, not because the contract is missing.

> Singular vs. plural is load-bearing here: `care_record` (no `s`) is the **plan**; `care_records` is the
> **visit history**. They are different resources on adjacent paths.

## Two different ownership models on one path

| | `care_record` (plan) | `care_records` (visits) |
| --- | --- | --- |
| Owner | the **family** (the customer) | the **nurse** who performed the visit |
| Write | `PUT` — upsert, replaces | `POST` — **append only** |
| Edit after the fact | yes, it is a living plan | **no** |
| Delete | no | **no** |

**A nurse can never edit or delete a visit record.** It is a clinical record: append-only is the whole
point, and there is no endpoint that would allow otherwise. Do not add one.

## `record_access` — check before you read

`GET record_access` answers "may this caller read this patient's records, and if not, why". The client
calls it **first** and renders the denial state rather than firing a read and interpreting an error.

Two reasons come back, and they are deliberately hard to tell apart from outside:

| `RecordAccessDeniedReason` | Means |
| --- | --- |
| `no_access` | The patient exists; you are not authorised |
| `not_found` | No such patient — **or** a tenancy mismatch |

That second row is the platform's tenancy rule: a row you do not own is a **404, never a 403**, because a
403 confirms it exists. See [../api-contract.md](../api-contract.md#status-codes).

## Shape rules the JSON does not express

- **Every record body is encrypted at rest** and decrypted only for an authorised caller. Care content is
  **never** projected into a list, never logged, and never included in a search index.
- **Nurse read access is scoped by an active booking**, not by having ever cared for the patient. The
  two-stage clinical disclosure rule applies: full care content is readable only post-confirmation, only by
  the assigned nurse and admin. See [bookings.md](bookings.md).
- **`CarePlanDto` is `{ patientId, medications, routine, tasks }`** — three structured lists, not free text,
  so the client can render a schedule and a checklist rather than a blob.
- **`CareRecordDto.taskResults` is structured** (REQ-027, delivered): each visit reports per-task outcomes
  against the plan's tasks, which is what lets the family see whether the routine was actually followed.
- **`nurseName` is on the visit record** so the history is attributable without a per-row lookup.
- Dose units, frequency presets and times-of-day are **codes**; the UI labels are i18n keys. Never render
  the code, and never parse a frequency into a schedule client-side.

## Enums

| Vocabulary | Values |
| --- | --- |
| `DoseUnit` | `tablet` `capsule` `drop` `cc` `unit` |
| `FrequencyPreset` | `once_daily` `twice_daily` `three_times_daily` `every_8_hours` `as_needed` |
| `TimeOfDayCode` | `morning` `noon` `evening` `night` |
| `RecordAccessDeniedReason` | `no_access` `not_found` |
| `CareRecordTab` *(client UI only)* | `medications` `routine` `history` `tasks` |

`as_needed` (PRN) has **no** time-of-day and must not be rendered on a schedule grid.

## Open REQs

| REQ | Status | Effect |
| --- | --- | --- |
| REQ-027 | delivered | The family-owned care record (medications/routine/tasks), `record_access`, and structured task results are all served |
