Skip to main content

Billing Service — Migration Plan

Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template

1. Scope

Migrate legacy "EHR billing module" and any customer-site spreadsheets/ERP exports into the canonical billing-service. Target tenants:

  • Afghanistan — mostly self-pay; minimal prior digital billing. Fresh installs dominate.
  • UAE — may have prior HIS billing and payer workflows; mixed data shapes.
  • Other pilots — variable; treated case-by-case.

2. Legacy sources

SourceFormatNotes
Legacy EHR apps/services/billing (pre-platform)Postgres tables (charges, invoices, payments, ledger_entries)Partial implementation; migrate as "baseline"
Tenant-provided ERP extractCSV per facilityMap to ChargeItem + Invoice + PaymentReconciliation
Paper / spreadsheet ARExcelConvert to charge + payment import via staging table

3. Phases

Phase 0 — Data assessment (1–2 weeks per tenant)

  • Extract schema; run profiling (row counts, null rates, currency mix).
  • Identify outliers (negative prices, unknown codes, zombie invoices without lines).
  • Agree cut-over date.

Phase 1 — Schema preparation (1 week)

  • Run canonical drizzle migrations.
  • Create staging schema billing_migration for raw imports.
  • Provision tenant row in tenant-service with currency + facility defaults.

Phase 2 — Reference data (1 week)

  • Import payer directory via claims-service.
  • Publish a "migration" price list (effective_from = historical earliest service date) to allow re-pricing of historical charges.
  • Load tax rules for the country/facility combinations.

Phase 3 — Historical load (2 weeks)

  • Load historical charges → billing_migration.charges_staging → normalise → billing.charges (status=posted, ledger_entries written).
  • Load historical payments → billing.payments + allocations → ledger.
  • Load adjustments and refunds.
  • Use the existing append-only invariant: every historical row writes a new ledger entry.
  • Reconcile end-of-migration balance against source balances; publish diff report.

Phase 4 — Consumer wiring (1 week)

  • Subscribe to clinical producer events (registration, scheduling, orders, medication, virtual-care, immunizations).
  • Wire claims-service to consume billing.invoice.issued.v1.
  • Wire patient-portal-service BFF to read accounts / invoices.

Phase 5 — Cut-over (1 day)

  • Freeze legacy writes.
  • Run final delta import.
  • Flip traffic via Kong route (/api/v1/billing → new service).
  • Smoke tests + reconciliation.
  • Un-freeze.

Phase 6 — Stabilisation (4 weeks)

  • Dual-read: queries fall back to legacy read-only for audit if needed.
  • Nightly reconciliation with legacy snapshot until stable.
  • Retire legacy database after 90-day burn-in + compliance sign-off.

4. Data mapping

Legacy fieldNew fieldNotes
charges.amount (decimal)charges.total_amount_minorMultiply by 10^currency-precision; enforce bigint
invoices.status (legacy enum)invoices.statusCREATEDdraft, ISSUEDissued, SETTLEDpaid, CANCELLEDvoided
Legacy audit.userLedger created_by (via outbox audit event)
Legacy coverage_idcarried forward; claims-service owns
Paper ledgersone-shot import into adjustments with reason MIGRATION_OPENING_BALANCE

5. Validation & rollback

CheckRule
Balance reconciliationsum(legacy_balance) == sum(new_ledger) per account
Invoice countequal ± 0.1 % (allow rounding on historical)
Currency integrityno cross-currency accounts
Issued invoices are immutable0 post-migration edits

Rollback: within first 24 h, route traffic back to legacy and quarantine new service. After 24 h, rollback requires DR plan + approval.

6. Cut-over communications

  • 14 days before: tenant admin notification + migration schedule.
  • 24 h before: final data freeze notice.
  • Day of: status page; hotline to ops channel.
  • Post-migration: 7-day hypercare; reconciliation report shared with tenant finance.

7. Risks

RiskMitigation
Historical currency mis-scalingPer-tenant precision table; property-based tests on import
Legacy codes not in canonical terminologyMap to local code system + flag for ops recode
Missing facility IDsDefault to tenant's main facility with ops review
Tenant over-counted historical paymentsMark differences as adjustments with reason MIGRATION_RECONCILIATION