Consent Model
See Architecture → Auth + Consent Flow for the full sequence diagrams + resolution-order flowchart.
5 consent paths
When a PHI-route handler carries @ConsentScope("<scope>"), the ConsentGuard resolves in strict order — short-circuit on first ALLOW:
- Admin bypass —
authSource=admin_bypass+ captured rationale - Patient self — the patient accessing their own record
- Standing consent — active
consentsrow granting scope to user or care-team member - Break-glass — time-bounded (15 min) emergency access with captured justification + HIGH-severity audit + async care-manager notification + patient alert
- Intake bootstrap —
@IntakeExemptroutes only (patient creation + first-visit encounter)
Deny on none-of-the-above → 403 + audit w/ deny reason.
Consent scopes catalog
| Scope | Grants |
|---|---|
patient_self | patient accessing own record |
contact_disclosure | provider can see contact details |
referral_read | specialist can see referral chain |
family_read | family member view |
care_team | whole-team visibility |
decision_graph_read | AI decision lineage access |
memory.read | retrieval endpoint access |
medical_record_view | standard EHR chart view |
break_glass_override | break-glass session scope |
Roles
admin | provider | nurse | coordinator | patient
Adding a new role requires a spec amendment. Each role's allowed scopes are defined in apps/api/src/modules/consent/scope-matrix.ts.
Key guarantees
- Per-request evaluation — no cache. Revocation is immediate.
- No silent broad access — every deny path writes an audit event with deny reason.
- Break-glass audit — HIGH severity + care-manager notification + patient alert.
- Patient-id filter at repo — FR-013d defense-in-depth; even if consent guard misconfigured, the repo layer refuses unscoped PHI reads for non-admin callers.
Family groups + proxy consent
Parents / guardians manage minor accounts (spec 013):
- Proxy consent scoped to minor's record
- Age-of-majority graduation — minor's 18th birthday triggers automatic transition prompt; parent loses proxy; minor retains all history
- Family group can grant each other
family_readscope
Revocation path
ACL + consent combined
SPEC-01 Week 7-8 consent hardening (spec 046) added post-resolver ACL check:
- Entity-level
acl.roles[]evaluated AFTER consent resolution - Even allowed-by-consent access can be denied by ACL
- Break-glass does NOT bypass ACL (FR-046-005) — consent-denied-at-ACL still denies
get_manysilently filters denied entities (FR-046-014)
See specs 046 (memory-store-consent-hardening) for the full ACL model.