medOS ultra

Sidecar Services

Auxiliary sidecar services that augment the core microservice mesh.

11 min read diagramsUpdated 2026-03-26docs/architecture/architecture/03-sidecar-services.md

23 auxiliary services across compute, storage, messaging, AI, and infrastructure layers


Overview

MedOS employs a rich sidecar architecture — auxiliary services that run alongside the core 18 Moleculer microservices. These sidecars handle data ingestion, AI orchestration, infrastructure, storage, and external integrations.

No service mesh (Istio/Envoy/Linkerd) is deployed. Routing is handled by Nginx reverse proxy + NATS message bus.


Architecture Diagram

┌──────────────────────────────────────────────────────────────────────────────┐
│                          EXTERNAL TRAFFIC                                    │
│                                                                              │
│  Browsers / Mobile / API Consumers / Metriport / EHR Systems                │
└───────────────────────────────────┬──────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                    LAYER 1: INGRESS & ROUTING                                │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐  │
│  │  NGINX REVERSE PROXY                                                   │  │
│  │  docker/reverse-proxy/ — Alpine Nginx 1.22                            │  │
│  │  Workers: 4 | Body: 100MB | Timeout: 600s | SSL: LetsEncrypt          │  │
│  │                                                                        │  │
│  │  Routing:                                                              │  │
│  │  /              → Next.js (3000)                                       │  │
│  │  /api/, /api/v2/→ API Gateway (3001)                                  │  │
│  │  /filestore/    → Filestore (8083)                                    │  │
│  │  /e-form        → eForm (8085) [WebSocket]                            │  │
│  │  /socket.io     → WebSocket (3003) [WebSocket]                        │  │
│  │  /reporting/    → Jasper (8088)                                       │  │
│  │  /openapi/      → Public API (8082)                                   │  │
│  │                                                                        │  │
│  │  3 server blocks: sandbox, UAT, test                                  │  │
│  └────────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│  ┌──────────────────────┐                                                   │
│  │  CERTBOT SIDECAR     │  certbot/certbot:latest                          │
│  │  Auto-renew SSL certs│  ACME challenge via Nginx .well-known/           │
│  └──────────────────────┘                                                   │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                  LAYER 2: MESSAGING & SERVICE BUS                            │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐  │
│  │  NATS MESSAGE BROKER                                                   │  │
│  │  docker/nats/ — NATS 2-alpine                                         │  │
│  │                                                                        │  │
│  │  Ports: 4222 (client) | 8222 (monitor) | 6222 (server) | 5222 (route)│  │
│  │  Max Payload: 64MB | Write Deadline: 40s                              │  │
│  │                                                                        │  │
│  │  All 18 Moleculer microservices connect via TRANSPORTER=nats://nats:4222│
│  └────────────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│               LAYER 3: CORE MICROSERVICES (18 services)                      │
│                                                                              │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐           │
│  │  api-gateway │ │  api-aaa    │ │  api-admin   │ │  api-clinical│          │
│  │  :3001,:3210 │ │  Auth/AuthZ │ │  :4002       │ │  Clinical    │          │
│  ├─────────────┤ ├─────────────┤ ├─────────────┤ ├─────────────┤           │
│  │  api-diag    │ │  api-meds   │ │  api-finance │ │  api-found   │          │
│  │  Lab/Imaging │ │  Pharmacy   │ │  Billing     │ │  Foundation  │          │
│  ├─────────────┤ ├─────────────┤ ├─────────────┤ ├─────────────┤           │
│  │  api-filestore│ │  api-eform  │ │  api-interop │ │  api-migrate │          │
│  │  :8083       │ │  E-Forms    │ │  FHIR/HL7   │ │  Migration   │          │
│  ├─────────────┤ ├─────────────┤ ├─────────────┤ ├─────────────┤           │
│  │  api-messaging│ │  api-printing│ │  api-prm    │ │  api-task   │          │
│  │  :8084,:3003 │ │  :8088 (Java)│ │  PRM        │ │  Scheduling  │          │
│  ├─────────────┤ ├─────────────┤ │             │ │              │          │
│  │  public-api  │ │  global-seq  │ │             │ │              │          │
│  │  :8082       │ │  ID Gen      │ │             │ │              │          │
│  └─────────────┘ └─────────────┘ └─────────────┘ └──────────────┘          │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                   LAYER 4: DATA PERSISTENCE                                  │
│                                                                              │
│  ┌──────────────────────┐  ┌──────────────────────┐  ┌─────────────────┐    │
│  │  MongoDB (Primary)   │  │  PostgreSQL (eForm)  │  │  Supabase       │    │
│  │  ──────────────────  │  │  ──────────────────  │  │  (Read Models)  │    │
│  │  mongo:5 replica set │  │  postgres:14.5       │  │  Cloud Postgres │    │
│  │  Port: 27017         │  │  Port: 5432          │  │  + Realtime     │    │
│  │  Pool: 100-500 conn  │  │  DB: eform           │  │                 │    │
│  │  ulimits: 64000 fd   │  │                      │  │                 │    │
│  └──────────────────────┘  └──────────────────────┘  └─────────────────┘    │
│                                                                              │
│  ┌──────────────────────┐  ┌──────────────────────┐                         │
│  │  MongoDB Setup       │  │  PgAdmin             │                         │
│  │  (Init Helper)       │  │  dpage/pgadmin4:6.10 │                         │
│  │  Runs mongo_setup.sh │  │  Port: 5050          │                         │
│  │  then exits          │  │  DB admin console    │                         │
│  └──────────────────────┘  └──────────────────────┘                         │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                  LAYER 5: FILE STORAGE                                        │
│                                                                              │
│  ┌──────────────────────────────────────────┐  ┌──────────────────────────┐  │
│  │  IPFS Node                               │  │  IPFS Cluster Manager   │  │
│  │  ipfs/go-ipfs:master                     │  │  ipfs/ipfs-cluster      │  │
│  │  Port: 4001 (swarm)                      │  │  Port: 9094 (REST API)  │  │
│  │  Port: 5001 (API)                        │  │  Port: 9096 (Proxy)     │  │
│  │  Port: 8080 (gateway)                    │  │  CRDT consensus         │  │
│  └──────────────────────────────────────────┘  └──────────────────────────┘  │
│                                                                              │
│  ┌──────────────────────────────────────────┐                               │
│  │  FTP Server (Legacy)                     │                               │
│  │  stilliard/pure-ftpd                     │                               │
│  │  Port: 21 (control)                      │                               │
│  │  Ports: 30000-30009 (passive)            │                               │
│  │  User: ever / ftpPassEver                │                               │
│  └──────────────────────────────────────────┘                               │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                 LAYER 6: TERMINOLOGY & REFERENCE DATA                        │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐    │
│  │  SNOMED CT Terminology Server (Snowstorm)                            │    │
│  │  docker/snowstorm/docker-compose.snowstorm.yml                       │    │
│  │                                                                      │    │
│  │  ┌──────────────────────┐     ┌───────────────────────────────────┐ │    │
│  │  │  Elasticsearch 7.17  │────▶│  Snowstorm 10.2.0                 │ │    │
│  │  │  snowstorm-es        │     │  SNOMED CT Browser + FHIR API     │ │    │
│  │  │  Single-node cluster │     │  Port: 8085                       │ │    │
│  │  │  2GB JVM heap        │     │  1-2GB JVM heap                   │ │    │
│  │  └──────────────────────┘     └───────────────────────────────────┘ │    │
│  └──────────────────────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│              LAYER 7: AI & AUTOMATION SIDECARS                               │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐    │
│  │  HEALTH-DATA-PLATFORM SIDECAR                                        │    │
│  │  his-vajira/packages/health-data-platform/src/sidecar/               │    │
│  │                                                                      │    │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌───────────────┐ │    │
│  │  │  Webhook    │  │  FHIR API  │  │  CSV        │  │  Transformer  │ │    │
│  │  │  Collector  │  │  Collector  │  │  Collector  │  │  + Forwarder  │ │    │
│  │  │  (push)     │  │  (pull/60s) │  │  (batch)    │  │  → Data Lake  │ │    │
│  │  └────────────┘  └────────────┘  └────────────┘  │  → Search Idx  │ │    │
│  │                                                   │  → Event Bus   │ │    │
│  │                                                   └───────────────┘ │    │
│  └──────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐    │
│  │  PRM (Patient Relationship Management) SIDECARS                      │    │
│  │  his-vajira/medbase/functions/prm-sidecars/                          │    │
│  │                                                                      │    │
│  │  ┌─────────────────────┐  ┌──────────────────────────────────────┐  │    │
│  │  │  Dify AI Personas   │  │  n8n Workflow: care-gap-reactivation │  │    │
│  │  │  ─────────────────  │  │  ────────────────────────────────── │  │    │
│  │  │  Protocol Scout     │  │  1. Webhook: prm.opportunity.created │  │    │
│  │  │  (Clinical Analyst) │  │  2. Consent checker                 │  │    │
│  │  │  Brand Concierge    │  │  3. HubSpot contact upsert          │  │    │
│  │  │  (VIP Liaison)      │  │  4. HubSpot deal creation           │  │    │
│  │  │  Thai/EN WhatsApp   │  │  5. Dify AI outreach generation     │  │    │
│  │  └─────────────────────┘  └──────────────────────────────────────┘  │    │
│  │                                                                      │    │
│  │  ┌──────────────────────────────────────────────────────────────┐    │    │
│  │  │  OpenClaw Insurance Verification Sidecar                     │    │    │
│  │  │  openclaw/skills/insurance-liaison/verify_coverage.py        │    │    │
│  │  │  Providers: AIA, Bupa, Allianz, etc.                        │    │    │
│  │  │  Input: patient_id + package_code + provider_name            │    │    │
│  │  │  Output: coverage status + out-of-pocket calculation         │    │    │
│  │  └──────────────────────────────────────────────────────────────┘    │    │
│  └──────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐    │
│  │  REPORTING SIDECAR (Jasper)                                          │    │
│  │  ever-api-printing (Spring Boot, Java)                               │    │
│  │  Port: 8088                                                          │    │
│  │  PDF generation, Jasper Reports, IPFS storage                        │    │
│  └──────────────────────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                LAYER 8: FRONTEND SIDECARS                                    │
│                                                                              │
│  ┌──────────────────────┐  ┌──────────────────────────────────────────────┐ │
│  │  Next.js Web App     │  │  eForm Builder (Toolpad)                     │ │
│  │  Port: 3000          │  │  Port: 8085                                  │ │
│  │  SSR + React frontend│  │  Postgres-backed form builder                │ │
│  └──────────────────────┘  └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘

