medOS ultra

Platform Services Architecture

Architecture & implementation guide to the platform services that power medOS.

18 min read diagramsUpdated 2026-04-15docs/PLATFORM_SERVICES.md

Branch: claude/explore-new-repo-GVf2W Files changed: 16 | Lines added: 2,421

What This Is

Two optional infrastructure services that bolt onto the medOS hospital stack:

  1. Metabase — BI analytics dashboards (“medOS Analytics”)
  2. Wazuh — SIEM/XDR security monitoring (“medOS Security Monitor”)

Both are pre-configured to work with medOS data and branding. Hospital IT deploys them and everything is ready — no configuration, no learning curve.


Why These Two

Need Solution Why not alternatives?
Hospital analytics (census, revenue, bed occupancy) Metabase Open-source, connects directly to MongoDB, non-technical users can browse dashboards without SQL
Security monitoring (HIPAA, intrusion detection, audit) Wazuh Open-source SIEM with built-in file integrity, agent-based monitoring, and compliance mapping

Removed: OpenCTI was originally included but removed — it’s a threat intelligence platform for SOC teams, not something hospital IT departments would use.


File Structure

infrastructure/platform-services/
├── .env.example                        # All credentials (MUST change before deploy)
├── README.md                           # User-facing quick start
├── deploy-platform.sh                  # Unified deploy script (197 lines)
├── hospital-sizes.env                  # 4 scaling profiles
│
├── branding/                           # Shared medOS brand assets
│   ├── medos-logo.png                  # Heartbeat circle icon (62 KB)
│   ├── medos-favicon.ico               # Browser tab icon
│   ├── medos-favicon.png               # PNG variant
│   ├── medos-wordmark.png              # EVER logo horizontal (17 KB)
│   └── medos-wordmark.svg              # EVER logo vector
│
├── metabase/
│   ├── docker-compose.metabase.yml     # Metabase + PostgreSQL (metadata)
│   └── metabase-setup.sh              # Auto-setup: branding + 13 dashboards
│
└── wazuh/
    ├── docker-compose.wazuh.yml        # Indexer + Manager + Dashboard
    ├── medos-decoders.xml              # 6 custom log decoders (225 lines)
    ├── medos-rules.xml                 # 80+ detection rules (864 lines)
    └── wazuh-setup.sh                  # Auto-setup: rules + branding

Hospital Size Scaling

Every service has resource limits tuned to four deployment sizes. The deploy-platform.sh script reads hospital-sizes.env and exports the right variables before running docker compose up.

Profile Beds Metabase Wazuh (total) Combined
small < 50 1 GB 2 GB ~3 GB
medium 50–300 2 GB 4 GB ~6 GB
large 300–1000 4 GB 8 GB ~12 GB
enterprise 1000+ 6 GB 16 GB ~22 GB

Controls: Java heap, CPU shares, Docker memory limits, Wazuh indexer JVM, and (for Metabase) concurrent query capacity.


Metabase — “medOS Analytics”

Docker Architecture

┌─────────────────────────────────────────┐
│  medos-metabase (port 3100)             │
│  metabase/metabase:latest               │
│  Connects to medOS MongoDB for queries  │
│  Stores metadata in its own PostgreSQL  │
├─────────────────────────────────────────┤
│  metabase-postgres (port 5433)          │
│  postgres:14.5                          │
│  Internal metadata only (not patient)   │
└─────────────────────────────────────────┘

Branding Applied

Setting Value
Application name medOS Analytics
Brand color #009378 (medOS teal)
Logo Heartbeat circle (medos-logo.png)
Favicon medos-favicon.ico
Loading message “Preparing hospital data…”
Metabase links Hidden
Metabot Disabled
Help link Hidden

Pre-built Dashboards (13 reports)

Created automatically by metabase-setup.sh via the Metabase API.

Clinical Operations:

Report MongoDB Collection Query Type
Daily Patient Census admission Group by ward, filter status=Admit/Admitted
Admissions Today admission Filter admitDateTime >= today
Discharges This Week admission Filter dischargeDateTime >= 7 days ago
Emergency Visits (30d) admission Filter treatmentMode=Emergency, group by date
Top 20 Diagnoses (30d) diagnosis Group by icd10Code, sort by count

