medOS ultra

Modular Multi-Country Deployment

Two-axis model: country-agnostic modules times per-country market packs, module.json contracts, dependency-resolving installer.

6 min read diagramsUpdated 2026-06-03docs/architecture/modular-multicountry-deployment.md

How medOS is sold per module and deployed per (module × country) from one codebase. This is the architecture reference for the module-deploy system (infrastructure/modules/), the market-pack system (infrastructure/market-packs/), and how they compose. Read this before touching module manifests, the installer, market packs, entitlement flags, or per-country deployment.

1. Thesis — two orthogonal axes

medOS deployment is the cross-product of two independent axes:

                 MODULES  (country-agnostic features — the SQL/edge/UI is identical everywhere)
                 ────────────────────────────────────────────────────────────────────────▶
   MARKET PACKS  │  read-model-core   fpa-warehouse   rollout-kpi   scheduling   telemetry  …
   (per-country  │  ──────────────────────────────────────────────────────────────────────
    overlays:    │  🇨🇳 china     locale zh · CNY · commercial+社保 insurers · ICD-10-CN · Fapiao
    locale,      │  🇯🇵 japan     locale ja · JPY · kaigo rates · MEDIS-DC
    seeds,       │  🇵🇭 philippines locale fil · PHP · PhilHealth case rates
    insurers,    │  🇹🇭 thailand  locale th · THB · NHSO 16-file
    terminology) │  🇺🇸 united-states locale en · USD · CPT/CMS-1500
                 ▼  … any future country = drop a market pack
  • One codebase. Application code (16 services + React frontend + ~80 edge functions) is byte-identical across every country. Proven by 6 live packs.
  • A deployment = choose feature modules (what the hospital bought) + one market pack (which country). install-module.sh <modules> --region=<country>.
  • This is why the marginal country/site is cheap: it’s data + config, not code.

2. What is modular at each layer

Layer Modular unit Mechanism
Frontend federated miniapp + VITE_* entitlement flag module-federation (web/public/module-federation/module-manifest.json) + central registry + moduleEnabled()
Backend services Moleculer service 16 services on NATS; run what you need
Read-model SQL module (infrastructure/modules/<id>/module.json) dependency-resolved install-module.sh
Country config market pack (infrastructure/market-packs/medos-<c>/) manifest.json + idempotent seed SQL/TS; --region=<c>
Edge functions named Deno fn supabase functions deploy (reported by the installer)

3. The two deploy contracts

3a. module.json — a country-agnostic feature

{
  "id": "rollout-kpi",
  "catalogCategory": "Reporting",            // maps to docs/pricing-module-catalog.csv
  "requires": ["fpa-warehouse","read-model-core","scheduling","telemetry"],  // dependency edges
  "migrations": ["medbase/migrations/20260602b_gold_rollout_kpi.sql",],     // schema — always
  "seeds":      ["medbase/migrations/095_fpa_seed_data.sql"],                 // demo — only with --with-seed
  "edgeFunctions": ["slot-backfill-dispatcher"],   // supabase functions deploy
  "miniapp": "fpa-dashboard",                       // frontend federation id
  "flags": { "VITE_ROLLOUT_KPI_ENABLED": "true" },  // entitlement contract
  "postInstall": "SELECT fn_refresh_rollout_kpi();" // run after this module's SQL
}

Paths are relative to infrastructure/.

3b. market-pack manifest.json — a country overlay

{
  "name": "medos-japan", "locale": "ja", "timezone": "Asia/Tokyo", "currency": "JPY",
  "country_code": "JP", "terminology": {}, "facility_types": [],
  "seeds":   ["seed-hospital-facility.sql","seed-kaigo-rates.sql",],  // applied by --region=japan
  "scripts": ["seed-blood-donors.ts"],                                  // TS seeds (npx tsx)
  "complianceProfile": { "dataResidency": "…", "retentionDays":, "phiMaskingLevel": "…" }
}

A country needing more than seeds (edge fns, deps) can also be expressed as a full module.jsonmedos-china is the worked example (commercial-insurer connector packs + close-encounter-billing bridge + dependency on read-model-core).

4. The engine