Sidecar Inventory (23 services)

Infrastructure Sidecars

# Service Image/Tech Port(s) Purpose
1 Nginx Reverse Proxy nginx:1.22-alpine 80, 443 API gateway, SSL termination, routing
2 Certbot certbot/certbot LetsEncrypt certificate automation
3 NATS nats:2-alpine 4222, 8222, 6222, 5222 Inter-service message bus

Data Persistence Sidecars

# Service Image/Tech Port(s) Purpose
4 MongoDB mongo:5 27017 Primary OLTP database (replica set)
5 MongoDB Setup mongo:5 Replica set initialization (run-once)
6 PostgreSQL postgres:14.5 5432 eForm relational database
7 PgAdmin dpage/pgadmin4:6.10 5050 Database admin console

File Storage Sidecars

# Service Image/Tech Port(s) Purpose
8 IPFS Node ipfs/go-ipfs 4001, 5001, 8080 Distributed file storage
9 IPFS Cluster ipfs/ipfs-cluster 9094, 9096 Cluster coordination (CRDT)
10 FTP Server stilliard/pure-ftpd 21, 30000-30009 Legacy file transfer

Terminology Sidecars

# Service Image/Tech Port(s) Purpose
11 Elasticsearch elasticsearch:7.17.18 9200 Snowstorm storage backend
12 Snowstorm snowstorm:10.2.0 8085 SNOMED CT browser + FHIR API

