Dev Reference

Patient Portal

Secure messaging, document management, online payments, and sensitive-class consent gating for patient-facing portal features.

Data Classification: Mixed scoping. PortalMessage and Payment are org-scoped (partitioned by OrganizationID). PatientDocument and SensitiveClassGating are global (no OrganizationID) — these are exceptions to IC rule #11 because documents and consent travel with the patient across organizations. See Data Model for ownership rules.

PortalMessage

Org-scoped. Trust Tier: T1 (PHI in message body).

Schema

FieldTypeRequiredPKFKNotes
PortalMessageIDUUIDYesYesPrimary key
PatientIDUUIDYesPatient
SenderUserIDUUIDYesUser
RecipientUserIDUUIDYesUser
AttachedDocumentIDUUIDNoPatientDocument
ThreadIDUUIDYesGroups messages in a thread
SubjectString(100)Yes
BodyTextYes
CategoryString(50)Yese.g. Clinical, Billing, Administrative
PriorityString(50)YesNormal / Urgent
IsReadByRecipientBoolYes
ReadDateTimeDateTime (UTC)No
IsPatientInitiatedBoolYes
ResponseSLAHoursIntNoSLA deadline in hours
IsActiveBoolYes
OrganizationIDUUIDYesOrganizationTenant partition key
CreatedByUserIDUUIDYesUserAudit
CreatedDateTimeDateTime (UTC)YesAudit
UpdatedByUserIDUUIDYesUserAudit
UpdatedDateTimeDateTime (UTC)YesAudit

RBAC

RoleTierPermissions
Patient (10)T1Read own messages; send new messages
Family Proxy (10*)T1Consent-gated access to patient messages
Front Desk (30)T1Read / respond to administrative messages
MA / RN (40)T1Read messages; attach to encounter
Clinician (60)T1Read / respond to clinical messages; sign documents
Manager (70)T1Read all; manage SLA configuration
EditAMI (90)T1Schema administration

PatientDocument

Global entity (no OrganizationID) — exception to IC rule #11. Documents travel with the patient. Trust Tier: T1 (PHI content).

Schema

FieldTypeRequiredPKFKNotes
PatientDocumentIDUUIDYesYesPrimary key
PatientIDUUIDYesPatient
EncounterIDUUIDNoEncounter
SourceOrganizationIDUUIDYesOrganizationOriginating org (not partition key)
DocumentTypeString(50)Yese.g. Lab Result, Consent, Insurance Card
FileNameString(100)Yes
MimeTypeString(50)Yesapplication/pdf, image/jpeg, etc.
FileSizeBytesIntYes
StorageUrlStringYesBlob storage URL (SAS-token gated)
DescriptionString(200)No
IsSensitiveBoolYesTriggers consent gating
SensitiveClassString(50)Noe.g. BehavioralHealth, SubstanceUse, HIV
IsActiveBoolYes
CreatedByUserIDUUIDYesUserAudit
CreatedDateTimeDateTime (UTC)YesAudit
UpdatedByUserIDUUIDYesUserAudit
UpdatedDateTimeDateTime (UTC)YesAudit

RBAC

RoleTierPermissions
Patient (10)T1Read own documents; upload documents
Family Proxy (10*)T1Consent-gated read access
Front Desk (30)T1Read non-sensitive; upload insurance/admin docs
MA / RN (40)T1Read; attach to encounter
Clinician (60)T1Read all; sign clinical documents
Manager (70)T1Read all; manage document types
EditAMI (90)T1Schema administration

Payment

Org-scoped. Trust Tier: T2 (financial data, no clinical PHI).

Schema

FieldTypeRequiredPKFKNotes
PaymentIDUUIDYesYesPrimary key
PatientIDUUIDYesPatient
EncounterIDUUIDNoEncounter
StatementIDUUIDNoPatientStatement
PaymentPlanIDUUIDNoOptional payment plan reference
PaymentAmountMoneyYes
PaymentCurrencyCodeString(3)YesISO 4217
PaymentMethodString(50)YesCreditCard / DebitCard / ACH / Cash / Check
PaymentProcessorRefString(100)NoStripe/processor transaction ID
PaymentDateTimeDateTime (UTC)Yes
CategoryString(50)YesCopay / Coinsurance / Deductible / Balance
IsPortalInitiatedBoolYes
StatusString(50)YesPending / Completed / Failed / Refunded / Voided
IsActiveBoolYes
OrganizationIDUUIDYesOrganizationTenant partition key
CreatedByUserIDUUIDYesUserAudit
CreatedDateTimeDateTime (UTC)YesAudit
UpdatedByUserIDUUIDYesUserAudit
UpdatedDateTimeDateTime (UTC)YesAudit