Piece Role
infrastructure/modules/resolve-modules.mjs reads all module.json, computes the dependency closure, topologically sorts (deps first), emits an ordered plan. Detects cycles + unknown modules.
infrastructure/modules/install-module.sh <module-ids> [--region=<c>…] [--dry-run] [--with-seed] [--with-edge] — applies module SQL in order via psql (idempotent), applies any country’s market-pack seeds dynamically from its manifest, reports edge fns + flags.
infrastructure/medbase/apply-fpa-rollout.sh the original hand-built bundle for the FP&A+rollout stack — superseded by the manifest-driven installer, kept as a fixed recipe.
.github/workflows/apply-modules.yml manual one-click CI (workflow_dispatch) that runs the installer against a SUPABASE_DB_URL secret. NOT on-push (auto-applying migrations to a live DB is unsafe).
install-module.sh rollout-kpi --region=japan --with-seed
#   → resolve: read-model-core, scheduling, telemetry, fpa-warehouse, rollout-kpi  (deps first)
#   → apply each module's migrations (idempotent) + 095 demo seed
#   → apply medos-japan manifest seeds (facility, kaigo rates, pathology-ja, …)
#   → report: deploy slot-backfill-dispatcher; set VITE_ROLLOUT_KPI_ENABLED, locale ja

5. Entitlement — catalog → flags → deploy

hospital buys modules → entitlement (VITE_ENABLED_MODULES) → install-module.sh <ids> --region=<c>
   (pricing-module-catalog.csv,        (per-site allowlist;          (resolve deps → apply SQL →
    201 features / 20 categories)        unset = all-on, demo-safe)    report edge fns + flags)

moduleEnabled(id) (fpa-dashboard/entitlements.ts) reads VITE_ENABLED_MODULES (comma list):

  • unset → all modules on (dev/demo — nothing breaks)
  • set → only listed modules render (production purchase gate)

6. Multi-country

  • Any country works via --region=<country>, read dynamically from the pack manifest — no hardcoded country list, so future countries need zero code change.
  • Existing packs: china, japan, philippines, thailand, united-states, english.
  • Add a country: drop market-packs/medos-<c>/manifest.json (+ bilingual idempotent seeds); --region=<c> discovers it. Graduate to a module.json if it needs edge fns/deps.
  • Topologies (docs/ARCHITECTURE_DEPLOYMENT_PLAN.md): cloud / on-prem / air-gapped; LITE vs FULL.
  • Data residency: each site keeps its own read model in-region; only de-identified aggregates federate to a group tier (docs/architecture/cross-region-policy-gates-deployment.md, china-pipl-dsl-compliance.md).

7. Invariants (the rules that make it safe)

  1. Idempotent — every migration/seed uses IF NOT EXISTS / ON CONFLICT / to_regclass guards, so applying any module-set repeatedly never damages anything. (This is the property that makes a package-manager-style installer safe.)
  2. Dependency-closed — a module deploys with its full requires closure, topologically ordered. Skipping a dependency is the 42P01: relation … does not exist error (e.g. the rollout-KPI views read fpa_fact_encounter, department_queues, booking_slots, ui_interaction_events).
  3. Order-independent where possible — view-creating migrations (e.g. 20260602b) self-guard on to_regclass, so a partial apply degrades gracefully instead of hard-failing.
  4. Entitlement defaults open in dev, closed in prodVITE_ENABLED_MODULES unset = all-on.
  5. Country = data, not code — application code never branches on country; differences are market-pack rows.
  6. No PHI crosses a region boundary — group roll-ups are de-identified aggregates only.

8. How to extend

  • Add a module: create infrastructure/modules/<id>/module.json (declare migrations/seeds/ edge fns/flag/requires); the installer + CI pick it up. Wire moduleEnabled('<id>') at the UI surface to gate by purchase.
  • Add a country: create infrastructure/market-packs/medos-<c>/manifest.json + idempotent bilingual seeds; --region=<c> works immediately.

9. Honest status (what’s real vs. intent)

  • ✅ Real: dependency resolution, ordered idempotent SQL apply, dynamic multi-country --region, edge-fn/flag reporting, one-click CI, entitlement gating of the Rollout-KPI surface.
  • 🟡 Intent: not every module yet gates its UI on its flag (extend moduleEnabled() per surface); flags must be synced into each Vercel project.
  • ⚠️ Pragmatic layer: native supabase db push is blocked by a drifted migration-history table — this installer is the workaround until that’s repaired. Auto-on-push CI is intentionally avoided.
  • ⚠️ Per-region prod targets need per-region SUPABASE_DB_URL secrets/environments.
  • Catalog: docs/pricing-module-catalog.csv · Editions/topologies: docs/ARCHITECTURE_DEPLOYMENT_PLAN.md
  • Market-pack mechanism: root CLAUDE.md (Multi-Region Deployment) · Seeds: docs/ai-seed-guide.md
  • China overlay: docs/architecture/china-pipl-dsl-compliance.md · Build log: docs/uat/medos-china-build-log.md
  • Module system: infrastructure/modules/README.md
Ask Anything