Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

For: Organization administrators and billing staff Last Updated: 2026-02-23 Permission Required: pm.portal.manage

Overview

The PM-12 Patient Portal provides patient self-service capabilities. This guide covers configuration, proxy management, and troubleshooting.

Portal Architecture

Authentication Flow

  1. Patient registers with email matching their pm_patients record
  2. Supabase Auth creates identity; pf_profiles.portal_patient_id links to patient
  3. Login creates an audit row in pm_portal_sessions (append-only)
  4. Account lockout triggers after 5 consecutive failed attempts

Data Isolation

  • RLS: pm_portal_has_org_access() and pm_portal_visible_patient_ids() (SECURITY DEFINER)
  • Application: usePortalPatientId() hook scopes all portal queries
  • Double enforcement: Both layers must pass for data access

Proxy Authorization

Granting Proxy Access

Staff with pm.portal.manage permission can authorize proxy access:
  1. Navigate to the patient’s record in PM
  2. Add a proxy entry in pm_portal_users with:
    • proxy_for_patient_id: The patient being represented
    • proxy_relationship: parent, legal_guardian, healthcare_decision_maker, or other
    • proxy_expires_at: Expiration date (required)

Revoking Proxy Access

Set proxy_expires_at to a past date or update status to inactive. The proxy user will immediately lose access to the linked patient’s data.

Proxy Rules

  • Proxy access is always time-limited
  • Expired proxies return no data (enforced at RLS and application layers)
  • A user can be a proxy for multiple patients
  • Proxy audit trail is maintained in pm_portal_sessions

Session Management

Audit Trail

All portal sessions are recorded in pm_portal_sessions:
  • portal_user_id, ip_address, user_agent, created_at
  • Sessions are append-only — no UPDATE or DELETE allowed
  • revoked_at is set on sign-out

Account Lockout

  • After 5 failed login attempts, pm_portal_users.status is set to locked
  • Staff can unlock by updating the status back to active
  • Lockout does not affect the Supabase Auth account itself

Security Configuration

MFA

  • Patients can self-enroll in TOTP MFA via the portal Security page
  • pm_portal_users.mfa_enabled flag tracks enrollment status
  • Supabase Auth handles TOTP factor management natively
  • Backup codes are displayed once during enrollment

Rate Limiting

  • Portal login attempts are tracked per-user
  • No IP-based rate limiting at the application layer (rely on Supabase Auth and infrastructure-level protections)

Feature Integration Summary

FeatureSource SpecPortal Capability
AppointmentsPM-03View upcoming/past, cancel
Health RecordsCL-*View chart, medications, goals (consent-gated)
FormsPF-08Complete intake/consent forms
DemographicsPM-01View info, submit update requests
BillingPM-09View balance, payment history
MessagesPM-14Secure messaging with care team
When a patient’s chart has SUD (Substance Use Disorder) indicated:
  • The portal checks for active Part 2 consent via cl_check_sud_consent RPC
  • Without consent, SUD-related data (e.g., risk level) is suppressed from the portal view
  • Non-SUD clinical data (medications, treatment goals) remains accessible per the 21st Century Cures Act
  • A consent restriction banner is shown to the patient
  • This is enforced at both the RLS layer (database) and the application layer (useConsentCheck)

Troubleshooting

IssueResolution
Patient can’t registerVerify email matches pm_patients record
Portal shows no dataCheck pf_profiles.portal_patient_id is set
Proxy sees wrong patientVerify pm_portal_users.proxy_for_patient_id and expiration
Account lockedUpdate pm_portal_users.status to active
MFA lostPatient must contact admin; unenroll factor via Supabase Auth dashboard
Session audit missingCheck pm_portal_sessions — rows are append-only

Database Tables

TablePurposeRLS
pm_portal_usersPortal user metadata, proxy configFORCE RLS
pm_portal_sessionsAppend-only session auditFORCE RLS (no UPDATE/DELETE)
pf_profiles.portal_patient_idLinks auth user to patient recordExisting PF RLS

Permissions

PermissionDescriptionDefault Roles
pm.portal.viewView portal configuration and proxy listorg_admin
pm.portal.manageManage proxy authorization and settingsorg_admin