Financial & Billing:

Report MongoDB Collection Query Type
Daily Revenue Summary invoice Group by docDate, sum totalAmount
Outstanding A/R account_receivable Filter status != Paid, group by payorName
Payment Methods receipt Group by paymentMethod, sum amount

Hospital Operations:

Report MongoDB Collection Query Type
Bed Occupancy by Ward bed Group by ward, calc occupied/total ratio
Lab Request Volume (7d) lab_request Group by date, count
Medication Orders by Status medication_request Group by status
Active Staff Today user Filter lastLogin >= today, group by department
Appointment Volume (7d) appointment Filter start between today and +7d

Wazuh — “medOS Security Monitor”

Docker Architecture

┌─────────────────────────────────────────┐
│  medos-wazuh-indexer (port 9201)        │
│  wazuh/wazuh-indexer:4.9.2              │
│  OpenSearch-based, stores alert data    │
├─────────────────────────────────────────┤
│  medos-wazuh-manager                    │
│  wazuh/wazuh-manager:4.9.2             │
│  Ports: 55000 (API), 1514 (agents),    │
│         1515 (enrollment), 514/udp      │
│  Runs rules engine, receives logs       │
├─────────────────────────────────────────┤
│  medos-wazuh-dashboard (port 5601)      │
│  wazuh/wazuh-dashboard:4.9.2           │
│  Branded as "medOS Security Monitor"    │
└─────────────────────────────────────────┘

Branding Applied

Setting Value
Application title medOS Security Monitor
Tab title medOS Security
App logo Heartbeat circle
Sidebar logo EVER wordmark
Health check logo Heartbeat circle
Favicon medos-favicon.ico

Custom Decoders (9 parsers — medos-decoders.xml)

Each decoder parses a specific medOS log format so Wazuh rules can trigger on structured fields.

Decoder Source Format Key Fields Extracted
medos-gateway API Gateway JSON (Moleculer) level, msg, nodeID, action, caller, requestID, duration
medos-auth AAA Service Syslog structured action, user, ip, status, role, department
medos-access Audit Trail Syslog structured user, action, resource, patient ID, breakglass flag
medos-db Database Proxy Syslog structured user, query_type, table, rows_returned, duration_ms
medos-device Device Gateway Syslog structured device_id, type, ip, event, target, status
medos-rbac RBAC Events Syslog structured actor, action, target_user, role, prev_role
medos-manifest Supabase triggers + backend Syslog structured table, action, event_type, encounter, source, client_type
medos-orchestrator Deno Edge Function JSON + syslog level, event_id, event_type, latency_ms, status, hmac_valid
medos-workflow Workflow State Machine Syslog structured event, user, encounter, from, to, transition_valid, server_validated

Custom Rules (130+ detections — medos-rules.xml)

All rules use ID range 100000–100999 (Wazuh custom range). Severity levels follow Wazuh convention: 0–4 informational, 5–7 low, 8–10 medium, 11–13 high, 14–15 critical.

Authentication & Access Control (100000–100099)

Rule ID Level Detection HIPAA Ref
100000 3 Failed login attempt 164.312.d
100001 10 Brute force (5+ failures/2min from same IP) 164.312.d
100002 12 Targeted account attack (5+ failures/5min same user) 164.312.d
100010 8 After-hours login (22:00–06:00) 164.312.a.1
100011 6 Weekend login 164.312.a.1
100012 10 Login from external IP (outside RFC1918) 164.312.e.1
100722 6 User account disabled 164.308.a.3
100723 13 Disabled/terminated account still logging in 164.308.a.3
100730 5 Password changed 164.312.d
100731 7 Password reset by admin 164.312.d
100732 11 Bulk password resets (5+/5min by same admin) 164.312.d
100740 9 Shared/generic account login 164.312.a.2.i
100741 10 Concurrent sessions from different IPs 164.312.d
100742 12 Login from Tor exit node / anonymizer

Patient Record Access — HIPAA (100100–100199)

