Skip to main content

Patient Portal Service — Migration Plan

Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 03 platform-services

1. Migration Context

The patient-portal-service is a net-new service on the Ghasi-eHealth platform. There is no pre-existing portal service to migrate from. The migration plan covers:

  1. New tenant onboarding — provisioning portal access for existing patient populations.
  2. Legacy patient portal data import — for tenants transitioning from an external portal product.
  3. Keycloak patient realm bootstrapping.

2. New Tenant Provisioning

When a tenant activates (tenant.tenant.activated.v1 event received):

  1. Portal service creates default portal configuration for the tenant (feature flags, result release policy defaults, MFA enforcement policy).
  2. Existing patients are eligible for portal registration immediately — no bulk account creation; patients self-register.
  3. Module entitlement ehr.portal must be granted by platform operator before portal endpoints are accessible for the tenant.

3. Legacy Portal Data Import

For tenants migrating from an existing patient portal:

PhaseActionNotes
Phase 1 — AssessmentExport patient account list from legacy portal; map to Ghasi patient IDs via registration-serviceRequires patientId matching via MRN or national ID
Phase 2 — Account creationBulk-create PortalAccount records for matched patients (status: pending_verification)Admin API: POST /internal/portal/accounts/bulk
Phase 3 — Keycloak user migrationCreate Keycloak user records in patient realm; send password-reset linksKeycloak admin API + bulk email via communication-service
Phase 4 — Proxy delegation importImport existing proxy/caregiver relationships; create ProxyDelegation records via admin APIManual review required for legal consent compliance
Phase 5 — Access log migrationHistorical access logs from legacy portal are not migrated (new audit trail starts on platform go-live)Document as known gap in compliance review

4. Data Migration Tooling

Migration scripts located at: scripts/migration/patient-portal/

ScriptPurpose
import-portal-accounts.tsBulk create PortalAccount records from CSV
import-proxy-delegations.tsImport proxy relationships from CSV with validation
validate-patient-mapping.tsVerify patientId matches between legacy portal and registration-service

All scripts are idempotent (upsert on tenant_id + patient_id). Failed rows are logged to migration_errors.json and do not abort the batch.


5. Keycloak Patient Realm Bootstrap

Each tenant's patient realm is initialized with:

  1. portal client (PKCE, SMART on FHIR scopes).
  2. MFA TOTP policy (required, not optional).
  3. Password policy: min 12 chars, complexity required.
  4. Session settings: access token 15 min, refresh 24h, refresh-token rotation enabled.

Bootstrap script: scripts/migration/patient-portal/bootstrap-patient-realm.ts


6. Rollback Plan

ScenarioRollback action
Bulk account import failureDelete all accounts in pending_verification status for tenant; re-run import
Keycloak realm misconfigurationRestore realm from backup snapshot; re-run bootstrap
Feature flag misconfigurationDisable ehr.portal entitlement for tenant; re-configure

Portal database migrations (Drizzle) are down-migration capable for all changes during the migration window.