RBAC

RoleTierPermissions
Patient (10)T2Read own payments; initiate portal payments
Front Desk (30)T2Read; create copay payments
MA / RN (40)T2Read
Biller (51)T2Create / adjust payments
Clinician (60)T2Read
Manager (70)T2Read all; void / refund
EditAMI (90)T2Schema administration

SensitiveClassGating

Global entity (no OrganizationID) — exception to IC rule #11. Consent decisions travel with the patient. Trust Tier: T1 (consent metadata for sensitive categories).

Schema

FieldTypeRequiredPKFKNotes
SensitiveClassGatingIDUUIDYesYesPrimary key
PatientIDUUIDYesPatient
SensitiveClassString(50)YesBehavioralHealth / SubstanceUse / HIV / ReproductiveHealth
IsConsentedBoolYes
ConsentedDateTimeDateTime (UTC)No
ConsentRevokedDateTimeDateTime (UTC)No
ProxyAccessAllowedBoolYesFamily proxy can view this class
SharingWithOtherOrgsAllowedBoolYesCross-org sharing permission
GatingPromptTextTextNoDisplayed to user before access
IsActiveBoolYes
CreatedByUserIDUUIDYesUserAudit
CreatedDateTimeDateTime (UTC)YesAudit
UpdatedByUserIDUUIDYesUserAudit
UpdatedDateTimeDateTime (UTC)YesAudit

RBAC

RoleTierPermissions
Patient (10)T1Read own consent records; update consent decisions
Family Proxy (10*)T1Read if ProxyAccessAllowed = true
Clinician (60)T1Read consent status (not modify)
Manager (70)T1Read all consent records
EditAMI (90)T1Schema administration

Trust tier roll-up

EntityTierSource of truth
PortalMessage1 — Internal canonicalAuthored by a verified user within the system (patient or practice staff)
PatientDocument1 — Internal canonicalUploaded by an authenticated user; content trust depends on source (patient-attested vs. practice-scanned)
Payment1 — Internal canonicalCreated from payment processor webhook (confirmed) or manual entry (pending confirmation)
SensitiveClassGating1 — Internal canonicalSet by the patient or authorized proxy; consent actions are audited

RBAC matrix (IC 0–100 scale)