Rule ID Level Detection HIPAA Ref
100100 2 Patient record viewed (baseline) 164.312.a.1
100101 10 Bulk snooping (20+ records/5min) 164.308.a.5
100102 8 After-hours patient record access 164.312.a.1
100110 10 Break-glass emergency override used 164.308.a.4
100111 8 Access without care relationship 164.312.a.1
100120 4 Patient record edited 164.312.c.1
100121 12 Patient record deleted 164.312.c.1
100997 10 VIP/celebrity patient record accessed 164.312.a.1
100998 13 VIP snooping (3+ VIP records/10min) 164.312.a.1

Data Exfiltration (100200–100299)

Rule ID Level Detection HIPAA Ref
100200 6 Data export event (baseline) 164.312.e.1
100201 12 Bulk export (100+ records) 164.308.a.1
100202 13 After-hours export 164.312.e.1
100203 11 Repeated exports (3+/10min same user) 164.312.e.1

Database Anomalies (100300–100399)

Rule ID Level Detection
100300 8 Large query result (1000+ rows)
100301 11 Mass query on clinical tables (patient, diagnosis, vital_sign)
100310 6 Slow query (>5 seconds)
100320 15 DROP/TRUNCATE on production tables

Medical Device Security (100400–100499)

Rule ID Level Detection
100400 10 Device attempting external connection
100401 8 Blocked connection from device
100410 12 Unauthorized firmware update
100420 9 New unknown device on medical network
100421 11 Device making repeated blocked connections

Privilege Escalation / RBAC (100500–100599)

Rule ID Level Detection HIPAA Ref
100500 7 Role assignment event 164.312.a.1
100501 12 Admin privilege granted 164.312.a.1
100502 14 Self-elevation (user changed own role) 164.312.a.1
100510 10 Break-glass override in RBAC context 164.312.a.1
100520 13 Rapid role changes (3+/5min)

Application Health (100600–100699)

Rule ID Level Detection
100600 5 API error (single)
100601 10 API error spike (20+/minute)
100610 6 Slow API response (>10 seconds)

Compliance & Audit (100700–100799)

Rule ID Level Detection HIPAA Ref
100700 15 Audit log tampering attempt 164.312.b
100710 8 System settings changed 164.312.a.1
100720 6 New user account created 164.308.a.3
100721 10 Rapid user creation (5+/5min)

Pharmacy & Medication Safety (100800–100899)

Rule ID Level Detection
100801 6 Controlled substance order
100802 11 High-volume controlled substance orders (10+/hour)
100810 9 Medication cancelled after dispensing (diversion risk)
100811 8 Medication safety override (CDS bypass)
100812 11 Frequent safety overrides (5+/hour)
100820 10 Self-dispensing detected
100830 7 Pharmacy inventory adjustment
100831 10 Large inventory decrease
100832 11 Frequent inventory adjustments (5+/hour)
100840 12 Medication administered without valid order
100841 7 High-alert medication ordered (insulin, heparin, chemo)

Blood Bank & Transfusion Safety (100900–100949)

Rule ID Level Detection
100900 3 Blood product issued (baseline)
100901 12 Blood issued WITHOUT crossmatch
100902 9 Emergency blood release (uncrossmatched)
100910 10 Expired blood product still in inventory
100911 5 Blood product discarded (waste tracking)
100912 9 High wastage (5+ discards/24h)
100920 14 Blood type mismatch — STOP transfusion
100930 8 Blood stock critically low

Ransomware & Malware (100950–100979)

Rule ID Level Detection
100950 14 Files renamed with encryption extensions
100951 15 Ransom note file detected
100952 13 50+ file modifications in 30 seconds
100955 12 Credential dumping tool (mimikatz, lazagne, etc.)
100956 10 Encoded PowerShell execution
100957 14 Shadow copy deletion (backup destruction)
100958 9 Suspicious scheduled task creation
100960 10 Large outbound data transfer
100961 12 DNS query to known malicious domain

Session & API Abuse (100980–100999)