AI & Automation Sidecars

# Service Image/Tech Port(s) Purpose
13 Health-Data Sidecar TypeScript (in-process) FHIR data collect → transform → forward
14 Dify Protocol Scout Dify YAML persona Clinical telemetry analysis
15 Dify Brand Concierge Dify YAML persona VIP patient outreach (Thai/EN)
16 n8n Care Gap Workflow n8n JSON workflow PRM opportunity → HubSpot → Dify
17 OpenClaw Insurance Python skill Insurance coverage verification

Application Sidecars

# Service Image/Tech Port(s) Purpose
18 Jasper Reporting Spring Boot (Java) 8088 PDF generation + Jasper Reports
19 Next.js Frontend Node.js 3000 SSR web application
20 eForm Builder Toolpad (React) 8085 Electronic form builder

Migration Box Sidecars (portable deployment)

# Service Image/Tech Port(s) Purpose
21 migration-api Moleculer + Claude Portable migration engine
22 medbase-db PostgreSQL Migration metadata store
23 Migration Gateway API Gateway Minimal Box UI gateway

Inter-Sidecar Communication

┌─────────────┐   TCP 4222    ┌──────────────┐
│ Microservice │──────────────▶│     NATS     │◀──── All 18 services
│   (any)      │              └──────────────┘
└──────┬───────┘
       │ TCP 27017
       ▼
