diff --git a/docs/api/README.md b/docs/api/README.md index a41bf6d84..52e49b52b 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -1,8 +1,12 @@ # HealthLog API Spec -`openapi.yaml` is the canonical OpenAPI 3.1 description for the HealthLog -Next.js API. It is the source of truth for the native iOS client's -DTO codegen. +`openapi.yaml` is the OpenAPI 3.1 description for the HealthLog +Next.js API and the source of truth for the native iOS client's DTO +codegen. The file is **generated**: `pnpm openapi:generate` emits it +from the Zod registry under `src/lib/openapi/` (`registry.ts` plus the +route modules in `src/lib/openapi/routes/`). Do not edit the YAML by +hand; the next generation overwrites it, and CI (`openapi:check`) +fails the build when the committed YAML drifts from the registry. The MCP server is documented separately — it is a distinct contract over JSON-RPC, not part of the REST OpenAPI spec: @@ -34,36 +38,38 @@ npx @redocly/cli build-docs docs/api/openapi.yaml --output docs/api/index.html npx @redocly/cli lint docs/api/openapi.yaml ``` -The spec is expected to be lint-clean (errors = 0). Some warnings are -intentional: - -- `no-server-example.com` — `http://localhost:3000` is the dev server. -- `operation-2xx-response` / `operation-4xx-response` — webhook + redirect - endpoints intentionally omit one or the other. -- `no-unused-components` — `ReminderPhase` is exposed for client codegen - even though no path response references it directly. +The spec is expected to be lint-clean (errors = 0). Warnings such as +`no-server-example.com` for the localhost dev server are tolerated; +re-run the lint to see what it produces against the current file +before treating a warning as a regression. ## Layout -- **`info`** — title, version (mirrored from `package.json`), description. -- **`servers`** — production `https://healthlog.bombeck.io` plus - `http://localhost:3000` for local development. -- **`tags`** — domain groupings (`Auth`, `Measurements`, `Medications`, - `Mood`, `Dashboard`, `Insights`, `Achievements`, `DoctorReport`, - `Integrations`, `User`, `Tokens`, `Notifications`, `Onboarding`, - `Health`, `Settings`, `Analytics`, `Export`, `AuditLog`, - `Monitoring`, `Webhooks`, `Ingest`, `Admin`). +- **`info`** — title, description, and `version` mirrored automatically + from `package.json` at generation time. Never bump it by hand. +- **`servers`** — `https://healthlog.example.com` as the self-hosted + placeholder plus `http://localhost:3000` for local development. +- **`tags`** — domain groupings; the current set lives at the top of + the generated file (`Auth`, `Measurements`, `Medications`, `Mood`, + `Analytics`, `Insights`, `Consent`, `Dashboard`, `Notifications`, + `Devices`, `Export`, `Sync`, `Cycle`, `MeasurementReminders`, + `Labs`, `Illness`, `Documents`, `Records`, `Admin`, `Meta`, + `Retired`). - **`securitySchemes`**: - `bearerAuth` — long-lived `hlk_*` API tokens issued via `POST /api/tokens`. Required on `/api/ingest/medication`. - `sessionCookie` — HttpOnly `healthlog_session` cookie set by the password and passkey login flows. Used by the web app and any iOS client running inside a web view. -- **`components.schemas`** — DTOs for all routes plus the underlying - Prisma models (e.g. `Measurement`, `Medication`, `MedicationIntakeEvent`, - `MoodEntry`, `User`, `DashboardLayout`, `ApiEnvelope`, `ApiError`). -- **`paths`** — all routes from `src/app/api/**/route.ts`, including - the `/api/admin/*` family which is tagged `Admin` and marked internal. +- **`components.schemas`** — DTOs for the documented routes plus the + underlying Prisma models (e.g. `Measurement`, `Medication`, + `MedicationIntakeEvent`, `MoodEntry`, `User`, `DashboardLayout`, + `ApiEnvelope`, `ApiError`). +- **`paths`** — the client-facing REST surface. Not every + `src/app/api/**/route.ts` is in the contract: most `/api/admin/*` + routes, the OAuth connect/callback legs, and the webhook surfaces + are not documented here. The `Retired` tag lists removed paths that + answer `410 Gone`. ## Conventions @@ -79,8 +85,12 @@ intentional: When adding or changing routes: 1. Update the relevant route handler under `src/app/api/**/route.ts`. -2. Mirror the change in `openapi.yaml`. Keep `operationId` camelCase and - stable — the iOS codegen keys off it. -3. Run `npx @redocly/cli lint docs/api/openapi.yaml` and resolve all - errors. Warnings are tolerated when documented above. -4. Bump `info.version` if the change is breaking for clients. +2. Change the Zod schemas and their `.meta()` registrations under + `src/lib/openapi/` (registry entry plus the matching module in + `src/lib/openapi/routes/`). Keep `operationId` camelCase and + stable; the iOS codegen keys off it. +3. Run `pnpm openapi:generate` and commit the regenerated + `openapi.yaml` alongside the schema change. CI's `openapi:check` + fails on drift. +4. Never edit the YAML directly and never bump `info.version` by + hand; the version follows `package.json` at generation time. diff --git a/docs/api/mcp-capabilities.md b/docs/api/mcp-capabilities.md index 92e0a0e23..9cb7dc7cb 100644 --- a/docs/api/mcp-capabilities.md +++ b/docs/api/mcp-capabilities.md @@ -87,6 +87,9 @@ server-authoritative path; no new analytics is computed at the wire. | `get_integration_status` | Sync health of connected devices/services — connected, last sync, reauth-required/failing — to answer "why is my data stale?". No secrets or tokens. | | `get_preventive_care` | What preventive care is coming up: the user's own configured Vorsorge reminders (upcoming/overdue checkups with next-due dates) plus the appointments booked as future visits. Surfaces configured items, invents nothing. | | `get_visits` | The user's own past doctor visits over a bounded window (default 12 months, optional practitioner-name filter): date, status, kind, practitioner + specialty, the visit's own reason/outcome, and any linked condition labels. `{ present: false }` when none was ever recorded. | +| `get_intraday_pulse` | The 10-minute heart-rate shape for one local day (hourly grain outside the dense-retention window), with at most one cautious descriptive elevated-at-rest window. Gated on the `insights` module. | +| `get_ecg_recordings` | Metadata for the user's ECG recordings (time, duration, sampling rate, lead, the device's own rhythm classification). Never the waveform, never a re-classification. Gated on the `insights` module. | +| `get_nutrients` | Without an argument, the presence overview per logged nutrient code; with one, that code's per-day summed series plus its EFSA reference. Gated on the opt-in `nutrients` module. | | `search` | Free-text search over the user's record (metric domains, medications, lab analytes). Returns `{ results: [{ id, title, url }], nextCursor? }`. | | `fetch` | Hydrate one record by the id `search` returned (`metric:weight`, `med:`, `lab:LDL`). Returns `{ id, title, text, url, metadata }` with a citation deep-link. | @@ -196,6 +199,7 @@ doubles as honest discovery. | `healthlog://lab/{analyte}` | One lab analyte's recent readings (value, unit, reference range, status). | | `healthlog://medication/{id}` | One medication by id, with its schedules. User-scoped (`{present:false}` if not yours). | | `healthlog://report/doctor-visit/{window}` | The doctor-visit summary over a chosen window. | +| `healthlog://nutrient/{code}` | One nutrient's per-day intake series plus its EFSA reference (opt-in `nutrients` module). | ## Prompts (skills)