medOS ultra

Architecture & Deployment Plan

Cross-region deployment learnings: AWS Japan, Philippines EC2 demo, Thai on-prem air-gapped.

11 min read diagramsUpdated 2026-04-15docs/ARCHITECTURE_DEPLOYMENT_PLAN.md

Learnings from deploying to AWS Japan, Philippines (EC2 demo), and planning for Thai on-premise air-gapped hospitals and countryside clinics.


Table of Contents

  1. System Overview
  2. Edition System (LITE vs FULL)
  3. Deployment Topologies
  4. What We Built Today
  5. What We Learned
  6. Hardware Guide by Deployment Type
  7. Recommended Next Steps

1. System Overview

medOS-ultra monorepo
├── 16 NestJS microservices (Moleculer mesh over NATS)
├── React 19 + Vite frontend (21 packages, 92+ miniapps)
├── MongoDB (write truth) + Supabase/PostgreSQL (read models)
├── Module system (registry + dynamic loading + plugin manager + marketplace)
├── 2 app modes: CLINIC (multi-tenant) / HOSPITAL (single-tenant)
├── 17 locale translations (ja, fil, th, en, etc.)
└── Market packs (region-specific seed data, insurance rates)

Key Existing Infrastructure

System File Status
App Mode (CLINIC/HOSPITAL) web/src/config/app-mode.config.ts Working — gates features by mode
Feature Flags web/src/utils/featureFlags.ts Working — VITE_FEATURE_* env vars
Module Registry web/src/lib/modules/moduleRegistry.ts Working — isActive() per module
Dynamic Module Loading web/src/lib/module-federation/ Working — manifest-based lazy loading
Plugin Manager web/src/lib/modules/plugin-manager.ts Working — runtime .zip install
App Store / Marketplace web/src/lib/appstoreSupabaseClient.ts Working — separate Supabase instance
Edition Flag main-flow-editor/config/index.ts Partial — only for workflow editor (SELF_HOSTED/CLOUD)

2. Edition System

Proposed Editions

Edition Target Modules Backend Services
LITE Small clinics, countryside, mobile units OPD + basic IPD 5-6 core services
FULL Hospitals, nursing homes Everything All 13+ services

LITE Edition Scope

Included:

  • Patient registration + queue management
  • Screening + consultation
  • Prescription + pharmacy dispensing
  • Basic billing + receipts
  • Appointment scheduling
  • Medical records + diagnosis
  • Lab orders + imaging orders
  • Basic IPD (admission, discharge, ward board)
  • Nursing log + vital signs + progress notes

Excluded (FULL only):

  • Surgery / operating room / anesthesia
  • Blood bank
  • Forensics
  • Emergency department (advanced)
  • ICU / CCU monitoring
  • Nursing home (kaigo) workflows
  • Clinical decision support (CDS)
  • Workflow editor (visual flow builder)
  • Advanced analytics / dashboards
  • Multi-location management
  • FHIR / HL7 interoperability engine
  • Advanced RCM (claim submission, denial management)

How to Implement

Use the existing isFeatureEnabled() system + module registry isActive(). No code deletion — modules just don’t activate.

VITE_EDITION=LITE   →  Only LITE modules register at startup
VITE_EDITION=FULL   →  All modules register (default)

New file: web/src/config/edition.config.ts — maps edition → module list Modify: web/src/config/app-mode.config.ts — add getEdition(), wire into feature gates


3. Deployment Topologies

Topology A: Cloud-Connected Client (Browser Only)

Clinic (countryside)              Central Server
┌──────────────────┐             ┌──────────────────┐
│  Any device with │── internet ─│  EC2 / VXRail    │
│  a browser       │             │  Full backend    │
│  No install      │             │  Shared tenancy  │
└──────────────────┘             └──────────────────┘
Aspect Detail
Client Browser (laptop, tablet, phone)
Server Centralized (cloud or hospital data center)
Edition LITE or FULL (controlled by build/env var)
Internet Required (always)
Cost/clinic $0 — just needs a browser
Offline No
Multi-tenant Yes — use VITE_APP_MODE=CLINIC with tenant isolation
Best for Connected clinics, mobile health teams, pilot programs

Deployment: Vercel frontend build with VITE_EDITION=LITE, pointing to central backend. Each clinic gets a tenant ID.

Topology B: Local Server (Offline-Capable)

Clinic (air-gapped or unreliable internet)
┌─────────────────────────────────────┐
│  Mini PC (Intel NUC / Beelink)      │
│  Docker Compose (LITE services)     │
│  MongoDB + 5 services + frontend    │
│  Serves clinic LAN via nginx        │
│  Works fully offline                │
└─────────────────────────────────────┘
         ↕ (optional sync when online)
