P3-1-T6. loadShareViewData now returns the link's document set as metadata only
(id, title, kind, documentDate, byteSize, servingClass) — scoped to the
membership rows, the owner, and live rows; the blob column is never selected
(the serve route is the only decrypt path). Register documentCount on the share
summary, documentIds on create, and the public /c/{token}/d/{id} serve route in
the OpenAPI contract; regenerate docs/api/openapi.yaml.
P2-1-T7/T8/T9.
- document-content-index-backfill: on-demand per-user pg-boss job that indexes
a user's not-yet-indexed image/PDF documents via one provider transcription
each. Consent + budget gated, id-cursor forward walk, capped per run, stops
on budget exhaustion, resumable. Queue + worker registered in the maintenance
registrar (no cron — deliberate action only). POST /reindex triggers it.
- rotation: register DocumentContentIndex.textEncrypted and add a dedicated
block that re-encrypts the text AND re-tokenises the blind index under the new
active HKDF subkey in one update (P2-D7).
- OpenAPI: suggest / summary / index / reindex paths; hasContentIndex on the
document schema; assistAvailable + contentIndex on usage. Regenerated
docs/api/openapi.yaml.
The filter bar derived its condition chips from the loaded corpus, so an
episode whose only linked documents sat pages deep in the timeline never
surfaced a chip — the condition route into an older document silently
disappeared at four-digit corpus sizes. The usage endpoint (already read
on page mount) now returns `linkedEpisodes` — every episode carrying at
least one live document link, one indexed grouped query, no blobs — and
the view unions it with the active-filter fallback. Additive DTO change;
OpenAPI regenerated.
The documents route table picks up every delta: conditionLinks +
servingClass on the document DTO (render/download by servingClass, never
by MIME guess; unknown kind values decode as OTHER), the broadened upload
accept-set with the 413/415 error contract and the 200+meta.duplicate
dedupe outcome, episodeIds on upload and PATCH (replace-set), the kind[] /
episodeId / year list facets, the class-aware /original posture, and the
new /restore, /bulk, and /usage endpoints. Regenerated docs/api/openapi.yaml
committed alongside; openapi:check is clean.
Task: W1-T14.
Two new self-report instruments join the mental-wellbeing engine on the
existing PHQ-9 / GAD-7 infrastructure:
- WHO-5 Well-Being Index: 5 items on the 6-point 5..0 scale over the last
two weeks; the reported total is raw-sum x 4 (0-100) per the official
WHO scoring (WHO/UCN/MSD/MHE/2024.1, CC BY-NC-SA 3.0 IGO). A total of
50 or below follows the WHO comment (below 50 = indication for further
assessment).
- Sleep Condition Indicator: 8 DSM-5-aligned items, 0-4 each with
item-specific anchors, total 0-32, higher = better sleep; a total of
16 or below maps to the probable-insomnia range of the source
publication (Espie et al., BMJ Open 2014;4:e004183, CC BY-NC,
(c) Sleepio Limited).
The instrument registry generalises rather than forking: per-item answer
ceilings, option order/label schemes, recall-stem captions, a reported-
score multiplier, score direction (higher-is-better inverts the follow-up
threshold), per-instrument attribution lines, and the validated-item
locale set are now instrument properties. Scoring stays server-
authoritative; the create route validates the per-instrument answer
ceiling and projects the total onto a COMPUTED WHO5_SCORE / SCI_SCORE
measurement row (never client-attributable), which also auto-satisfies a
planned screening reminder. Migration 0226 adds the enum values
(additive, idempotent). OpenAPI regenerated.
Neither instrument carries a self-harm item; the PHQ-9 item-9 crisis
routing is unchanged.
Groundwork for the plan confirm/manage UI. The CoachPlan pipeline has been
complete on the server since v1.21.3/v1.22 — extractor writes proposals
(status "proposed", per-user cap, de-dup, encrypted prose), the PATCH
confirms proposed -> active, buildCoachPlansBlock injects the top-6 active
plans into the snapshot, and the review sweep drives the reviewDate
lifecycle — but no surface ever listed or confirmed a proposal, so the
extraction spend had no user-visible outcome.
Two additive contract changes the UI needs:
- GET /api/coach/plans accepts ?scope=open|past|all (open = proposed +
active + review_due, past = met + abandoned + reviewed, all = no status
clause) so the management page reads its ledger in one round-trip.
Mutually exclusive with ?status=; both omitted keeps today's
non-terminal default unchanged.
- Plan items now carry sourceConversationId so the chat thread can show
only the proposals born in the open conversation.
OpenAPI regenerated; route tests cover the scope mappings, the
status+scope 422, and the provenance passthrough.
The MED_COMPLIANCE hero ring carried the pooled 7-day adherence
percentage — a mystery number next to today-focused scores. It now
answers the question the hero poses: how many of today's doses are
done. The resolver reads takenToday/scheduledToday off the snapshot's
own medsToday block (one shared builder call, no second tally); score
stays the rounded 0..100 progress for wire compatibility and a new
additive doses field carries the taken/scheduled pair. No dose
scheduled today means no ring, and the band is progress semantics —
green once everything is taken, yellow while doses remain, never red
(a pending morning dose is not an alert state).
The web ring renders the tally (1/3) with a doses label over the ring
system's constant green arc — the same green family the compliance
surfaces in Insights paint — instead of a band gradient; the derived
rings keep their exact insights hues. ScoreRing gains documented
valueText/ariaLabel overrides for tally-shaped centres. OpenAPI
regenerated; labels land in all six locales.
The structured Allergy / FamilyHistoryEntry stores reached FHIR export
only: the doctor-report PDF shipped without the two sections every
clinical intake asks for first, and the Coach knew allergies only from
the free-text answer — a penicillin allergy recorded in the structured
records UI never reached either surface.
Doctor report: two new section toggles (allergies, familyHistory; both
default ON, same stance as labs) across the prefs schema, the export
selection, the aggregator, the PDF renderer, and the export panel. The
tables render stored fields only — substance/category/kind/severity/
reaction/status and relationship/condition/age-at-onset; the reaction
decrypts fail-soft per row and free-text notes are never read, matching
the illness-journal stance. OpenAPI regenerated for the extended
sections shape.
Coach: the about-me context block now appends the structured rows as
clearly labelled entries (authoritative over the free-text answer on
conflict); the projection is a pure composer with unit tests. New
section labels land in all six locales.
The Vorsorge card resolves both rules at once: the action button keeps
its constant look in every state (v1.27.5), and a screening reminder's
action reads 'start the check-in' instead of the numeric measure
wording (this wave).
Resolve the selected rings server-side and publish them as scoreRings
on the dashboard snapshot (additive, optional for cached payloads).
READINESS, RECOVERY_SCORE and SLEEP_SCORE go through the same
computeDerivedMetric dispatcher the derived batch route calls, with the
profile loaded once via the shared loader; MED_COMPLIANCE pools the
7-day adherence across active non-PRN medications through the canonical
compliance engine (taken over taken-plus-missed, skips out of the
denominator) and bands on the targets-tile thresholds. Rings gate on
their owning module plus the insights gate for the derived trio, drop
out when no data backs them, and resolve fail-soft per ring so a
throwing engine never sinks the snapshot. OpenAPI regenerated.
PHQ9_SCORE / GAD7_SCORE join the Vorsorge reminder type allow-list as
their own "Seelisches Wohlbefinden" group, with a 4-week default
cadence (both instruments cover the last two weeks; 28 joins the
interval presets). The reminders ride the existing activity-aware
engine unchanged: they fire only when overdue, and a completed check-in
auto-satisfies them — the assessment route now kicks the eventful
reminder-satisfy worker, which resolves against the server-written
score row; the 15-min cron stays the idempotent safety-net. The
screening reminder's primary action opens the check-in page (a score is
never typed in), and the dispatcher gates the reminder on the opt-in
mental-health module so a disabled module never nags. OpenAPI spec
regenerated for the widened MeasurementReminderType enum.
Each completed PHQ-9 / GAD-7 administration already projects its total
onto a PHQ9_SCORE / GAD7_SCORE measurement row (unit score, linked via
externalId assessment:<id>). Those rows were attributed MANUAL — a
client-writable source. The projection is a server-derived value, so it
now writes source COMPUTED, the same server-owned source RECOVERY_SCORE
uses: no client write surface can attribute COMPUTED, so a forged score
trend point cannot enter through the measurement POST. Migration 0225
re-attributes the existing assessment-linked projection rows; a score a
user typed into the generic measurement form keeps MANUAL. OpenAPI
description updated and the spec regenerated.
Add a Google Health connection that reads Fitbit, Pixel Watch, and Fitbit
Air data through the user's Google account, alongside the existing Fitbit
connection, as the path forward before the classic Fitbit Web API sunsets
in September 2026.
Surface the Google Health integration to the operator and document the
setup honestly.
- A settings card matching the other integration cards: the BYO Google
client id and secret form, connect and disconnect, a manual sync, and
a distinct reconnect prompt when the connection needs fresh consent.
- Register the card in the connections panel and extend the integration
key, the docs-link provider, and the query-key factory.
- Translations for the card copy across all six locales. The copy states
plainly that this reads Fitbit, Pixel Watch, and Fitbit Air through the
user's Google account, that it succeeds the Fitbit connection Google
retires in September 2026, that the operator registers their own Google
client, that stress and readiness are not available, and that a
periodic reconnect may be needed.
- Rewrite the Google Health runbook into the real setup: a Google Cloud
project, the Health API, an OAuth consent screen kept in Testing, a
Web Server client, the callback redirect, the four Restricted scopes,
the hundred-test-user ceiling, and the reconnect caveat.
- Regenerate the OpenAPI contract for the new measurement source.
Narrow the workout create schema's source to the client-writable set
(MANUAL, APPLE_HEALTH), matching the measurement write surfaces, so a
client cannot forge a server-owned source into the cross-source picker.
Apply the single-entry plausibility bound to the measurement batch
timestamps so a backdated or future-dated row can no longer slip past
the batch path. Regenerate the OpenAPI contract.
Restore the daily briefing when it cites your own vitals (the number-grounding
gate stripped it on any blood-pressure, pulse, weight, mood or sleep figure it
did not recognise), surface a medication's dose as a tag beside its category,
let the custom on-time window switch stay on, and drop the layout-shifting
back-link from the Appearance sub-pages.