Skip to main content

Consent Model

See Architecture → Auth + Consent Flow for the full sequence diagrams + resolution-order flowchart.

When a PHI-route handler carries @ConsentScope("<scope>"), the ConsentGuard resolves in strict order — short-circuit on first ALLOW:

  1. Admin bypassauthSource=admin_bypass + captured rationale
  2. Patient self — the patient accessing their own record
  3. Standing consent — active consents row granting scope to user or care-team member
  4. Break-glass — time-bounded (15 min) emergency access with captured justification + HIGH-severity audit + async care-manager notification + patient alert
  5. Intake bootstrap@IntakeExempt routes only (patient creation + first-visit encounter)

Deny on none-of-the-above → 403 + audit w/ deny reason.

ScopeGrants
patient_selfpatient accessing own record
contact_disclosureprovider can see contact details
referral_readspecialist can see referral chain
family_readfamily member view
care_teamwhole-team visibility
decision_graph_readAI decision lineage access
memory.readretrieval endpoint access
medical_record_viewstandard EHR chart view
break_glass_overridebreak-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.

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_read scope

Revocation path

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_many silently filters denied entities (FR-046-014)

See specs 046 (memory-store-consent-hardening) for the full ACL model.