Changelog¶
All notable changes to VitaraVox
This project adheres to Semantic Versioning.
[4.3.0] - 2026-03-09¶
SMS Booking Confirmation + OSCAR REST Production + Provider Config¶
Three major features merged to main: SMS confirmations via Telnyx, OSCAR REST protocol extension for Kai-hosted instances, and 3-level provider configuration inheritance.
SMS Booking Confirmation¶
- Telnyx API v2 integration via native
fetch(no SDK) —sms.service.ts(353 lines) - Fire-and-forget pattern:
setImmediate()in webhook handler ensures SMS never delays Vapi tool response - 5-guard chain (
sms.service.ts:55-100): TELNYX_API_KEY → smsSenderNumber → smsConsent → valid phone → smsEnabled - Opt-out consent model: Default
smsConsent: true; onlyfalsewhen patient explicitly declines during Patient-ID phase - 6 default templates: 3 actions (booking, reschedule, cancel) × 2 languages (EN, ZH)
- Custom templates: Per-clinic JSON in
ClinicConfig.smsTemplateswith{{patientName}},{{date}},{{time}},{{providerName}}variables - Platform-level Telnyx: Single API key + messaging profile in env vars; per-clinic sender numbers in DB
- Phone normalization:
normalizeToE164()handles North American formats (10/11 digit, with/without +1) - 3 API endpoints:
GET /api/clinic/config/sms,POST /api/clinic/config/sms,POST /api/clinic/config/sms/validate - Voice agent updates:
smsConsentparam added tocreate_appointment,update_appointment,cancel_appointmenttools;smsSentresponse field; consent disclosure in Patient-ID prompt - 79 unit tests covering guard chain, templates, normalization, service, API routes
OSCAR REST Protocol Extension¶
- OAuth 1.0a 3-leg flow:
POST /api/oscar/oauth/initiate→ callback → token exchange (oscar-oauth.ts:45-269) - 11 REST endpoints: demographics CRUD, appointment CRUD, provider search, schedule data
preferRestflag: Per-clinic setting for Kai-hosted OSCAR behind Cloudflare WAF (which blocks SOAP content-inspection)- Provider 3-tier fallback: JSON (Accept: application/json) → XML (Accept: application/xml) → DB cache
- Split circuit breakers: SOAP and REST adapters have independent Opossum breakers
- AES-256-GCM storage: OAuth tokens encrypted at rest, scope-isolated resolution (NEVER mix clinic + env)
- Token monitor: 6 AM + 6 PM daily check for expiring tokens (10-year TTL default)
- 98 unit + 8 integration tests
Provider Configuration v3.1¶
- 3-level inheritance: Global defaults →
clinic_config→clinic_providers(resolved inprovider-config-resolver.ts) - 8 new
clinic_configcolumns:defaultVisitMode,defaultVisitReason,defaultIsNewPatient,defaultPreferredTime,scheduleIntelligenceEnabled,bookingBufferMinutes,maxDailyBookings,allowDoubleBooking - 4 new
clinic_providerscolumns:visitMode,visitReason,isNewPatient,preferredTime - Settings UI redesign: 4-card layout (General, Voice & Booking, OSCAR Configuration, Privacy & Compliance)
Database Changes¶
| Table | New Columns |
|---|---|
ClinicConfig |
smsSenderNumber, smsEnabled, smsLanguage, smsTemplates, smsBookingTemplate, smsRescheduleTemplate, smsCancelTemplate, smsCustomTemplates, smsWebhookUrl |
CallLog |
smsConsent, smsSentAt |
ClinicConfig |
defaultVisitMode, defaultVisitReason, defaultIsNewPatient, defaultPreferredTime, scheduleIntelligenceEnabled, bookingBufferMinutes, maxDailyBookings, allowDoubleBooking |
ClinicProviders |
visitMode, visitReason, isNewPatient, preferredTime |
[4.2.1] - 2026-03-07¶
v3.1 Provider Configuration + REST Schedule Intelligence + P1 Fixes¶
Comprehensive update covering provider-level configuration, REST protocol hardening, FreshBay E2E validation, Settings UI redesign, and resolution of all P1 known issues.
Provider Configuration (v3.1)¶
- 3-level config inheritance: Global defaults → clinic config → provider-level overrides via new
provider-config-resolver.ts - 8 new
clinic_configcolumns:defaultVisitMode,defaultVisitReason,defaultIsNewPatient,defaultPreferredTime,scheduleIntelligenceEnabled,bookingBufferMinutes,maxDailyBookings,allowDoubleBooking - 4 new
clinic_providerscolumns:visitMode,visitReason,isNewPatient,preferredTime - Tool parameter expansion:
create_appointmentandfind_earliest_appointmentnow acceptvisitMode,visitReason,isNewPatient,preferredTime
REST Protocol Hardening¶
- quickSearch fix: Correct param is
?query=(notsearchStringorterm). OSCAR CXF@QueryParam("query")annotation. - startTime fix:
.replace(/:\d{2}$/, '')on "14:00" produced "14". Fixed to.slice(0, 5). - Provider XML fallback: JSON returns 406 (JAXB bug) → XML
Accept: application/xmlreturns 200. 28 providers from Kai. - warmUp lifecycle:
EmrAdapterFactorynow awaits warmUp forpreferRestadapters. Prevents cold TLS (~6s) exceeding 4s breaker. - PM2 startup warmUp: IIFE in
index.tswarms allpreferRestclinic adapters on restart.
FreshBay E2E Validation (5/5 PASS)¶
- searchPatient, getScheduleSlots, createAppointment, getAppointments, cancelAppointment — all validated on Kai OSCAR
- Test appointment ID 314132 created+cancelled (provider 124, 2026-03-19)
- OAuth consumer
Vitaradevre-authorized with TTL=-1 (permanent)
Settings UI Redesign¶
- Settings page reorganized into 4 cards: General, Voice & Booking, OSCAR Configuration, Privacy & Compliance
- New
VoiceBookingConfigcomponent for booking rule management
P1 Fixes Resolved¶
| Fix | Details |
|---|---|
| ZH CONVERSATION STYLE | FALSE ALARM — all 4 ZH prompts already have ## 对话风格 |
| Past-date clamp | Added in bookAppointment handler (vapi-webhook.ts) |
| EMR adapter warmup | IIFE in index.ts warms preferRest adapters on PM2 startup |
| transfer_call tool | Added to 6 agents: Patient-ID EN/ZH, Booking EN/ZH, Registration EN/ZH |
| handoff_to_router_v3 | Added to Patient-ID-ZH in squad YAML |
| Lock degradation | acquireAdvisoryLock returns false on error (was true) |
Fax Fixes¶
- Response shape: Fax list returns
data: {docs, pagination}(not flat array) - Verify method: Changed from POST to PUT
[4.1.1] - 2026-02-25¶
Fixed -- Fax Intelligence Pipeline Hardening¶
4 bug fixes and 1 enhancement to the Fax Intelligence pipeline, discovered during end-to-end upload testing.
Bug Fixes¶
- Original uploads deleted after extraction -- The cleanup step was deleting ALL image paths including the original uploaded file. Now tracks temp files (PDF→PNG, TIFF→PNG conversions) separately and only deletes those. Original uploads are preserved on disk.
- Hardcoded
image/pngMIME type -- All 3 AI providers (Anthropic, OpenAI, Google) were sendingmedia_type: 'image/png'regardless of actual file type. Added dynamic MIME detection based on file extension (.jpg→image/jpeg,.png→image/png, etc.). - TIFF files accepted but unsupported -- Multer accepted TIFF uploads but no AI vision API supports TIFF natively. Added TIFF→PNG conversion using
sharplibrary with multi-page support (sharp({ pages: -1 })). - Wrong Anthropic model ID -- Hardcoded
claude-sonnet-4-6-20250514does not exist in the Anthropic API. Changed toclaude-sonnet-4-6(confirmed available via/v1/modelsquery).
Enhancement¶
- Configurable AI model -- Added
FAX_ANTHROPIC_MODELenv var (default:claude-sonnet-4-6) so model changes don't require code edits. Wired throughconfig/env.tsZod schema and consumed infax-extraction.service.ts.
Files Changed¶
| File | Change |
|---|---|
services/fax-extraction.service.ts |
MIME detection, TIFF conversion, temp file tracking, configurable model |
middleware/upload.ts |
Added fs.mkdirSync(UPLOAD_DIR, { recursive: true }) for missing directory |
config/env.ts |
Added FAX_ANTHROPIC_MODEL with Zod default |
Dependencies Added¶
sharp@0.34.5-- High-performance image processing for TIFF→PNG conversion
[4.2.0] - 2026-02-23¶
Pipecat Migration Analysis — Enterprise Architecture Review¶
Comprehensive CTO-level analysis of migrating from Vapi.ai to Pipecat (open-source) + AWS ECS Fargate. Expert-reviewed by CTO Architect and Senior Voice AI Engineer agents.
New Documentation¶
- Pipecat Migration Analysis (
8-upgrade-plans/pipecat-migration-analysis.md) — Full enterprise migration plan with 14 sections covering:- Current state inventory (9 Vapi assistants, 14 tools, OSCAR SOAP adapter)
- Target architecture (ECS Fargate + Pipecat Flows + Azure OpenAI Canada Central)
- CTO-level strategic comparison (Vapi vs Pipecat across 14 dimensions)
- Component migration map with effort estimates
- AWS ca-central-1 deployment architecture (VPC, ALB, Fargate, RDS, S3)
- HIPAA/PHIPA/PIPA compliance architecture with BAA chain
- Cost analysis: 45% infrastructure savings ($5,950 → $3,275/month at 10 clinics)
- 4-phase migration (804 hours / $120,600 / 22 weeks — revised after expert review)
- Devil's advocate review with 6 challenges addressed
- Risk register with 20+ risks across technical, compliance, operational, financial categories
- Go/No-Go decision framework with phase gates
Key Decisions Documented¶
- ECS Fargate over Lambda — Lambda's 15-min timeout and stateless model incompatible with voice sessions
- Azure OpenAI Canada Central over Bedrock — GPT-4o in Canada, same model as current prompts, automatic BAA
- Keep Node.js OSCAR adapters — 1,212 lines battle-tested; call from Python via HTTP
- Gated approach — Phase A ($0 HIPAA fix) → Phase B ($6K POC) → Phase C ($120K full)
[4.1.0] - 2026-02-21¶
Fax Intelligence -- AI-Powered Document Processing¶
Complete fax intake automation: AI extracts patient data from fax PDFs, matches against OSCAR EMR, and presents to MOA for one-click verification. Reduces per-fax processing from 5-15 minutes to 30 seconds.
Backend (8 new files, ~1,276 lines TypeScript)¶
- Multi-provider AI extraction (
fax-extraction.service.ts) -- PDF-to-PNG viapdftoppm, then AI vision analysis. Supports 3 providers viaFAX_AI_PROVIDERenv var:anthropic(default) -- Claude Sonnet 4.6openai-- GPT-4o-minigoogle-- Gemini 2.0 Flash
- Patient matching cascade (
fax-matching.service.ts) -- PHN exact match (100%) -> Name+DOB (95%) -> Name-only (85%) -> No match (review needed). Reuses existingEmrAdapterFactoryfor OSCAR search. - Fax provider abstraction (
IFaxProvider.ts+MockSRFaxProvider.ts) -- Interface with mock implementation for demo. Loads synthetic PDFs + JSON sidecars from fixtures directory. - Automated polling (
fax-poller.service.ts) -- Configurable interval polling with deduplication via faxId tracking. Start/stop lifecycle controlled by admin UI. - Orchestrator service (
fax.service.ts) -- Complete pipeline: file -> extract -> match -> persist. CRUD operations with pagination and status filtering. - 10 API endpoints (
routes/fax.ts) -- Upload, list, detail, verify match, polling start/stop/status, seed, reset, fixtures list. All behind JWT auth. - Upload middleware (
middleware/upload.ts) -- Multer disk storage for PDF/PNG/JPG/TIFF, 10MB max, UUID-based filenames. - 5 synthetic fax fixtures -- Referral, lab results, specialist report, prescription renewal, insurance pre-auth. Each with PDF + JSON sidecar.
Database¶
- FaxDocument model (23 columns) -- Status enum (
pending->processing->extracted->matched/review_needed->verified/error), AI extraction fields (documentType, urgency, extractedData JSON, confidence, model, cost), patient match fields (demographicId, confidence, method), review tracking. - FaxStatus enum -- 7 states:
pending,processing,extracted,matched,review_needed,verified,error - 3 indexes:
clinic_id,status,created_at. FK constraint toclinicstable.
Frontend¶
- Fax Intelligence page (
FaxIntelligence.tsx) -- Controls bar with polling toggle, upload button, seed/reset (demo). Detail panel with extraction results and OSCAR match card. Paginated history table with status badges and confidence bars. Auto-refresh every 5s when poller is running. - Sidebar navigation -- "Fax Intelligence" item with
FileSearchicon added to clinic portal nav.
Configuration¶
- 6 new environment variables:
ANTHROPIC_API_KEY,OPENAI_API_KEY,GOOGLE_AI_API_KEY,FAX_AI_PROVIDER,FAX_PROVIDER,FAX_POLL_INTERVAL_MS
Dependencies Added¶
@anthropic-ai/sdk-- Claude vision APIopenai-- GPT-4o-mini vision API@google/generative-ai-- Gemini 2.0 Flash APImulter/@types/multer-- File upload middlewarepdf-lib-- Synthetic fax PDF generation (dev tooling)- System:
poppler-utils(pdftoppmbinary for PDF-to-PNG conversion)
[4.0.1] - 2026-02-16¶
Added¶
- OSCAR SOAP API Reference -- Complete documentation for all 14 OSCAR SOAP web services at
/oscar/ws/, covering 80+ operations across DemographicService, ProviderService, ScheduleService, AllergyService, PrescriptionService, MeasurementService, DocumentService, PreventionService, BookingService, ProgramService, FacilityService, LabUploadService, LoginService, and SystemInfoService - Includes WS-Security authentication details, credential format, two-step auth flow, SOAP header examples
- Documents all transfer object field definitions (demographicTransfer, appointmentTransfer, drugTransfer with 55 fields, etc.)
- Non-bookable schedule codes reference table (14 codes: L, P, V, A, a, B, H, R, E, G, M, m, d, t)
- REST Bridge to SOAP operation mapping table (13 bridge methods)
- VitaraVox services-used subset (7 of 14 services actively consumed by OscarSoapAdapter)
- Cross-references to existing docs: Schedule Deep Dive, Adapter Implementations, SOAP Integration Evidence
- Router maxTokens 150->400 -- was causing GPT-4o silent truncation (tool-call JSON alone = 80-120 tokens)
- Circuit breaker timeout 10s->4s -- both SOAP and bridge phone search timeouts
- Router prompt rewritten -- removed rigid scripting, replaced with warm acknowledgment + get_clinic_info dynamic greeting
- request-start messages on all 14 tools (4 audible, 10 silent)
- firstMessage removed from Patient-ID EN/ZH squad members (was causing 16s silence)
- FILLER PHRASE RULES deleted from Booking + Modification EN/ZH prompts
- transferAssistant -> handoff_to_X in all 8 non-Router prompts (fixed to use actual handoff tool function names)
Changed¶
- Filler phrase strategy now tool-level
request-startinstead of LLM-generated filler phrases
[4.0.0] - 2026-02-15¶
Onboarding Redesign + Admin Provisioning Workflow¶
Complete restructure of the clinic onboarding flow and addition of admin-side clinic activation workflow.
Onboarding Flow Redesign (4 Steps -- was 5)¶
- New step order: Clinic Details -> EMR Connection -> Business Hours -> Validation
- EMR Connection (Step 2): EMR type selector cards (OSCAR, TELUS PS Suite, Accuro, Other) -- OSCAR fully supported, others "coming soon" with contact support CTA
- Business Hours (Step 3): Enhanced with explanatory guidance text about typical Mon-Fri 8AM-5PM hours
- Validation (Step 4): Replaces old "Go Live" step with 6 parallel integration checks:
- EMR Connection -- tests OSCAR connectivity
- Provider Roster -- verifies at least 1 provider with OSCAR ID
- Schedule Codes -- checks OSCAR config for template codes
- Appointment Types -- verifies configured appointment types
- Sample Availability -- retrieves actual schedule slots via adapter
- Sample Patient Search -- tests patient search via adapter
- EMR Connection and Provider Roster are REQUIRED; others are informational warnings
- All 6 checks run in parallel via
Promise.allSettled()for speed - Expandable data panels show raw JSON results per check
- "Complete Onboarding" creates admin notification for provisioning
Admin Provisioning Workflow¶
- Pending Activation Card: Admin dashboard shows amber card listing clinics with
onboardingProgress.completedAtset butstatus=pending - Provisioning Checklist: Admin
ClinicDetailpage shows checklist: - Phone number assigned (check
clinic.vapiPhone) - Squad linked (check
config.vapiSquadId) - "Activate Clinic" button (enabled when phone + squad assigned)
- Activation Endpoint:
PUT /api/admin/clinics/:id/activatevalidates phone + squad, setsstatus=active, creates notification for clinic manager
10-Point Pre-Launch Validation (was 8)¶
- 7 blocking checks: clinic info, business hours, providers, EMR connection, Vapi squad, privacy officer, credentials encrypted
- 3 informational (non-blocking): test call passed, schedule data flow, OSCAR config synced (within 7 days)
OSCAR Config Management¶
- New
OscarConfigsettings page (/clinic/settings/oscar-config) - Schedule template codes management (bookable/non-bookable)
- Appointment type mappings configuration
- Config pull from OSCAR with sync status tracking
oscarConfigPulledAtfield tracks freshness (7-day staleness warning)
Booking Engine: SOAP Adapter Enhancements¶
- OscarSoapAdapter now production path (OscarBridgeAdapter retained for dev/fallback)
OscarUniversalAdapterrenamed toOscarBridgeAdapter(clarifies purpose)- Enhanced schedule slot parsing with
normalizeTime()for JAXB Calendar objects - Non-bookable codes expanded (L, P, V + full OSCAR set documented)
New API Endpoints¶
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/clinic/onboarding/complete |
Complete onboarding, notify admins |
| POST | /api/clinic/onboarding/test-slots |
Test schedule slot retrieval |
| POST | /api/clinic/onboarding/test-patient-search |
Test patient search |
| GET | /api/clinic/oscar-config |
OSCAR config (codes, types, sync status) |
| POST | /api/clinic/oscar-config/pull |
Pull config from OSCAR instance |
| GET | /api/admin/clinics/pending-activation |
Clinics awaiting activation |
| GET | /api/admin/clinics/:id/provisioning |
Provisioning status |
| PUT | /api/admin/clinics/:id/activate |
Activate clinic |
New Client API Methods¶
testScheduleSlots(),testPatientSearch(),completeOnboarding()getOscarConfig(),pullOscarConfig()getProvisioningStatus(clinicId),activateClinic(clinicId),getPendingActivationClinics()
New Shared Types¶
ValidationCheckResult,SlotTestResult,PatientSearchResult
Files Summary¶
- 1 new file:
StepValidation.tsx - 1 deprecated:
StepGoLive.tsx(replaced by StepValidation) - ~12 modified files across client, server, and shared packages
- 48 files changed total, +5239 / -1005 lines
[3.2.7] - 2026-02-14¶
Documentation¶
OSCAR Data Architecture -- REST API & Known Bugs Update¶
- Updated OSCAR Data Architecture to v3.1
- REST API Endpoint Reference: Full OAuth 1.0a flow endpoints, Demographics CRUD (5 endpoints with mandatory/optional fields), Schedule/Appointment CRUD (9 endpoints)
- Known Bugs & Gotchas: 9 validated issues with workarounds -- secUserRole NPE, provider reference trap, DemographicConverter link bug, AppointmentConverter null return, scheduledate.hour naming, template name VARCHAR(20) limit, missing admissionProgramId crash, OAuth provider validation, endTime off-by-one
- Entity Creation Order: 9-step sequence showing required creation dependencies
- Scheduling Layer updates: Slot duration formula (
1440 / len(timecode)), 96-char position reference table,'W'(Same Week) code added - Cross-reference to new OSCAR Demo Data page
OSCAR Demo Data & Test Environment -- New Page¶
- New page: OSCAR Demo Data & Test Environment
- Design Principles: 6 rules for referential integrity in a no-FK database
- Provider Set: 4 doctors (100 Anderson, 101 Chen, 102 Patel, 10 Lee) with required secUserRole and program_provider records
- Schedule Templates: 16 templates (96-char) across 3 providers + 2 Public templates, fully decoded (FullDay, clinic, day-of-week variants)
- Demographic Set: 12 patients with diverse BC demographics, health card numbers, MRP assignments
- Appointment Set: 12 sample bookings across all providers and appointment types (Office Visit, Annual Physical, Consult, Prenatal, Mental Health, etc.)
- OAuth Clients: Production (VitaraPlatform, 1hr TTL) and test (vitaraPostman, 10hr TTL)
- Validation Checklist: 8 SQL checks for provider-role, patient-admission, demographic-provider, schedule-template, appointment reference integrity, secUserRole data quality, REST smoke tests
- Automation:
oscar-align-load.shscript documentation -- 4-phase lifecycle (pre-flight, alignment, load, verification), fully idempotent
[3.2.6] - 2026-02-14¶
Documentation¶
OSCAR EMR Data Architecture -- Complete Entity Reference¶
- New page: OSCAR Data Architecture in EMR Integrations section
- Identity Layer:
provider,secUserRole,ServiceClient(OAuth) -- full column definitions, mandatory fields, REST prerequisites - Patient Layer:
demographic(with DOB-as-3-strings quirk),admission(program_id=10034 hardcoded),program,demographicExt(EAV),demographiccust - Scheduling Layer:
scheduletemplatecode(slot alphabet),scheduletemplate(timecode patterns),scheduledate(template assignment via name JOIN) - Appointment Layer:
appointment(independent of schedule slots),appointmentType(free text, no FK), status codes (t/H/C/T/b/A/sc) - OAuth Layer:
ServiceClient->ServiceRequestToken->ServiceAccessToken-- full 5-step flow with token TTL and expiry rules - Cross-Entity Dependency Graph: Visual showing all provider_no references across 5 entities
- Documented critical traps: secUserRole NPE, provider reference NPE, no FK constraints, appointment/slot independence
[3.2.5] - 2026-02-13¶
Upgrade Plans¶
Booking Engine Upgrade -- Master Implementation Plan¶
- New documentation section: Upgrade Plans
- Published Booking Engine Upgrade Plan for stakeholder review
- Full current-state vs future-state ASCII architecture diagrams
- 6-phase migration safety strategy with rollback checkpoints at every stage
- Impact analysis: 2 files created, 5 files modified, 0 database migrations
- 7 milestones (M0-M6) with 80+ acceptance criteria
- Agent team orchestration: parallel M1+M2, sequential M3-M6
- Comprehensive testing strategy: SOAP adapter, BookingEngine, and regression test cases
- Risk registry with 7 identified risks and mitigations
- Status: PLANNING -- awaiting stakeholder approval before any code changes
[3.2.4] - 2026-02-13¶
Architecture Decision¶
ADR-004: Booking Product Architecture¶
- Decision: All booking intelligence lives in the VitaraVox platform layer. No custom code deployed on customer OSCAR instances.
- Created ADR-004: Booking Product Architecture documenting three-layer architecture
- Layer 1 (our servers): BookingEngine -- availability calculation, conflict detection, slot locking, double-booking prevention, bookinglimit enforcement
- Layer 2 (pluggable adapters): SOAP Adapter (universal production), REST Adapter (OSCAR 15+), Bridge Adapter (dev/test only)
- Layer 3 (customer's OSCAR): Connect via standard SOAP/OAuth APIs. Install nothing.
- Corrected Schedule Deep Dive Section 7 -- booking intelligence belongs in platform, NOT in bridge
- Bridge reclassified as dev/testing tool and reference implementation, not a portable production connector
- Migration path: Phase 1 Bridge Adapter -> Phase 2 SOAP Adapter -> Phase 3 first customer on SOAP
[3.2.3] - 2026-02-13¶
Documentation¶
OSCAR Schedule System Deep Dive¶
- New architecture decision page: OSCAR Schedule Deep Dive
- Documented core 4-table relationship chain (
scheduledate.hour->scheduletemplate.name->timecode->scheduletemplatecode) - Documented bookinglimit advisory-only enforcement (OSCAR never implemented strict limits)
- Critical finding: Appointments and schedule slots are completely independent (no FK between
appointmentandscheduledate) - Full API surface comparison: SOAP ScheduleWs vs OSCAR native REST vs our bridge -- identified gap in native REST (no schedule endpoints)
- Duplicate booking vulnerability analysis: OSCAR SOAP
addAppointmenthas zero conflict checking;BookingWsrace condition in check-then-book flow - Commercial competitive analysis: Cortico, Ocean, Veribook, Porton, Phelix, OSCAR Self-Book -- all subtract booked slots from availability; our bridge does not
- P0 required actions: subtract booked appointments from availability, pre-booking conflict check
[3.2.2] - 2026-02-13¶
Documentation¶
OSCAR Database ERD & Bridge Mapping¶
- Added full OSCAR database entity relationship diagram to OSCAR REST Bridge (Section 2)
- Documented all core tables:
provider,demographic,appointment,allergies,drugs,measurements,measurementsExt,measurementType - Added schedule subsystem ERD:
scheduledate->scheduletemplate->scheduletemplatecodeJOIN architecture - Added detailed SOAP-to-REST bridge mapping tables (Section 6) showing exact SOAP method calls for all endpoints
- Added bridge internal data flow diagram showing Routes -> Services -> SOAP Client / DB Service paths
- Documented notable table quirks (varchar birth dates, Aria engine, no FK constraints, etc.)
[3.2.1] - 2026-02-12¶
Security Hardening Sprint (Post-Review)¶
5 targeted fixes addressing the highest-priority findings from the architecture review.
Fix 1: Production Security Enforcement¶
- Set
NODE_ENV=production-- activates fail-fast secret validation via Zod - Generated and configured
ENCRYPTION_KEYfor AES-256-GCM credential encryption - HMAC-SHA256 webhook verification now mandatory (was skipped in dev mode)
Fix 2: Waitlist Database Persistence¶
addToWaitlisttool handler now writes to PostgreSQL via Prisma (WaitlistEntry.create)- Previously the Prisma call was commented out -- patients were told they were added but nothing persisted
Fix 3: PHI Log Redaction¶
- Added
redactPhi()helper that strips names, DOB, phone, email, health cards from all log output - Redacted 7 log sites in
vapi-webhook.tsthat were dumping full patient data - Caller phone logged as
[SET]/[NOT SET]instead of actual number - End-of-call-report logs only
callIdanddurationSeconds
Fix 4: OSCAR Route Authentication¶
- Moved 15
/api/oscar/*routes to a dedicated sub-router with explicitauthMiddleware GET /api/oscar/healthremains public (monitoring)- All other OSCAR proxy routes now require JWT authentication
Fix 5: Graceful Shutdown Handler¶
- Added SIGTERM/SIGINT handler that drains in-flight requests before exit
- 10-second forced shutdown timeout with
.unref()to prevent Node.js hang - Critical for
update_appointmentwhich does book-new + cancel-old (non-atomic)
Production Launch Backlog Documented¶
| ID | Issue | Priority |
|---|---|---|
| BL-01 | JWT token revocation | Medium |
| BL-02 | Redis-backed rate limiting | Medium |
| BL-03 | Multi-tenant OSCAR wiring | High |
| BL-08 | Webhook integration tests | High |
| BL-09 | Monitoring + alerting | High |
[3.2.0] - 2026-02-12¶
Fixed - Phone Number Linking & Human Handover (Theme 7)¶
Bug Fix¶
- transfer-destination-request webhook now returns the actual clinic phone number for call transfers, fixing human handover routing
Added¶
Vapi Phone Number Listing
- New GET /api/admin/vapi/phone-numbers endpoint -- lists all Vapi phone numbers (admin only)
- Server-side VapiService method to fetch phone numbers from Vapi API
Client API Methods
- New client API methods for Vapi phone management (getVapiPhoneNumbers, assignPhoneToClinic, unassignPhoneFromClinic)
Admin Phone Management Page (/admin/phones)
- Stat cards: total phone numbers, assigned, available, clinics without phone
- Clinic assignments table with assign/unassign actions
- Vapi phone numbers table showing all numbers with assignment status
- Assign modal for linking unassigned phone numbers to clinics
Database Backup Scripts
- scripts/backup-db.sh -- PostgreSQL backup script with retention
- scripts/install-cron.sh -- Cron job installer for automated daily backups
[3.1.0] - 2026-02-11¶
Added - Platform Maturity (5 Themes)¶
Complete platform hardening across compliance, reliability, onboarding, clinical control, and support -- transforming from prototype to production-grade multi-tenant SaaS.
Theme 2: Compliance (PIPEDA/PIPA)¶
Credential Encryption (AES-256-GCM)
- New lib/crypto.ts: encrypt(), decrypt(), isEncrypted() -- AES-256-GCM with random IV
- OSCAR credentials (oscarConsumerSecretEnc, oscarTokenSecretEnc) encrypted at rest
- ENCRYPTION_KEY (32-byte hex) required in production; dev warns on missing key
- API responses mask encrypted fields (never expose plaintext)
Audit Logging
- New middleware/audit.ts: Auto-captures POST/PUT/DELETE -> AuditLog table
- Redacts password, secret, key, token fields from stored details
- New services/audit.service.ts: Non-blocking writes, paginated admin queries
- New GET /api/admin/audit with date/action/user filters
Privacy & Retention
- Privacy officer fields: privacyOfficerName, privacyOfficerEmail, privacyOfficerPhone
- BAA/DPA tracking: baaVapiSigned, baaHostingSigned with timestamps
- Data retention: transcriptRetentionDays (default 90), callLogRetentionDays (default 365)
- New jobs/data-retention.ts + jobs/scheduler.ts: node-cron daily 3 AM purge
- Nulls transcripts after retention period, deletes call logs after longer period
Theme 3: Reliability & Production Standards¶
Security Hardening
- Helmet security headers (CSP, HSTS, X-Frame-Options, etc.)
- Rate limiting: 5/min auth, 300/min webhooks, 100/min API
- Env validation: Zod schema in config/env.ts, fail-fast on missing secrets in production
Observability
- Pino structured logging (lib/logger.ts) -- JSON in prod, pretty-print in dev
- pino-http request logger with x-request-id correlation
- Replaced ~30 console.log/error calls with structured logger
Resilience
- Circuit breaker (Opossum) wrapping all OSCAR Bridge calls
- Real health checks: DB ping + OSCAR Bridge /health + Vapi API check with latency
- PostgreSQL backup automation (scripts/backup-db.sh, daily 2 AM, 14 retained)
Validation
- 18 Zod schemas with .strict() enforcement in validation/schemas.ts
- validate() middleware factory for all POST/PUT endpoints
Theme 1: Onboarding¶
- New
services/onboarding.service.ts:getProgress(),updateStep(),validatePreLaunch(),goLive() - 8-point pre-launch validation
POST /api/admin/clinics-- Transaction creating Clinic + User + ClinicConfig + OnboardingProgress + 7 ClinicHours- 5-step onboarding wizard (
pages/clinic/Onboarding.tsx)
Theme 4: Clinical Control¶
- ClinicConfig fields:
customGreeting,customGreetingZh,transferPhoneNumber,defaultProviderId,preferredPharmacy*,appointmentTypeMappings PUT /api/clinic/clinical-settingsendpoint- Clinical Settings page
Theme 5: Support & Notifications¶
- New Prisma models:
SupportTicket,TicketMessage,Notification - 11 route endpoints (4 clinic, 4 admin, 3 notifications)
isInternalenforced server-sideNotificationBell.tsxcomponent with 30-second polling
Database Changes¶
| Migration | New Models | New ClinicConfig Fields |
|---|---|---|
| Audit log | AuditLog |
-- |
| Privacy/retention | -- | privacyOfficer*, transcriptRetentionDays, callLogRetentionDays, baaVapi*, baaHosting* |
| Onboarding | OnboardingProgress |
-- |
| Clinical control | -- | customGreeting*, transferPhoneNumber, defaultProviderId, preferredPharmacy*, appointmentTypeMappings |
| Support tickets | SupportTicket, TicketMessage |
-- |
| Notifications | Notification |
-- |
Total models: 8 -> 13
[3.0.0] - 2026-02-10¶
Added - Dual-Track Bilingual Voice Agent (v3.0)¶
9-Agent Dual-Track Squad Architecture¶
- New squad: 9 assistants organized as Router + 4 roles x 2 language tracks (EN/ZH)
- Squad ID:
13fdfd19-a2cd-4ca4-8e14-ad2275095e32 - Router (vitara-router-v3): Pure language gate -- detects EN/ZH from first utterance, routes to correct track
- Patient-ID (EN/ZH): Identifies caller by phone, detects intent, routes to role agent
- Booking (EN/ZH): Finds slots, books appointments with
create_appointment - Modification (EN/ZH): Consolidated reschedule + cancel + check (was 2 separate agents)
- Registration (EN/ZH): Collects 7 fields, registers new patients
- Confirmation agent eliminated --
log_call_metadataabsorbed into every role agent
Per-Language STT/TTS Configuration¶
- Router STT: AssemblyAI Universal (bilingual auto-detect)
- EN STT: Deepgram nova-2
en - ZH STT: Deepgram nova-2
zh - EN TTS: ElevenLabs eleven_multilingual_v2
- ZH TTS: Azure
zh-CN-XiaoxiaoNeural
Vapi GitOps (Config-as-Code)¶
- All 9 assistants, 14 tools, and squad YAML managed in
vapi-gitops/directory - Slug-based tool references
- Environment separation (dev/staging/prod)
Server-Side Changes¶
callMetadataCache: In-memory Map bridging tool-call and end-of-call-report webhooks- v3 parameter support (
demographicId,appointmentId,providerId,startTimeISO 8601) - Appointment type validation against
['B', '2', '3', 'P'] - Dual squad resolution (
vapi_squad_id_v3column)
[2.3.0] - 2026-02-09¶
Added - Production Voice Quality & Silent Transfers¶
- 6-agent squad (Router + Booking + Reschedule + Cancel + Registration + Confirmation)
- AssemblyAI Universal transcriber (replaces Deepgram multi — was forcing English on Mandarin)
- ElevenLabs
eleven_multilingual_v2TTS for all agents - Silent transfers (patient doesn't hear handoff between agents)
- Inline confirmation flow (Confirmation agent handles call summary)
- Slot collision checking before booking
- Non-numeric
providerIdhandling ("any" / "任何" → search all providers)
[2.2.0] - 2026-02-06¶
Added - Voice Agent Server Consolidation & Multi-Clinic Hardening¶
- IEmrAdapter pattern (ADR-003) -- TypeScript rewrite
- Caller phone auto-detection (server-side extraction from
call.customer.number) find_earliest_appointment-- smart slot finder with 1-slot return, past-date clamping, provider name resolution- 6-assistant squad architecture
- Multi-auth webhook middleware (HMAC-SHA256 + API key + Bearer)
- Robust appointment booking with dual parameter support
[2.1.0] - 2026-02-03¶
Added - Admin Vapi Management & Call Log Integration¶
- 1 Assistant to 1 Clinic linking in admin dashboard
- Vapi config fields in
clinic_config(vapi_assistant_id,vapi_squad_id,vapi_webhook_secret) - Admin API endpoints for Vapi management
- Webhook call log saving on
end-of-call-report - OSCAR Bridge integration fixes
[2.0.0] - 2026-02-02¶
Changed - Voice Agent Squad Architecture v2.0¶
- 5-agent squad architecture (Router, Patient ID, Registration, Booking, Modification)
- 6 new tool handlers
- Language handling (English + Mandarin with mid-conversation switching)
- Emergency/frustration detection
[1.5.2] - 2026-01-21¶
Added - Marketing Website Documentation¶
- Marketing website documentation and code review
- Identified 20 issues (2 critical, 4 high, 6 medium, 8 low)
[1.5.1] - 2026-01-16¶
Fixed - Admin Dashboard Data Display¶
- API response pagination fix
- Frontend field name mapping to PostgreSQL column names
- JSONB safeJsonParse helper
- Nginx authorization header forwarding
[1.5.0] - 2026-01-14¶
Added - Admin System with Per-Clinic EMR Control¶
- Multi-tenant admin dashboard (React)
- Two user roles: Vitara Admin and Clinic Manager
- PassportJS + JWT authentication
- Per-clinic EMR live status
- 125 new unit tests
[1.4.0] - 2026-01-14¶
Added - EMR Abstraction Layer (Epic 1.2)¶
- IEmrAdapter interface + OscarUniversalAdapter
- EmrAdapterFactory with 5-minute TTL cache
- Feature flags system for controlled rollout
- 224 total tests (86% statement coverage)
[1.3.2] - 2026-01-14¶
Added - OSCAR REST Bridge v1.3.0¶
- Admission records on patient registration
- Configuration centralization (environment variables)
- Health check improvements
- Graceful shutdown
[1.3.1] - 2026-01-13¶
Added - OSCAR REST Bridge v1.2.0 (DB-Based Availability)¶
- Provider availability endpoint (direct database query)
- Schedule pattern parsing (48-char/96-char templates)
- Voice agent integration
[1.3.0] - 2026-01-13¶
Added - Vapi Production Integration¶
- Bearer token authentication with Vapi credentialId
- Phone number normalization
- Name spelling confirmation
- OSCAR phone search
- Deepgram Nova-3 transcriber
[1.2.0] - 2026-01-13¶
Added - Infrastructure Hardening¶
- Input validation (Joi, 12 schemas)
- Structured logging (Pino with PHI redaction)
- Circuit breaker (Opossum)
- Health checks (Kubernetes-ready)
- Error standardization
- Rate limiting
[1.1.0] - 2026-01-12¶
Added¶
- BC Health registration requirements (PHN, BC Services Card)
get_clinic_infoandadd_to_waitlistendpoints- Comprehensive compliance documentation (PIPEDA, PHIPA, SOC2)
[1.0.0] - 2025-12-29¶
Added¶
- Multi-clinic support with phone number routing
- PostgreSQL database for configuration
- New patient registration flow
- Waitlist management
- Mandarin Chinese language support
- Admin dashboard (basic)
- Docker Compose deployment
- NGINX reverse proxy with SSL/TLS
[0.5.0] - 2025-12-19¶
Added¶
- Initial release
- Single-clinic appointment booking
- Patient lookup by phone and name
- OSCAR EMR integration (OAuth 1.0a)
- English language support
- Node.js Express webhook handler
- PM2 process management
Future — Planned¶
Planned Features¶
- FAQ Knowledge Base (v3.1 — common clinic questions)
- Fax Intelligence v2 (SRFax production provider)
- French Canadian language track
- Cantonese language track
- Appointment reminders (outbound)
Planned Technical¶
- Structured Logging Tier 1-3
- v3.0 E5 Testing (76 test cases)
- Family Doctor Routing (v3.2)
- Clinic timezone from DB (replace hardcoded
America/Vancouver) - Pipecat POC Phase B ($6K budget)
Version Numbering¶
Given a version number MAJOR.MINOR.PATCH:
| Component | Meaning |
|---|---|
| MAJOR | Incompatible API changes |
| MINOR | Backwards-compatible functionality |
| PATCH | Backwards-compatible bug fixes |
Release Schedule¶
| Version | Target | Status |
|---|---|---|
| v0.5.0 | Dec 19, 2025 | Released |
| v1.0.0 | Dec 29, 2025 | Released |
| v1.1.0 | Jan 12, 2026 | Released |
| v1.2.0 | Jan 13, 2026 | Released |
| v1.3.0 | Jan 13, 2026 | Released |
| v1.3.1 | Jan 13, 2026 | Released |
| v1.3.2 | Jan 14, 2026 | Released |
| v1.4.0 | Jan 14, 2026 | Released |
| v1.5.0 | Jan 14, 2026 | Released |
| v1.5.1 | Jan 16, 2026 | Released |
| v1.5.2 | Jan 21, 2026 | Released |
| v2.0.0 | Feb 02, 2026 | Released |
| v2.1.0 | Feb 03, 2026 | Released |
| v2.2.0 | Feb 06, 2026 | Released |
| v2.3.0 | Feb 09, 2026 | Released (production hardening) |
| v3.0.0 | Feb 10, 2026 | Released (deployed, testing) |
| v3.1.0 | Feb 11, 2026 | Released (5 themes) |
| v3.2.0 | Feb 12, 2026 | Released (phone linking) |
| v3.2.1 | Feb 12, 2026 | Released (security hardening) |
| v3.2.2 | Feb 13, 2026 | Released (OSCAR ERD) |
| v3.2.3 | Feb 13, 2026 | Released (Schedule Deep Dive) |
| v3.2.4 | Feb 13, 2026 | Released (ADR-004) |
| v3.2.5 | Feb 13, 2026 | Released (Booking Engine Plan) |
| v3.2.6 | Feb 14, 2026 | Released (OSCAR entity reference) |
| v3.2.7 | Feb 14, 2026 | Released (REST API, demo data) |
| v4.0.0 | Feb 15, 2026 | Released (onboarding redesign) |
| v4.0.1 | Feb 16, 2026 | Released (P0/P1/P2 fixes) |
| v4.1.0 | Feb 21, 2026 | Released (Fax Intelligence) |
| v4.1.1 | Feb 25, 2026 | Released (Fax pipeline hardening) |
| v4.2.0 | Feb 23, 2026 | Released (Pipecat migration analysis) |
| v4.2.1 | Mar 07, 2026 | Released (provider config, REST hardening, P1 fixes) |
| v4.3.0 | Mar 09, 2026 | Released (SMS booking confirmation, OSCAR REST, provider config) |