Edge Functions Architecture
Serverless compute layer on Supabase Edge Functions (Deno) - orchestrators, matchers, dispatchers.
7 min read diagramsUpdated 2026-03-26docs/architecture/architecture/01-edge-functions.md
Serverless compute layer — Supabase Edge Functions (Deno Deploy)
Overview
MedOS uses Supabase Edge Functions as its serverless compute layer — no AWS Lambda, SAM, or CDK. All functions run on Deno Deploy with TypeScript, invoked via HTTP POST or Postgres database triggers.
Two deployment targets exist:
| Deployment | Location | Functions |
|---|---|---|
| Clinic Frontend | ever-medos-global-pure-react/supabase/functions/ |
5 functions |
| Medbase HIS Backend | his-vajira/medbase/supabase/functions/ |
1 function (+ 15 planned) |
Architecture Diagram
┌─────────────────────────────────────────────────────────────────────┐
│ INGRESS LAYER │
├─────────────┬──────────────┬──────────────┬─────────────────────────┤
│ React UI │ Metriport │ Postgres │ WebhookDispatcher │
│ (HTTP POST)│ (Webhook) │ (DB Trigger)│ (HMAC-signed POST) │
└──────┬──────┴──────┬───────┴──────┬───────┴──────────┬──────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────┐
│ SUPABASE EDGE FUNCTIONS (Deno) │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │
│ │ claim-coder │ │ diagnosis-assist │ │ patient-screener │ │
│ │ ────────── │ │ ─────────────── │ │ ──────────────── │ │
│ │ Medical Record │ │ Symptoms+History │ │ Intake Data │ │
│ │ ↓ │ │ ↓ │ │ ↓ │ │
│ │ Dify AI (POST) │ │ Dify AI (POST) │ │ Dify AI (POST) │ │
│ │ ↓ │ │ ↓ │ │ ↓ │ │
│ │ ICD/CPT Codes │ │ Diff. Diagnoses │ │ Risk Score │ │
│ └────────┬─────────┘ └────────┬──────────┘ └────────┬──────────┘ │
│ │ │ │ │
│ ┌────────▼─────────────────────▼───────────────────────▼──────────┐ │
│ │ _shared/difyClient.ts │ │
│ │ callDifyClaimCoder() | callDifyDiagnosisAssistant() │ │
│ │ callDifyPatientScreener() | callDifyWorkflow() │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ fhir-webhook │ │ integration-health-check │ │
│ │ ────────────── │ │ ──────────────────────── │ │
│ │ Metriport POST │ │ connection_id → fetch(base_url) │ │
│ │ HMAC verify │ │ Latency measurement │ │
│ │ Event dispatch: │ │ Status: ok/error + latency_ms │ │
│ │ • doc-download │ │ │ │
│ │ • doc-convert │ └──────────────────────────────────────────┘ │
│ │ • consolidated │ │
│ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐│
│ │ encounter-orchestrator (~30k LOC) ││
│ │ ───────────────────────────────────────────── ││
│ │ Ingress: DB Trigger | WebhookDispatcher | Direct POST ││
│ │ ││
│ │ Events: ││
│ │ encounter.opened/progressed/closed ││
│ │ order.placed/fulfilled/cancelled ││
│ │ lab.resulted | imaging.resulted | medication.administered ││
│ │ alert.issued/resolved ││
│ │ ││
│ │ Outputs → encounter_journey_cache (read model) ││
│ │ → department_queues (operational queues) ││
│ │ → dlq (dead letter queue on error) ││
│ │ ││
│ │ Features: dedup by event_id | dept routing | alert pruning ││
│ │ DLQ for retry | latency logging ││
│ └──────────────────────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────┐
│ PERSISTENCE LAYER │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ Supabase Postgres│ │ Dify AI Platform │ │ External Systems │ │
│ │ ─────────────── │ │ ──────────────── │ │ ───────────────── │ │
│ │ claim_coding_req │ │ Workflow Engine │ │ Metriport (HIN) │ │
│ │ diagnosis_req │ │ (hosted/self) │ │ EHR endpoints │ │
│ │ screening_req │ │ │ │ Integration URLs │ │
│ │ fhir_hin_docs │ └─────────────────┘ └─────────────────────┘ │
│ │ fhir_audit_log │ │
│ │ encounter_cache │ │
│ │ department_queues│ │
│ │ integration_conn │ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
Function Details
1. claim-coder
| Property | Value |
|---|---|
| Path | ever-medos-global-pure-react/supabase/functions/claim-coder/index.ts |
| Trigger | HTTP POST from React frontend |
| Auth | Supabase JWT (from request header) |
| AI Backend | Dify workflow via DIFY_CLAIM_CODER_ENDPOINT |
| Input | { claimCodingData: { medicalRecord: string } } |
| Output | { suggested_icd_codes, suggested_cpt_codes } |
| DB Table | claim_coding_requests (request + response + user_id) |
2. diagnosis-assistant
| Property | Value |
|---|---|
| Path | ever-medos-global-pure-react/supabase/functions/diagnosis-assistant/index.ts |
| Trigger | HTTP POST from React frontend |
| Auth | Supabase JWT |
| AI Backend | Dify workflow via DIFY_DIAGNOSIS_ASSISTANT_ENDPOINT |
| Input | { patientData: { symptoms, historyAndContext, keyTestResults, vitals? } } |
| Output | { potential_diagnoses, suggested_orders: { labs, imaging, meds, consults } } |
| DB Table | diagnosis_assistant_requests |
3. patient-screener
| Property | Value |
|---|---|
| Path | ever-medos-global-pure-react/supabase/functions/patient-screener/index.ts |
| Trigger | HTTP POST from React frontend |
| Auth | Supabase JWT |
| AI Backend | Dify workflow via DIFY_PATIENT_SCREENER_ENDPOINT |
| Input | { intakeData: { age, presentingComplaint, medicalHistory, medications, allergies } } |
| Output | { identified_risks, suggested_actions, risk_score } |
| DB Table | patient_screening_requests |
4. fhir-webhook
| Property | Value |
|---|---|
| Path | ever-medos-global-pure-react/supabase/functions/fhir-webhook/index.ts |
| Trigger | Metriport webhook POST (external HIN provider) |
| Auth | HMAC-SHA256 signature via x-metriport-signature header |
| Events | medical.document-download, medical.document-conversion, medical.consolidated-data |
| DB Tables | fhir_hin_documents, fhir_hin_patient_map, fhir_audit_log |
| Features | Dedup by metriport_doc_id, status tracking (downloaded → converted) |
5. integration-health-check
| Property | Value |
|---|---|
| Path | ever-medos-global-pure-react/supabase/functions/integration-health-check/index.ts |
| Trigger | HTTP POST from frontend or scheduled checks |
| Input | { connection_id: string } |
| Output | { status, latency_ms, http_status, error? } |
| DB Table | integration_connections (updates last_health_check, health_check_ok) |
| Timeout | 10 seconds per check |
6. encounter-orchestrator
| Property | Value |
|---|---|
| Path | his-vajira/medbase/supabase/functions/encounter-orchestrator/index.ts |
| Scale | ~30,500 LOC — the largest edge function |
| Triggers | 3 ingress paths (DB trigger, WebhookDispatcher, Direct POST) |
| Auth | HMAC-SHA256 (x-vajira-signature) or Service Role Key |
| Events | 11 event types (encounter, order, lab, imaging, medication, alert) |
| Output Tables | encounter_journey_cache, department_queues, dlq |
| Features | Event dedup, department routing, alert pruning (max 50), DLQ, latency logging |
Environment Variables
# Clinic Frontend Functions
DIFY_API_KEY= # Dify platform auth
DIFY_CLAIM_CODER_ENDPOINT= # Claim coding workflow URL
DIFY_DIAGNOSIS_ASSISTANT_ENDPOINT= # Diagnosis workflow URL
DIFY_PATIENT_SCREENER_ENDPOINT= # Screening workflow URL
SUPABASE_URL= # Supabase project URL
SUPABASE_ANON_KEY= # Supabase public key
METRIPORT_WEBHOOK_SECRET= # FHIR webhook HMAC secret
# Medbase Backend Function
SUPABASE_SERVICE_ROLE_KEY= # Privileged DB access
VAJIRA_WEBHOOK_SECRET= # Internal webhook HMAC secret
WEBHOOK_SECRET= # Alternate webhook secret
Shared Utilities
_shared/difyClient.ts (Clinic)
Centralized Dify AI workflow client with endpoint routing and auth injection. All three AI functions delegate to this shared module.
_shared/medbase-client.ts (Medbase)
MongoDB admin client for encounter-orchestrator’s read model projections.
_shared/event-contract.ts (Medbase)
Event type normalization — maps raw webhook payloads to typed HospitalEvent union.
_shared/hmac.ts (Medbase)
HMAC-SHA256 signature verification for webhook security.
Data Flow Patterns
AI Clinical Decision Support (claim-coder, diagnosis-assistant, patient-screener)
React UI → POST + JWT → Edge Function → Validate Auth → Call Dify AI → Store to DB → Return Response
FHIR Health Information Network (fhir-webhook)
Metriport → POST + HMAC → Edge Function → Verify Signature → Parse Event → Upsert Documents → Audit Log
Encounter Event Projection (encounter-orchestrator)
Backend API Write → Postgres Trigger OR WebhookDispatcher → Edge Function → Dedup Check
→ Project to encounter_journey_cache + department_queues → Supabase Realtime → React UI
→ On Error: Write to DLQ
Deployment
# Deploy individual function
supabase functions deploy claim-coder
supabase functions deploy encounter-orchestrator
# Set secrets
supabase secrets set DIFY_API_KEY=xxx METRIPORT_WEBHOOK_SECRET=yyy
Key Design Decisions
- Supabase over AWS Lambda — Tight integration with Supabase Postgres, Realtime channels, and Auth. No cold start issues with Deno Deploy.
- Dify as AI orchestrator — Externalizes prompt engineering and workflow management to Dify platform rather than embedding in edge functions.
- encounter-orchestrator as CQRS projection — Implements the “write model” → “read model” pattern. Backend writes to
hospital_events, the orchestrator projects to query-optimized caches. - HMAC for webhook security — Both external (Metriport) and internal (WebhookDispatcher) webhooks are HMAC-verified.
- DLQ pattern — Failed events go to dead letter queue for retry/audit rather than being lost.