Last updated: 2026-05-30
sequenceDiagram
participant App as Patient App
participant WS as Socket.io (/queue)
participant API as NestJS API
participant ML as ML Service
participant DB as PostgreSQL
participant Cron as Cron Job (15 min)
Note over Cron,DB: Background — every 15 minutes
Cron->>DB: SELECT COUNT(*) per branch/department
DB-->>Cron: queue counts
Cron->>DB: INSERT queue_snapshots
Note over App,WS: Patient has checked in
App->>WS: connect (socket.io) to /queue namespace
App->>WS: join room "appointment:<id>"
WS-->>App: emit { queueNumber, position, estimatedWaitMinutes, status }
Note over App,ML: ML-enhanced wait time
App->>API: GET /predict/wait-time?branchId=...
API->>DB: SELECT latest queue_snapshot WHERE branch_id=...
DB-->>API: { queueLength: 8 }
API->>ML: POST /predict/wait-time { hour:10, dayOfWeek:2, queueLength:8, doctorAvgTime:25 }
ML-->>API: { predicted_wait_minutes: 22 }
API-->>App: { predictedWaitMinutes: 22, confidence: 0.80, isFallback: false }
Note over App: Displays "~22 min (AI Est.)"
Note over WS: When doctor calls next patient
WS-->>App: emit { queueNumber: 4, position: 1, status: "NEXT" }
App->>App: show "You're next!" alert
Note over WS,App: Polling fallback (every 10s if WS unavailable)
App->>API: GET /appointments/:id
API->>DB: SELECT * FROM appointments WHERE id=...
DB-->>API: appointment data
API-->>App: { queuePosition, estimatedWaitTime }
| Event | Direction | Payload |
|---|---|---|
queue:update |
Server → Client | { queueNumber, currentNumber, position, estimatedWaitMinutes, status } |
queue:called |
Server → Client | { message: "Your turn!" } |
join-queue |
Client → Server | { appointmentId } |
/queue namespace.GET /predict/wait-time (polled every 3 min).appointment.estimatedWaitTime field from REST polling every 10s.If ML service is unreachable → isFallback: true → display socket or static estimate.