┌──────────────────┐
│  Central Server   │
│  (for backup/     │
│   reporting)      │
└──────────────────┘
Aspect Detail
Hardware Mini PC: 4-8 cores, 8-16GB RAM, 128GB SSD (~$200-500)
Services 5-6 only: gateway, auth, foundation, clinical, financial, (+messaging)
Database Local MongoDB (single node, no replica set needed for LITE)
Edition LITE
Internet Not required — fully offline
Cost ~$200-500 one-time hardware
Sync Future: background sync to central server when internet available
Best for Rural clinics, island clinics, mobile hospitals, disaster response

Deployment: Air-gapped package (package-airgap.sh) with LITE compose file. USB transfer.

Minimum hardware:

Component Spec Cost
Beelink SER5 (Ryzen 5, 16GB, 500GB) 6C/12T, 16GB DDR4, 500GB NVMe ~$300
Or Intel NUC 12 Pro 4C/8T, 16GB DDR4, 256GB NVMe ~$400
Or Raspberry Pi 5 (8GB) + SSD 4C, 8GB, 256GB USB SSD ~$150 (tight)
UPS (small) APC BE425M ~$50

Topology C: Hospital On-Premise (Full Stack)

Hospital Server Room
┌─────────────────────────────────────────┐
│  Dell VXRail / PowerEdge / Server       │
│  Docker Compose (FULL) or native Node   │
│  All 13 services + MongoDB + PostgreSQL │
│  VITE_EDITION=FULL                      │
│  VITE_APP_MODE=HOSPITAL                 │
│  Serves hospital LAN                    │
│  Air-gapped capable                     │
└─────────────────────────────────────────┘
Aspect Detail
Hardware 16+ cores, 32-64GB RAM, 500GB+ SSD
Services All 13 microservices + full infrastructure
Edition FULL
Internet Not required (air-gapped OK)
Cost $9,000-70,000 depending on hardware
Best for Hospitals, nursing homes, medical centers

Already built and tested — see docs/DEPLOY_ONPREMISE_AIRGAPPED.md.

Topology D: Cloud (AWS)

AWS Region (ap-northeast-1 / ap-southeast-1)
┌──────────────────────────────────────────────┐
│  ECS Fargate → 13 services                   │
│  DocumentDB → MongoDB                        │
│  RDS → PostgreSQL                            │
│  S3 + CloudFront → Frontend                  │
│  ALB → Path-based routing                    │
│  Supabase → Read models + realtime           │
└──────────────────────────────────────────────┘
Aspect Detail
Cost ~$460-650/month (production) or ~$95/month (demo EC2)
Edition FULL
Best for Multi-hospital chains, SaaS offering, demo/staging

Already built — Terraform modules at infrastructure/terraform/modules/medos-stack/.


4. What We Built Today

Infrastructure Created

Category Files Purpose
Terraform shared module 10 .tf files VPC, ECS, ALB, S3/CF, RDS, DocumentDB, ECR
Japan region config 3 files ap-northeast-1 Terraform
Philippines region config 3 files ap-southeast-1 Terraform
Philippines demo (EC2) 2 files Single EC2 t3.xlarge → r6i.xlarge
Docker Compose (Japan) 1 file All 15 services, TZ=Asia/Tokyo
Docker Compose (Philippines) 1 file All 15 services, TZ=Asia/Manila
Docker Compose (on-premise) 1 file All-in-one with health checks
Market pack: Japan 6 files Hospital + nursing home + kaigo rates (JA/EN)
Market pack: Philippines 6 files Hospital + PhilHealth rates (FIL/EN)
Market pack: English 3 files International hospital (EN)
Market pack: Thailand 1 file Manifest (seeds in web/scripts/)
Deploy script 1 file Multi-region CLI
Air-gap packager 1 file Build → tar.gz for USB transfer
On-premise setup 3 files SSL gen, mongo init, setup wizard
Nginx on-premise 1 file Docker DNS-based proxy config
Env files 8 files .env.japan/philippines/onpremise/lite per layer
Documentation 4 files CLAUDE.md, AGENTS.md, DEPLOY_PIPELINE.md, DEPLOY_AIRGAPPED.md

Live Deployment

Resource Detail
EC2 Instance i-0e4d61b97464b5477 (r6i.xlarge, 32GB)
Public IP 3.0.73.73
Region ap-southeast-1 (Singapore)
SSH Key ever-oma-mongo
Services Running 13 NestJS microservices + MongoDB + NATS + PostgreSQL + IPFS
Memory 4.6GB / 30GB used
Cost ~$95/month

5. What We Learned

Build Issues Encountered & Fixed