┌──────────────┐              ┌──────────────┐
│   MongoDB    │              │  PostgreSQL  │◀──── eForm, PgAdmin
│ (replica set)│              └──────────────┘
└──────────────┘
       │
       │ HTTP 5001             ┌──────────────┐
       │                       │  IPFS Node   │◀──── Filestore service
       │                       └──────┬───────┘
       │                              │ HTTP 5001
       │                       ┌──────▼───────┐
       │                       │ IPFS Cluster │
       │                       └──────────────┘
       │
       │                       ┌──────────────┐
       │                       │ Elasticsearch│
       │                       └──────┬───────┘
       │                              │ HTTP 9200
       │                       ┌──────▼───────┐
       │                       │  Snowstorm   │ SNOMED CT + FHIR
       │                       └──────────────┘
       │
       │ HTTP :5001            ┌──────────────┐
       └──────────────────────▶│  Dify API    │◀──── n8n workflow
                               └──────────────┘

       OAuth2                  ┌──────────────┐
       ──────────────────────▶│   HubSpot    │◀──── n8n workflow
                               └──────────────┘

Docker Compose Files

File Purpose Services
docker-compose.yml Primary development All core services + sidecars
docker-compose.migration-box.yml Portable migration migration-api, medbase-db, mongo, nats, gateway
docker/snowstorm/docker-compose.snowstorm.yml Terminology server Elasticsearch + Snowstorm
Multiple docker-compose.*.yml Environment variants sandbox, test, UAT configurations

Resource Requirements

Service CPU Memory Storage Notes
MongoDB Persistent volume 64,000 file descriptors
Elasticsearch 2GB JVM heap Persistent volume Memory lock enabled
Snowstorm 1-2GB JVM heap 120s startup period
NATS 64MB max payload
Nginx 4 workers 100MB body, 600s timeout
IPFS Persistent volume Swarm networking

Key Design Decisions

  1. NATS over Kafka/RabbitMQ — Lightweight, low-latency pub/sub for Moleculer microservices. 64MB payload supports large clinical documents.
  2. IPFS for file storage — Content-addressed, distributed storage with cluster replication. Supports large medical images and documents.
  3. Nginx over API Gateway service — Simple, battle-tested reverse proxy with SSL termination. No need for API gateway features like rate limiting (handled at app level).
  4. Snowstorm self-hosted — SNOMED CT terminology server avoids external API dependency. Critical for clinical coding workflows.
  5. PRM sidecars as plugins — Dify personas + n8n workflows + OpenClaw skills are loosely coupled to the core HIS. Easy to swap or disable.
  6. FTP for legacy — Pure-FTPd supports legacy system integrations that can’t use modern APIs.
  7. No service mesh — Complexity avoided in favor of NATS + Nginx. May revisit with Istio when multi-cluster deployment is needed.
Ask Anything