medOS ultra

IPD Command Center Deployment

Operator handoff for getting the IPD command center to show real data on a fresh Supabase project.

4 min read diagramsUpdated 2026-05-06docs/architecture/ipd-command-center-deployment.md

This is the operator handoff for getting /ipd/command-center to show real data on a fresh Supabase project (PH demo or otherwise).

What ships in the codebase (already merged)

  1. Page at /ipd/command-center (5 view modes + left rail + right slider)
  2. /ipd/quick-entry mini-app — emits all 4 EMRAM events directly into hospital_events so the orchestrator picks them up
  3. 4 new orchestrator handlers — handleVitalsDocumented / handleLabResultFiled / handleMedicationAdministered / handleAntibioticTiming in infrastructure/medbase/functions/encounter-orchestrator/
  4. Migration 054_ipd_command_center_projections.sql — adds the partial location index + (if cron_jobs registry exists) seeds the daily antibiotic-day-count cron

Deploy steps (manual — CLI access only on operator machine)

1. Apply migrations

In the Supabase SQL editor (or psql):

# If the cron_jobs registry isn't there yet, apply 036 first (safe to re-run):
psql "$SUPABASE_DB_URL" -f infrastructure/medbase/migrations/036_cron_jobs_registry.sql

# Always apply 054 (idempotent — guard checks for cron_jobs):
psql "$SUPABASE_DB_URL" -f infrastructure/medbase/migrations/054_ipd_command_center_projections.sql

# Apply the read-model schema (idempotent):
psql "$SUPABASE_DB_URL" -f web/supabase/migrations/20260209_ipd_dashboard_tables.sql

2. Deploy the orchestrator

supabase functions deploy encounter-orchestrator

This is the deploy that activates the 4 new handlers — without it, vitals/MAR/lab/antibiotic events written to hospital_events will be ignored.

3. Verify the read model is reachable

-- Should return 0 rows on a fresh project, and an existing row count on a populated one.
SELECT count(*) FROM ipd_admissions_dashboard;

-- Should return the partial index from migration 054:
SELECT indexname FROM pg_indexes
WHERE indexname = 'idx_journey_cache_location_partial';

Backfill (the most important part if your dashboard is empty)

The 5 PH [DEMO] patients (HN 6–10/69) have admissions in MongoDB but probably no rows in ipd_admissions_dashboard. There are two paths:

Path A — Seed sample rows directly (fastest, demo-friendly)

-- Seed 5 demo IPD admissions matching the PH [DEMO] patients.
-- Safe to re-run (ON CONFLICT DO NOTHING).
INSERT INTO public.ipd_admissions_dashboard
  (admission_id, encounter_id, hn, patient_name, ward_id, ward_name,
   bed_number, admission_date, los_days, primary_doctor, payor, status)
VALUES
  ('demo-adm-006', 'demo-enc-006', '6/69',  '[DEMO] Maria Santos',     'ward-1', 'General Ward 1',  '101', now() - interval '2 days', 2, 'Dr. Cruz',    'PhilHealth', 'in-progress'),
  ('demo-adm-007', 'demo-enc-007', '7/69',  '[DEMO] Juan Dela Cruz',   'ward-1', 'General Ward 1',  '102', now() - interval '3 days', 3, 'Dr. Reyes',   'PhilHealth', 'in-progress'),
  ('demo-adm-008', 'demo-enc-008', '8/69',  '[DEMO] Anna Reyes',       'ward-1', 'General Ward 1',  '103', now() - interval '1 day',  1, 'Dr. Cruz',    'Self-pay',   'in-progress'),
  ('demo-adm-009', 'demo-enc-009', '9/69',  '[DEMO] Pedro Garcia',     'ward-2', 'General Ward 2',  '201', now() - interval '5 days', 5, 'Dr. Lim',     'HMO',        'in-progress'),
  ('demo-adm-010', 'demo-enc-010', '10/69', '[DEMO] Sofia Mendoza',    'ward-2', 'General Ward 2',  '202', now() - interval '4 days', 4, 'Dr. Lim',     'PhilHealth', 'in-progress')
ON CONFLICT (admission_id) DO NOTHING;

After running, /ipd/command-center should immediately show 5 patients across 2 wards.

Path B — Backfill from real MongoDB admissions (production path)

If the demo patients already have admission records in MongoDB and you want to drive everything end-to-end, fire manifest.admission.updated events for each. The orchestrator’s handleAdmissionUpdated will then write to encounter_journey_cache, and a follow-up trigger projects to ipd_admissions_dashboard (only if your project has the projection trigger — check web/supabase/migrations/20260209_ipd_dashboard_tables.sql).

Easiest way to test this path: open /ipd/quick-entry, paste an encounter ID, and click “Send admission-updated event” (provided as a button in the mini-app).

Testing the full flow with /ipd/quick-entry

Once Path A or B is done and the orchestrator is deployed:

  1. Open /ipd/command-center — see 5 patients in grid view.
  2. Click any patient → right slider opens with 8 tabs.
  3. In a second tab, open /ipd/quick-entry.
  4. Pick the same patient’s encounter_id.
  5. Submit a vitals reading → Command Center NEWS2 chip updates within 2 seconds (realtime).
  6. Submit a critical lab result → AcknowledgementInbox FAB badge increments; the patient’s row gets a tier-3 alert chip.
  7. Submit a med-administered scan → BCMA % column updates.
  8. Submit antibiotic-started → safety-indicator card on the card view shows “Day 1” stewardship.

What’s still missing (production gap, not a demo blocker)

  • Backend emitters for events 3 & 4: services/medication/.../medicationAdministration.controller.mixin.ts and the antibiotic order placement controller don’t call emitMedicationAdministered() / emit antibiotic_started yet. The Quick Entry mini-app fills this gap for demos, but production needs the controller wiring (~10 LOC each, requires PH backend deploy).
  • antibiotic-day-recompute edge function: the cron entry references it but the function doesn’t exist. Either build it (~50 LOC Deno) or leave the cron disabled (default in migration 054).
Ask Anything