RoleLevelPortalMessagePatientDocumentPaymentSensitiveClassGating
Patient (self)10Read own; write ownRead own; upload ownRead ownRead own; update own consent
Family / Proxy10*Read dependant’s; write on behalfRead dependant’s (consent-gated)Read dependant’sRead dependant’s; update with consent chain
Front desk (Jordan)30Read / respond in own orgRead (own org context)Create copay paymentsRead gating state
MA / RN (Tasha)40Read / respond clinicalRead; attach to encounterReadRead gating state
Biller (Priya)51Read billing-categoryRead billing-relatedCreate / adjust / reconcileRead gating state
Clinician (Dr. M / Maria)60Read / respond clinicalRead all; sign off on uploaded docsReadRead; recommend consent change
Practice manager (Sam)70Read all in org; manage SLARead allVoid / refundRead; override proxy disputes
EditAMI90Required for any AMI schema break (per IC hard rule #5)

* Proxy level is context-dependent: the base level is 10, but proxy access is further gated by the SensitiveClassGating consent flags and the authorization-chain trace. A proxy without consent for a sensitive class cannot view data in that class even at level 10.

FK Relationship Diagram

erDiagram
    Patient ||--o{ PortalMessage : "sends/receives"
    User ||--o{ PortalMessage : "SenderUserID"
    User ||--o{ PortalMessage : "RecipientUserID"
    PatientDocument ||--o{ PortalMessage : "AttachedDocumentID"
    Patient ||--o{ PatientDocument : "owns"
    Encounter ||--o{ PatientDocument : "attached to"
    Patient ||--o{ Payment : "pays"
    Encounter ||--o{ Payment : "for"
    PatientStatement ||--o{ Payment : "StatementID"
    Patient ||--o{ SensitiveClassGating : "consents"
    SensitiveClassGating ||..|| PatientDocument : "gates access"
    

Message Thread State Machine

stateDiagram-v2
    [*] --> Draft
    Draft --> Sent : Patient or staff sends
    Sent --> Read : Recipient opens
    Read --> Replied : Recipient responds
    Replied --> Read : Original sender reads reply
    Read --> Closed : Manager closes thread
    Replied --> Closed : Manager closes thread
    Sent --> Escalated : SLA breached
    Escalated --> Read : Recipient opens after escalation
    

Functional Requirements

  1. P0 The system SHALL allow patients to send secure messages to their care team and receive threaded responses.
  2. P0 The system SHALL enforce sensitive-class consent gating: documents marked IsSensitive=true are hidden from any user/proxy until the matching SensitiveClassGating record shows IsConsented=true.
  3. P0 The system SHALL allow patients to grant or revoke consent per sensitive class (BehavioralHealth, SubstanceUse, HIV, ReproductiveHealth) at any time.
  4. P0 The system SHALL process online payments (credit/debit/ACH) via the patient portal with PCI-DSS compliant tokenization (no card numbers stored).
  5. P0 The system SHALL support family/proxy access gated by per-class ProxyAccessAllowed flag on SensitiveClassGating.
  6. P1 The system SHALL track message SLA (ResponseSLAHours) and trigger escalation workflows when deadlines are breached.
  7. P1 The system SHALL allow patients to upload documents (insurance cards, forms, images) with file-type validation and virus scanning.
  8. P1 The system SHALL display patient statements and support partial payments and payment plans.
  9. P1 The system SHALL allow staff to attach portal messages to an encounter record.
  10. P1 The system SHALL support message categorization (Clinical, Billing, Administrative) for routing.
  11. P1 The system SHALL allow billers to create and adjust payment records for copays and balances.
  12. P1 The system SHALL allow managers to void or refund payments with audit trail.
  13. P2 The system SHALL support cross-org document sharing when SharingWithOtherOrgsAllowed=true on the relevant SensitiveClassGating record.
  14. P2 The system SHALL support payment receipt generation and email delivery.
  15. P2 The system SHALL provide read-receipt tracking for portal messages.
  16. P2 The system SHALL allow patients to download their complete document history as a ZIP export.

Non-Functional Requirements

icApplication Overrides

How the four Patient Portal AMI schemas turn into a live application: module-specific stack additions, override component bindings, a versioning worked example, environment cascade, and RBAC enforcement.

Shared generation map. The IC platform code-gen flow, default bindings, environment cascade, RBAC model, and CLI commands are identical across all modules. See the IC Reference for the canonical shared reference. This section covers only Patient Portal-specific content.

Technology stack P0

The shared platform stack (Cosmos DB, Redis, IC-generated API, Angular 21, SQS+SNS, OpenTelemetry, etc.) is documented in the IC Reference. Module-specific additions:

LayerTechnologyNotes
Document storageS3 + KMSEncrypted at rest with KMS-managed keys; pre-signed URLs for download. Per BUILD decision in PRD §4.6.
FHIR Patient Access APIFHIR R4 + HTI-1 USCDI v3Mandatory per HTI-1 §170.315(e)(1). Supports VDT, SMART on FHIR app launch.
SMART on FHIROAuth 2.0 + OpenID ConnectThird-party app launch with granular scopes. Backend-services SMART for server-to-server.
Messaging / notificationsTwilio (BAA), AWS SES, SendGridBUY primitives per PRD §4.6. TCPA opt-in/out management built on Twilio.
TranslationAWS Translate / DeepL ProBUY; human-in-loop for clinical content accuracy.
Patient educationUpToDate Patient Engagement, MedlinePlus (free), HealthwiseBUY licensed content per PRD §4.6.
Payment processorIntegrated processor (PCI DSS Level 1)Tokenized cardholder data; no PII stored locally.
Accessibility auditaxe-core + manual WCAG 2.2 AA auditAutomated scan on every CI build; manual audit on every release.

Portal-specific override bindings P1

These overrides are declared in rules/*.rules.json and replace the default for the matching field name pattern.

FieldDefault would renderOverride componentWhy
PortalMessage.CategoryString50plain text inputic-ng21-portal-1-category-selectConstrained dropdown: General / Clinical / Billing / Scheduling / Document / Prescription.
PortalMessage.PriorityString50plain text inputic-ng21-portal-1-priority-selectConstrained dropdown: Normal / Urgent / Emergency.
PortalMessage.BodyTextgeneric textareaic-ng21-portal-1-message-composeCustom compose widget with attachment linking and character count.
PatientDocument.DocumentTypeString50plain text inputic-ng21-portal-1-doc-type-selectConstrained dropdown: InsuranceCard / AdvanceDirective / OutsideRecord / ConsentForm / LabResult / ImagingReport / Other.
PatientDocument.StorageUrlurl inputic-ng21-portal-1-document-uploadCustom flow: drag-and-drop / camera capture → S3 upload → pre-signed URL → link to message.
Payment.AmountMoney + Payment.CurrencyCodeString3generic money inputic-ng21-portal-1-payment-formPayment card with statement context, processor integration, and plan enrollment.
Payment.PaymentMethodString50plain text inputic-ng21-portal-1-payment-method-selectConstrained dropdown: CreditCard / ACH / Cash / Check / PaymentPlan / Financing.
SensitiveClassGating.SensitiveClassString50plain text inputic-ng21-portal-1-sensitive-class-gateCustom consent-gating widget: class name, consent toggle, proxy-access toggle, prompt text, with audit logging.
(synthetic) AVS viewern/aic-ng21-portal-1-avs-viewerCustom: encounter-derived AVS with plain-language toggle, translation selector, and education-content links.
(synthetic) VDT actionsn/aic-ng21-portal-1-vdt-actionsCustom: View / Download (CCDA + FHIR Bundle) / Transmit (SMART on FHIR launch) with audit logging.
(synthetic) Slot pickern/aic-ng21-portal-1-slot-pickerCustom: provider + visit-type filter, eligibility status badge, booking confirmation with cost estimate.

Versioning — worked example P0

All Patient Portal artifacts are versioned break.feature.bug.buildtimestamp per IC hard rule #9. The example below traces a feature bump on SensitiveClassGating.

SensitiveClassGating 1.0.0.20260515T100000Z — Initial schema. Seven business fields plus three global audit columns (no OrganizationID — deliberate exception). Five sensitive classes: MentalHealth, SUD, HIV, Genetic, Reproductive. Component ic-ng21-portal-1-sensitive-class-gate binds to sensitiveclassgating@1.0.0.* via the DI manifest.

SensitiveClassGating 1.1.0.20260801T120000Z — feature bump — Adds a single optional field, AutoReConsentIntervalDaysInt, to support periodic re-consent prompts (e.g., ask the patient to re-confirm consent every 365 days for SUD data per 42 CFR Part 2 best practice). Per the IC change matrix:

ChangeVersion impactApproval neededMin permission
Add optional field AutoReConsentIntervalDaysIntfeature bump (1.0.0 → 1.1.0)NoWrite (51)

Because the change is backward-compatible, the component tag stays ic-ng21-portal-1-sensitive-class-gate. Existing UI consumers continue to bind sensitiveclassgating@1.x.* and ignore the new field. New UI surfaces that need the re-consent feature bind sensitiveclassgating@^1.1.0. No new database is required (IC rule #13 only applies to break bumps).

SensitiveClassGating 2.0.0.20280101T120000Z — break bump (illustrative) — An illustrative future break bump: SensitiveClassString50 is changed from a free-form String to a strongly-typed Enum with a fixed value set enforced at the DB layer. Per the IC change matrix this is change field type — break bump, EditAMI (90) approval, and per IC rule #13 a new database is provisioned with ETL from the old one. The component tag becomes ic-ng21-portal-2-sensitive-class-gate; consumers must re-bind. The old database stays live for the configured grace period (default 90 days) for rollback.

Illustrative. The 2.0.0 example is illustrative of the change matrix and IC rule #13; it is not a committed roadmap item.

Patient Portal environment details

EnvPayment processorFHIR Patient Access API
DevProcessor sandboxLocal FHIR server (test data)
QAProcessor sandboxHL7 reference server + test patients
UATProcessor UATLive FHIR endpoints (test patients)
ProdProcessor productionLive FHIR endpoints (real patients)

Patient Portal RBAC notes

Cross-Module Dependencies

See also: Patient Portal walkthrough · IC Reference