Issue Root Cause Fix
moleculer-db-adapter-mongoose@^0.9.12 not found Version gap in npm (0.9.4 → 0.10.1) Changed to ^0.10.1 in services/interoperability/package.json
platform-api-schema build fails Missing coverage/ module (was deleted or never created) Created stub at packages/platform-api-schema/src/administration/coverage/
Docker build 41GB cache Compose builds 14 identical images with separate caches Build API image ONCE, reuse for all services (same image, different SCOPE env var)
yarn install timeout in Docker Docker bridge DNS issues Use --network=host for Docker build
turbo: not found Not installed globally on EC2 sudo npm install -g turbo@2.5.4
bunx: not found Bun not installed on EC2 `curl -fsSL https://bun.sh/install
EC2 OOM (16GB) 13 Node.js services + 4 Docker containers Upgraded to r6i.xlarge (32GB)
SSH timeout Too many inline commands Write startup script to file, scp + execute
vCPU limit exceeded AWS default limit is 8 vCPU for standard instances Used r6i family (different quota bucket)
eform Dockerfile broken References apps/eform/ path that doesn’t exist in medOS-ultra Skip eform Docker build, run natively
nginx config paths Compose resolves ../docker/nats relative to compose file Use stock nats:2-alpine image instead of custom build

Key Architecture Insights

  1. Single API image, multiple services — All 13 NestJS services use the SAME Docker image. The SCOPE env var at runtime determines which service starts. Don’t build 13 separate images.

  2. Moleculer-runner is the entry point — Services start via moleculer-runner --config ./dist/moleculer.config.js, NOT via node dist/moleculer.config.js.

  3. Build order matters — Must build platform-* packages first (shared schemas), then services.

  4. CLINIC vs HOSPITAL is runtime, not build-time — The same binary supports both modes. Switched via env var.

  5. Supabase is for read models — The SQL seeds (wards, hospitals, pathology) go to Supabase, NOT to eform PostgreSQL. Insurance rates (kaigo, PhilHealth) go to eform PostgreSQL.

  6. Thai seeds are the default — They live in web/scripts/ and web/supabase/migrations/. Other regions have dedicated market packs in infrastructure/market-packs/.

  7. All seeds are additive — Region-prefixed IDs (jp-ward-*, ph-ward-*, en-ward-*) mean you can load ALL regions into one database.


6. Hardware Guide

For LITE Edition (Small Clinic)

Option Spec Cost Good For
Beelink SER5 Ryzen 5 5560U, 16GB, 500GB NVMe ~$300 Best value for clinic server
Intel NUC 12 i5-1240P, 16GB, 256GB NVMe ~$400 Reliable, well-supported
Raspberry Pi 5 ARM, 8GB, 256GB USB SSD ~$150 Cheapest, tight on RAM
Any old laptop i5+, 8GB+, 128GB+ SSD $0 Repurposed hardware

For FULL Edition (Hospital)

Option Spec Cost Good For
Dell PowerEdge R760 2x Xeon, 128GB, 4x SSD $8-12K Standalone server
Dell VxRail E660 2x Xeon Silver, 128GB $25-35K VMware hyperconverged
Dell VxRail V670 2x Xeon Gold, 256GB $45-65K 200+ bed hospital
AWS EC2 r6i.xlarge 4 vCPU, 32GB $95/month Cloud demo/staging

For Cloud

Size Instance Cost Users
Demo r6i.xlarge $95/mo 2-3 devs
Small Full Terraform stack (t3.medium DBs) $300/mo <100 users
Production Full Terraform stack (m5.large DBs) $650/mo 100-500 users

Immediate (this week)

  1. Create edition.config.ts — Define LITE/FULL module lists
  2. Create docker-compose-lite.yml — 5-service compose for clinic deployment
  3. Connect Supabase to the Philippines EC2 — load the ward/hospital/pathology seeds
  4. Start the Vite frontend on the EC2 — pnpm install && pnpm dev
  5. Test LITE mode — build with VITE_EDITION=LITE, verify excluded modules don’t appear

Short-term (this month)

  1. Fix the Docker build pipeline — Single API image build, proper multi-stage caching
  2. Create GitHub Actions deploy workflow — Auto-deploy to EC2 on push to main
  3. Create Vercel preview for Philippines — Separate env vars pointing to 3.0.73.73
  4. Test air-gapped deployment end-to-end — Build package on Mac, transfer to clean Ubuntu VM, verify

Medium-term (next quarter)

  1. Offline sync for LITE clinics — Background data sync to central server when internet available
  2. Central dashboard — Admin view showing all connected clinics, their status, last sync time
  3. Auto-update system — LITE clinics pull update packages from central server
  4. Billing integration — Connect kaigo rates and PhilHealth rates to the financial module
  5. CI/CD for air-gapped — Build pipeline that produces versioned .tar.gz release artifacts

Decision Matrix: Which Topology?

Does the clinic have reliable internet?
├── YES → Topology A: Cloud Client (browser only, $0/clinic)
│         Use CLINIC mode + LITE edition on Vercel
│
└── NO → Does the clinic need to work offline?
         ├── YES → Topology B: Local Server ($200-500 mini PC)
         │         Use docker-compose-lite.yml + LITE edition
         │
         └── SOMETIMES → Both
                         Local server for daily ops (offline)
                         + Cloud sync when connected (future)
Is this a hospital (>50 beds)?
├── YES → Topology C: On-Premise Full ($9K-70K server)
│         Or Topology D: AWS Cloud ($300-650/month)
│         Use HOSPITAL mode + FULL edition
│
└── NO → Use LITE edition (either Topology A or B)
Ask Anything