Skip to content

Infrastructure Topology

This page documents the full infrastructure layout for the VitaraVox platform, including network topology, service placement, request flows, and operational commands.


Network Topology

                                    INTERNET
                                       |
                     +-----------------+-----------------+
                     |                 |                 |
                     v                 v                 v
              +------------+   +-------------+   +---------------+
              | Cloudflare |   | Let's       |   | Telnyx        |
              | WAF        |   | Encrypt     |   | (Phone SIP)   |
              | (Kai only) |   | (OCI certs) |   +-------+-------+
              +-----+------+   +------+------+           |
                    |                  |                  v
                    v                  |            +-----------+
          +------------------+        |            |  Vapi.ai  |
          | fbh.kai-oscar.com|        |            |  (Voice   |
          | Kai OSCAR Pro    |        |            |   AI)     |
          | (WELL Health)    |        |            +-----+-----+
          | OAuth 1.0a REST  |        |                  |
          +------------------+        |                  | HTTPS POST
                                      |                  | (webhooks)
                    +--------+--------+--------+         |
                    |        |        |        |         |
                    v        v        v        v         v
               +------------------------------------------------+
               |        OCI ARM Instance (Toronto Region)        |
               |        Ubuntu on ARM64                          |
               |                                                 |
               |  +------------------------------------------+   |
               |  |  nginx (host-level)                      |   |
               |  |  :80 (HTTP -> HTTPS redirect)            |   |
               |  |  :443 (HTTPS, Let's Encrypt)             |   |
               |  |                                          |   |
               |  |  Virtual Hosts:                          |   |
               |  |  +------------------------------------+  |   |
               |  |  | dev.vitaravox.ca                    |  |   |
               |  |  |   static -> client/dist/            |  |   |
               |  |  |   /api/* -> localhost:3002           |  |   |
               |  |  +------------------------------------+  |   |
               |  |  | vitdocs.vitaravox.ca                |  |   |
               |  |  |   static -> vitaravox-docs/site/    |  |   |
               |  |  +------------------------------------+  |   |
               |  |  | api-dev.vitaravox.ca                |  |   |
               |  |  |   proxy -> localhost:3002            |  |   |
               |  |  +------------------------------------+  |   |
               |  +------------------------------------------+   |
               |                       |                         |
               |                       v                         |
               |  +------------------------------------------+   |
               |  |  PM2: vitara-admin-api (:3002)           |   |
               |  |  Express 4 + Prisma ORM + Pino           |   |
               |  |  Zod validation + opossum (breaker)      |   |
               |  |  node-soap (OSCAR SOAP client)           |   |
               |  +------------------------------------------+   |
               |                       |                         |
               |         +-------------+-------------+           |
               |         |                           |           |
               |         v                           v           |
               |  +----------------+    +-----------------------+|
               |  | SQLite (local) |    | /opt/zatuka-stack/    ||
               |  | (Prisma DB)    |    | Docker Compose        ||
               |  +----------------+    | (see Zatuka section)  ||
               |                        +-----------------------+|
               +------------------------------------------------+
                              |
                              | SOAP / REST
                              v
               +--------------------------------+
               |  AWS EC2 (ca-central-1)        |
               |  t3a.medium @ 15.222.50.48     |
               |  Terraform-managed             |
               |                                |
               |  +---------------------------+ |
               |  | Docker Compose            | |
               |  |                           | |
               |  | +--------+ +-----------+ | |
               |  | |Tomcat 9| |MariaDB    | | |
               |  | |OSCAR   | |10.5       | | |
               |  | |:8080   | |:3306      | | |
               |  | +--------+ +-----------+ | |
               |  +---------------------------+ |
               +--------------------------------+

Voice Call Request Flow

This diagram traces a patient phone call from the PSTN through to the EMR.

  Patient dials +1 236-305-7446
          |
          v
  +---------------+
  |  PSTN / SIP   |
  +-------+-------+
          |
          v
  +---------------+
  |    Telnyx     |     Phone number provider
  |  (SIP trunk)  |     Routes call to Vapi
  +-------+-------+
          |
          v
  +-------+-------+
  |    Vapi.ai    |     Voice AI platform
  |               |
  |  +---------+  |     1. Router agent answers
  |  | Router  |  |     2. Detects language (EN/ZH)
  |  +----+----+  |     3. Identifies intent
  |       |       |
  |  +----v----+  |     4. Transfers to role agent
  |  | Booking |  |        (Booking, Modification,
  |  | Modif.  |  |         Registration)
  |  | Regist. |  |
  |  +----+----+  |     5. Agent calls tools via
  |       |       |        HTTP POST webhooks
  +-------+-------+
          |
          | HTTPS POST (webhook)
          v
  +-------+-------+
  | api-dev       |     api-dev.vitaravox.ca
  | .vitaravox.ca |
  +-------+-------+
          |
          | SSL termination (Let's Encrypt)
          v
  +-------+-------+
  |    nginx      |     Reverse proxy
  |    :443       |     proxy_pass to :3002
  +-------+-------+
          |
          v
  +-------+-------+
  | Express API   |     vitara-admin-api (PM2)
  | :3002         |     /api/vapi webhook handler
  |               |
  | Zod validate  |     Validates Vapi payload
  | Route handler |     Dispatches to EMR adapter
  +-------+-------+
          |
          |  REST (OAuth 1.0a)         SOAP (WS-Security)
          +----------------+     +----------------+
          |                |     |                |
          v                v     v                v
  +---------------+    +---------------------------+
  | Kai OSCAR Pro |    | Dev OSCAR (EC2)           |
  | fbh.kai-      |    | 15.222.50.48:8080         |
  | oscar.com     |    |                           |
  | (production)  |    | (development/testing)     |
  +---------------+    +---------------------------+

Protocol Selection

The EMR adapter automatically selects the protocol based on the clinic's preferRest flag:

  • Kai-hosted clinics: OAuth 1.0a REST (Cloudflare WAF blocks SOAP text/xml POST)
  • Self-hosted clinics: SOAP via WS-Security (universal, ships with every OSCAR since v12)

Admin Dashboard Request Flow

  Browser: https://dev.vitaravox.ca
          |
          v
  +-------+-------+
  |    nginx      |     SSL termination (Let's Encrypt)
  |    :443       |     Virtual host: dev.vitaravox.ca
  +-------+-------+
          |
          +------ Static files? ------+
          |                           |
          | YES                       | NO (/api/*)
          v                           v
  +---------------+          +---------------+
  |  client/dist/ |          |  proxy_pass   |
  |               |          |  localhost     |
  |  React 19.2   |          |  :3002        |
  |  Vite build   |          +-------+-------+
  |  Tailwind 4   |                  |
  |               |                  v
  |  SPA routing: |          +---------------+
  |  try_files    |          | Express API   |
  |  $uri $uri/   |          | :3002         |
  |  /index.html  |          |               |
  |               |          | +----------+  |
  |  Asset cache: |          | | Prisma   |  |
  |  1 year       |          | | (SQLite) |  |
  +---------------+          | +----------+  |
                             |       |       |
                             | +-----v----+  |
                             | | OSCAR    |  |
                             | | Adapter  |  |
                             | +----------+  |
                             +---------------+

SPA Routing

nginx is configured with try_files $uri $uri/ /index.html so that all client-side routes (React Router) resolve to the index page. The Vite build output in client/dist/ includes hashed filenames with a 1-year cache header for optimal performance.


Zatuka Stack Layout

  /opt/zatuka-stack/  (Docker Compose)
  +---------------------------------------------------------+
  |                                                         |
  |  +-------------+  +-------------+  +----------------+   |
  |  | Mattermost  |  |   Outline   |  |    Vikunja     |   |
  |  | chat.zatuka |  | docs.zatuka |  | projects.zatuka|   |
  |  | .ai         |  | .ai         |  | .ai            |   |
  |  +------+------+  +------+------+  +-------+--------+   |
  |         |                |                  |            |
  |  +------+------+  +-----+-------+  +-------+--------+   |
  |  |     n8n     |  | Uptime Kuma |  | zatuka-nginx   |   |
  |  | n8n.zatuka  |  | status.     |  | (CURRENTLY     |   |
  |  | .ai         |  | zatuka.ai   |  |  DOWN - port   |   |
  |  +------+------+  +------+------+  |  80 conflict)  |   |
  |         |                |          +-------+--------+   |
  |         +--------+-------+------------------+            |
  |                  |                                       |
  |         +--------v--------+                              |
  |         |  Shared Infra   |                              |
  |         |                 |                              |
  |         | +-------------+ |                              |
  |         | | PostgreSQL  | |                              |
  |         | | 16          | |                              |
  |         | | :5432       | |                              |
  |         | +-------------+ |                              |
  |         |                 |                              |
  |         | +-------------+ |                              |
  |         | | Redis       | |                              |
  |         | | :6379       | |                              |
  |         | +-------------+ |                              |
  |         +-----------------+                              |
  +---------------------------------------------------------+

Port Conflict

The zatuka-nginx container is currently DOWN due to a port 80 conflict with the host-level nginx. The Zatuka services still function via their individual container ports, but external routing through zatuka-nginx is unavailable. The documentation site (vitdocs.vitaravox.ca) is served directly by host-level nginx and is unaffected.


SSL / TLS Termination Points

                           INTERNET
                              |
            +-----------------+-----------------+
            |                 |                 |
            v                 v                 v
   +----------------+  +------------+   +-------------+
   | Let's Encrypt  |  | Cloudflare |   | Vapi.ai     |
   | (OCI nginx)    |  | (Kai only) |   | (managed)   |
   +--------+-------+  +-----+------+   +------+------+
            |                 |                 |
   TLS terminated at:   TLS terminated    TLS terminated
   nginx :443            at CF edge        at Vapi edge
            |                 |                 |
            v                 v                 v
   +----------------+  +------------+   +-------------+
   | localhost:3002  |  | Kai OSCAR  |   | Webhook to  |
   | (plaintext     |  | (re-encrypted   | api-dev     |
   |  internal)     |  |  by CF)    |   | .vitaravox  |
   +----------------+  +------------+   | .ca :443    |
                                        +-------------+

   Legend:
   ~~~~~~~ = TLS encrypted
   ------- = plaintext (internal only)
Endpoint Certificate Issuer Termination
dev.vitaravox.ca Auto-renewed Let's Encrypt OCI nginx
vitdocs.vitaravox.ca Auto-renewed Let's Encrypt OCI nginx
api-dev.vitaravox.ca Auto-renewed Let's Encrypt OCI nginx
fbh.kai-oscar.com Managed Cloudflare CF edge
15.222.50.48:8080 None N/A No TLS (dev only)

Dev OSCAR has no TLS

The development OSCAR instance on AWS EC2 (15.222.50.48:8080) does not use TLS. It is intended for development and testing only. Production EMR traffic uses the Kai OSCAR Pro endpoint with Cloudflare TLS.


DNS Routing

  DNS Records (managed externally)
  +--------------------------------------------------+
  |                                                   |
  |  dev.vitaravox.ca ---------> OCI Public IP        |
  |                               (Toronto ARM)      |
  |                                                   |
  |  vitdocs.vitaravox.ca -----> OCI Public IP        |
  |                               (Toronto ARM)      |
  |                                                   |
  |  api-dev.vitaravox.ca -----> OCI Public IP        |
  |                               (Toronto ARM)      |
  |                                                   |
  |  chat.zatuka.ai ------------> OCI Public IP       |
  |  docs.zatuka.ai ------------> OCI Public IP       |
  |  projects.zatuka.ai --------> OCI Public IP       |
  |  n8n.zatuka.ai --------------> OCI Public IP      |
  |  status.zatuka.ai -----------> OCI Public IP      |
  |                                                   |
  |  fbh.kai-oscar.com ---------> Cloudflare proxy    |
  |                               (WELL Health /      |
  |                                Kai managed)       |
  +--------------------------------------------------+

  All *.vitaravox.ca and *.zatuka.ai domains resolve to the
  single OCI ARM instance. nginx virtual hosts differentiate
  traffic by hostname.

Port Matrix

Port Protocol Service Host Exposure
80 TCP nginx (HTTP redirect) OCI ARM Public
443 TCP nginx (HTTPS) OCI ARM Public
3002 TCP vitara-admin-api (Express/PM2) OCI ARM localhost only
5173 TCP Vite dev server OCI ARM Dev only, not production
5432 TCP PostgreSQL 16 (Zatuka) OCI ARM Docker internal
6379 TCP Redis (Zatuka) OCI ARM Docker internal
8080 TCP OSCAR Tomcat AWS EC2 Public (dev only)
3306 TCP MariaDB 10.5 AWS EC2 Docker internal

Security Note

Port 3002 (Express API) is not exposed publicly. All external traffic reaches it through nginx reverse proxy on ports 80/443. The Zatuka database ports (5432, 6379) are internal to the Docker network. MariaDB on the dev OSCAR instance is also Docker-internal only.


Deployment Commands

Express API Server

# Build TypeScript and restart PM2 process
cd /home/ubuntu/vitara-platform/admin-dashboard/server
npx tsc
pm2 restart vitara-admin-api

# View logs
pm2 logs vitara-admin-api --lines 100

# Monitor process
pm2 monit

# Check status
pm2 status

Admin Dashboard Client

# Build the React client
cd /home/ubuntu/vitara-platform/admin-dashboard/client
npm run build

# Output goes to client/dist/, served by nginx automatically
# No restart needed — nginx serves static files directly

Documentation Site

# Build and deploy docs
source /tmp/mkdocs-env/bin/activate
cd /home/ubuntu/vitaravox-docs
mkdocs build --site-dir /tmp/vitdocs-site
cp -r /tmp/vitdocs-site/* /home/ubuntu/vitaravox-docs/site/
sudo nginx -s reload

Vapi GitOps (Voice Agent Config)

# Push voice agent configuration to Vapi
cd /home/ubuntu/vitara-platform/vapi-gitops
npm run push:dev

nginx Management

# Test configuration
sudo nginx -t

# Reload (graceful, no downtime)
sudo nginx -s reload

# View access logs
sudo tail -f /var/log/nginx/access.log

# View error logs
sudo tail -f /var/log/nginx/error.log

# Check virtual host configs
ls /etc/nginx/sites-enabled/

PM2 Process Management

# List all processes
pm2 list

# Restart with zero-downtime reload
pm2 reload vitara-admin-api

# Save process list (survives reboot)
pm2 save

# Startup script (run once)
pm2 startup

# View detailed process info
pm2 show vitara-admin-api

External Service Dependencies

  vitara-admin-api (:3002)
          |
          +-------> Vapi.ai (Voice AI)
          |            Squads, Assistants, Tool webhooks
          |            v2.3.0 Squad: 775db28c (prod)
          |            v3.0 Squad:   13fdfd19 (deployed)
          |
          +-------> OpenAI
          |            GPT-4o (all agents, both EN and ZH)
          |
          +-------> ElevenLabs
          |            TTS: eleven_multilingual_v2
          |            English voice synthesis
          |
          +-------> Azure Cognitive Services
          |            TTS: zh-CN-XiaoxiaoNeural
          |            Mandarin voice synthesis
          |
          +-------> Deepgram
          |            STT: Nova-2
          |            Language-specific (en, zh)
          |
          +-------> AssemblyAI
          |            STT: Universal Multilingual
          |            Used by Router for language detection
          |
          +-------> Telnyx
          |            Phone number provisioning
          |            SIP trunking to Vapi
          |
          +-------> Kai OSCAR Pro (production EMR)
          |            OAuth 1.0a REST
          |            fbh.kai-oscar.com
          |
          +-------> Dev OSCAR (development EMR)
                     SOAP (WS-Security) + REST
                     15.222.50.48:8080

Full System Context Diagram

+===========================================================================+
|                              INTERNET                                      |
+===========================================================================+
       |              |              |              |              |
       v              v              v              v              v
  +--------+    +---------+    +----------+   +---------+    +---------+
  | Patient |   | Admin   |   | Docs     |   | Vapi    |   | Kai     |
  | Phone   |   | Browser |   | Browser  |   | .ai     |   | OSCAR   |
  +----+----+   +----+----+   +----+-----+   +----+----+   +----+----+
       |              |              |              |              ^
       v              |              |              |              |
  +--------+         |              |              |         OAuth 1.0a
  | Telnyx |         |              |              |         REST
  +----+---+         |              |              |              |
       |              |              |              |              |
       v              |              |              |              |
  +--------+         |              |              |              |
  | Vapi   |         |              |              |              |
  | Squad  |---------+--------------+--------------+              |
  +----+---+         |              |                             |
       |              |              |                             |
       | webhook      |              |                             |
       v              v              v                             |
  +===================================================================+
  |  OCI ARM Instance — Toronto Region                                 |
  |                                                                    |
  |  +-------------------------------------------------------------+  |
  |  |  nginx (:80/:443)  —  Let's Encrypt SSL                     |  |
  |  |                                                              |  |
  |  |  api-dev.      dev.           vitdocs.                       |  |
  |  |  vitaravox.ca  vitaravox.ca   vitaravox.ca                   |  |
  |  |       |              |              |                        |  |
  |  |  proxy_pass     +----+----+    static files                  |  |
  |  |       |         |         |         |                        |  |
  |  |       |    static     proxy     +--------+                   |  |
  |  |       |    files      /api/*    | site/  |                   |  |
  |  |       |    dist/        |       +--------+                   |  |
  |  |       |                 |                                    |  |
  |  +-------+-----------------+------------------------------------+  |
  |          |                 |                                       |
  |          +--------+--------+                                       |
  |                   |                                                |
  |          +--------v--------+                                       |
  |          | PM2: vitara-    |                                       |
  |          | admin-api       |--------------------------------------+-->
  |          | Express :3002   |        (to Kai OSCAR via HTTPS)
  |          |                 |
  |          | Prisma (SQLite) |
  |          +---------+-------+
  |                    |
  |                    | SOAP (WS-Security)
  |                    v
  |  +-----------------+----+            +-------------------------+
  |  | /opt/zatuka-stack/   |            |  AWS EC2 ca-central-1   |
  |  |                      |            |  15.222.50.48           |
  |  | Mattermost  Outline  |            |                         |
  |  | Vikunja     n8n      |            |  OSCAR (Docker)         |
  |  | Uptime Kuma          |            |  Tomcat :8080           |
  |  | PostgreSQL 16        |            |  MariaDB :3306          |
  |  | Redis                |            |                         |
  |  +----------------------+            +-------------------------+
  +====================================================================+

Architecture Summary

The entire VitaraVox platform runs on two compute instances plus managed external services. The OCI ARM instance in Toronto handles all web traffic, the Express API, documentation, and the Zatuka collaboration stack. The AWS EC2 instance in Montreal (ca-central-1) runs a development OSCAR EMR. Production EMR connectivity goes to Kai OSCAR Pro via OAuth 1.0a REST through Cloudflare.