Rule ID Level Detection
100980 8 API rate limit exceeded
100981 12 Sustained API abuse (10+ rate limit hits/minute)
100982 10 Expired JWT token reuse (replay attack)
100983 9 Session IP changed (hijack indicator)
100985 10 Non-admin accessing admin API endpoints
100986 12 SQL injection attempt
100987 11 XSS attempt
100988 11 Path traversal attempt
100990 5 Unauthorized API access (401)
100991 10 Authorization probing (15+ 401s/2min)
100992 9 Untrusted FHIR/interop endpoint access
100993 5 Report printed (audit)
100994 9 Bulk printing (10+/10min)
100995 7 E-form template modified
100996 8 E-form accessed for discharged patient

Event System Monitoring (medOS-Specific)

The medOS stack broadcasts events through a specific pipeline. These rules monitor that pipeline for tampering, forgery, and failures.

Event Flow

Backend API write
    ↓
hospital_events table (Supabase, append-only)
    ↓ Postgres trigger
    ↓ Webhook (HMAC-signed)
Encounter Orchestrator (Deno Edge Function)
    ↓ projects into
┌────────────────────────┬────────────────────────┬──────────────┐
encounter_journey_cache   department_queues        event_dlq
(per-encounter state)     (operational queues)     (failed events)
    ↓ Supabase realtime
React frontend subscribes

There are 140+ event types flowing through this pipeline. Rules below catch tampering at each stage.

Manifest / Encounter Journey Integrity (101000–101099)

Rule ID Level Detection HIPAA Ref
101000 2 hospital_events INSERT (baseline)
101001 13 hospital_events UPDATE/DELETE (append-only violation) 164.312.b, c.2
101010 13 encounter_journey_cache modified by non-orchestrator
101011 14 Frontend attempted direct write to read model
101020 10 Invalid event_type (possible injection)
101021 11 Event for non-existent encounter (forgery)
101030 10 Event storm (50+/minute for single encounter)
101040 11 Duplicate event_id (replay attack)
101041 9 Out-of-order event (state inconsistency)
101050 10 Event for archived encounter (zombie event)
101060 13 Safety snapshot tampered outside rules engine

Event Orchestration & Dead Letter Queue (101100–101199)

Rule ID Level Detection
101100 6 Orchestrator error (baseline)
101101 11 Error spike (5+/minute)
101110 8 Event sent to DLQ
101111 12 DLQ growing rapidly (10+/5min — pipeline broken)
101120 8 Slow orchestrator processing (>1 second)
101130 12 Orchestrator health check failing
101140 13 Invalid HMAC on webhook (forged event)
101141 14 Sustained HMAC forgery campaign (3+/5min)
101150 5 Cold start / restart
101151 10 Frequent restarts (5+/15min — unstable)
101160 7 Clinical alert pruning triggered

Workflow State Machine (101200–101299)

Rule ID Level Detection HIPAA Ref
101200 3 Workflow session started (baseline)
101210 12 Illegal workflow transition attempt
101211 9 Out-of-sequence workflow step
101220 5 Workflow session cancelled
101221 9 High cancellation rate (10+/hour)
101230 9 Workflow template modified 164.312.c.1
101231 13 Workflow template DELETED
101240 13 Transition without server validation
101250 6 Stale workflow session detected
101260 12 Workflow session bound to wrong target (hijack)

NATS / Moleculer Messaging (101300–101399)

Rule ID Level Detection
101300 8 NATS disconnection
101301 12 NATS broker unstable (5+ disconnects/10min)
101310 7 Moleculer action timeout / service not found
101311 11 Timeout spike (20+/2min)
101320 10 Unauthorized NATS subject subscription
101330 8 Moleculer node disappeared (service crash)
101340 7 Stale/lying cache detected

Supabase Realtime Channels (101400–101499)

Rule ID Level Detection HIPAA Ref
101400 10 Unauthorized realtime subscription 164.312.e.1
101401 11 Non-clinical user subscribed to journey cache 164.312.a.1
101410 10 Wildcard channel subscription (data mining)
101420 11 High-volume realtime consumption (500+/min scraping)
101430 10 Realtime subscription from external IP 164.312.e.1

Read Model & Queue Integrity (101500–101599)

Rule ID Level Detection
101500 13 department_queues modified by non-orchestrator
101510 10 Queue priority rules modified
101520 12 Queue number manually changed (line-jumping)
101521 11 Queue status changed bypassing workflow
101530 12 Clinical activity counter reset (metric tampering)
101540 9 Cache drift detected (orchestrator missed events)
101541 12 Frequent cache drifts (10+/30min)

Reverse Proxy Integration

Routes added to the Nginx default.conf.template (first server block):

/metabase/  →  medos-metabase:3000
/wazuh/     →  medos-wazuh-dashboard:5601  (with WebSocket upgrade)

Environment variables for host override: METABASE_HOST, WAZUH_DASHBOARD_HOST.


Deployment Flow

# 1. Copy and edit credentials
cd infrastructure/platform-services
cp .env.example .env
vim .env                               # Change ALL passwords

# 2. Deploy with hospital size
./deploy-platform.sh up medium         # or: small, large, enterprise

# 3. Wait ~2 minutes for containers to start, then run setup
./metabase/metabase-setup.sh           # Creates dashboards + branding
./wazuh/wazuh-setup.sh                 # Installs rules + branding

# 4. Verify
./deploy-platform.sh status

After this, hospital IT opens:

  • http://<host>/metabase/ — dashboards are already there
  • http://<host>/wazuh/ — security alerts are already flowing

Network Topology

All platform services join the medos-platform Docker bridge network. The deploy script auto-creates it if missing.

┌─────────────────────────────────────────────────────────┐
│  medos-platform network (Docker bridge)                 │
│                                                         │
│  ┌──────────┐  ┌──────────────┐  ┌───────────────────┐ │
│  │ Metabase  │  │ Wazuh        │  │ Wazuh             │ │
│  │ :3100     │  │ Manager      │  │ Dashboard :5601   │ │
│  └────┬─────┘  │ :55000/1514  │  └────────┬──────────┘ │
│       │        └──────┬───────┘           │             │
│  ┌────┴─────┐  ┌──────┴───────┐           │             │
│  │ Metabase  │  │ Wazuh        │           │             │
│  │ Postgres  │  │ Indexer      ├───────────┘             │
│  │ :5433     │  │ :9201        │                         │
│  └──────────┘  └──────────────┘                         │
│                                                         │
│  ─── Also on this network: ───                          │
│  mongo:27017  nats:4222  api-gateway:3001  web:3000     │
└─────────────────────────────────────────────────────────┘

Port Reference

Port Service Protocol Exposed
3100 Metabase UI HTTP Yes
5433 Metabase PostgreSQL TCP Yes (configurable)
5601 Wazuh Dashboard HTTP Yes
9201 Wazuh Indexer HTTP Yes
55000 Wazuh Manager API HTTPS Yes
1514 Wazuh Agent comms TCP Yes
1515 Wazuh Agent enrollment TCP Yes
514 Syslog collector UDP Yes

Customization

Swap Logos

Replace files in branding/ with hospital-specific logos:

  • medos-logo.png — square icon (recommended: 512x512 PNG)
  • medos-wordmark.png — horizontal logo for sidebars
  • medos-favicon.ico — browser tab icon

Re-run the setup scripts to apply.

Add Metabase Dashboards

Edit metabase/metabase-setup.sh and add more create_question calls. The function takes: name, description, collection_id, and a MongoDB aggregation pipeline as JSON.

Add Wazuh Rules

Add rules to wazuh/medos-rules.xml using IDs in the 100000–100999 range. Re-run wazuh/wazuh-setup.sh to deploy.

Adjust Scaling

Edit hospital-sizes.env to tune resource limits for your hardware. The variable naming convention is {SIZE}_{SERVICE}_{SETTING}.


Commits

Hash Description
c9c7fe68 Initial platform services (Metabase, OpenCTI, Wazuh) with hospital-size scaling
e81f95e2 Remove OpenCTI (not needed for hospital IT)
2d09150e Zero-config hospital customizations (13 dashboards, 40+ rules)
8a6689ef Custom Wazuh decoders for medOS log formats
36fe46f2 Expand to 80+ hospital-specific detections
88e45710 Rebrand Metabase and Wazuh with medOS logos and colors
Ask Anything