Topologija sustava
Jedna aplikacijska usluga na Cloud Runu — Node.js modularni monolit — poslužuje web-aplikaciju i API, uz Cloud SQL PostgreSQL 16, Cloud Storage i Cloud KMS. Posao koji traži drugačiji hardver ili strogu granicu izolacije izvodi se u malom broju satelitskih usluga: generator dokumenata, predobrada snimki i GPU servisi za inferenciju. Sve radi u odobrenim EU regijama; nema posrednika poruka, nego asinkroni rad nose Postgres outbox tablice koje se prazne po rasporedu.
Tehnička specifikacija vodi se na engleskom jeziku; naslovi i sažeci poglavlja prevedeni su na hrvatski.
System context (C4 level 1)
- Clinicians & staffweb · iOS · Android
- Patientsaftercare links · Patient Mode
- Investors & auditorsData Room
- Research readersannotation app
- Faurenis platformGoogle Cloud · EU
- Vertex AI (EU)Gemini models
- Speech providers (EU)Soniox · Google STT · TTS
- Open literaturePubMed · Europe PMC · …
- Practice systemsPMS · FHIR · Stripe
Connections (8)
- Clinicians & staff → Faurenis platform
- Patients → Faurenis platform
- Investors & auditors → Faurenis platform
- Research readers → Faurenis platform
- Faurenis platform → Vertex AI (EU)
- Faurenis platform → Speech providers (EU)
- Faurenis platform → Open literature · de-identified
- Faurenis platform ⇢ Practice systems
Containers (C4 level 2)
- Load balancer + Cloud ArmorWAF · rate limits
- Cloud SchedulerOIDC-signed cron calls
- Native shellsCapacitor 8
- Application serviceExpress API · SPA · WebSockets · workers
- Document rendererChromium → PDF/A
- Imaging pre-processorDICOM decode · derivatives
- Clinical LLM workervLLM · embeddings · NLI (GPU)
- Imaging inferencesigned model releases (GPU)
- Cloud SQL PostgreSQL 16clinical plane · RLS
- Research databasephysically separate
- Cloud Storageimaging · renditions · models
- Cloud KMS + Secret Managerper-clinic keys · signing
Connections (10)
- Load balancer + Cloud Armor → Application service
- Cloud Scheduler ⇢ Application service
- Application service → Document renderer
- Application service ⇢ Imaging pre-processor
- Application service → Clinical LLM worker
- Application service ⇢ Imaging inference
- Application service → Cloud SQL PostgreSQL 16
- Application service → Cloud KMS + Secret Manager
- Imaging pre-processor → Cloud Storage
- Clinical LLM worker → Cloud Storage · read-only models
Container inventory
- Application service
- Responsibility
- Every API route, the SPA, the four WebSocket endpoints, cron handlers and in-process workers
- Isolation
- Clinic scope per transaction; blue-green revisions
- Status
- Production
- Document renderer
- Responsibility
- Renders clinical documents to archival PDF/A-2b
- Isolation
- IAM-only invocation, no database access
- Status
- Production
- Imaging pre-processor
- Responsibility
- Decodes and validates DICOM, writes viewer derivatives to storage
- Isolation
- Internal ingress, own service account
- Status
- Production
- Clinical LLM worker
- Responsibility
- Self-hosted open-weight models, embeddings and entailment on an NVIDIA L4 GPU
- Isolation
- Internal ingress; refuses to start if database credentials are present; read-only model mount; no egress
- Status
- Rolling out
- Imaging inference
- Responsibility
- Runs signed imaging model releases
- Isolation
- Internal ingress; accepts only verified release packages
- Status
- Rolling out
- Research annotation app
- Responsibility
- Blinded imaging annotation for model development
- Isolation
- Separate origin, separate identity provider, separate database
- Status
- Rolling out
| Container | Responsibility | Isolation | Status |
|---|---|---|---|
| Application service | Every API route, the SPA, the four WebSocket endpoints, cron handlers and in-process workers | Clinic scope per transaction; blue-green revisions | Production |
| Document renderer | Renders clinical documents to archival PDF/A-2b | IAM-only invocation, no database access | Production |
| Imaging pre-processor | Decodes and validates DICOM, writes viewer derivatives to storage | Internal ingress, own service account | Production |
| Clinical LLM worker | Self-hosted open-weight models, embeddings and entailment on an NVIDIA L4 GPU | Internal ingress; refuses to start if database credentials are present; read-only model mount; no egress | Rolling out |
| Imaging inference | Runs signed imaging model releases | Internal ingress; accepts only verified release packages | Rolling out |
| Research annotation app | Blinded imaging annotation for model development | Separate origin, separate identity provider, separate database | Rolling out |
Every container here is Node.js except where models execute: the document renderer drives headless Chromium, and the clinical LLM and imaging workers are Node gatekeepers in front of vLLM and text-embeddings-inference on the GPU. Only the application service holds database credentials. Today it serves HTTP, server-sent events, the WebSocket voice paths and the scheduled jobs from one deployment; splitting those into separate deployments of the same image is a proposed next step.
Regions and data residency
The approved-region list in server/config/approvedEuRegions.ts names nine EU regions and excludes London and every non-EU multi-region. Gemini 3 models are served only from Vertex AI’s EU jurisdictional endpoint, which is approved explicitly. At boot, production validates its KMS location, residency region and enforcement flag and exits if any is missing or wrong — a misconfigured revision never takes traffic.
- Application service and satellites
- Region
- europe-west1 (Belgium)
- Cloud SQL
- Region
- europe-west3 (Frankfurt)
- GPU inference workers
- Region
- EU regions with L4 capacity, on the approved list
- Vertex AI models
- Region
- EU jurisdictional endpoint
- Speech recognition
- Region
- Provider EU endpoints
| Component | Region |
|---|---|
| Application service and satellites | europe-west1 (Belgium) |
| Cloud SQL | europe-west3 (Frankfurt) |
| GPU inference workers | EU regions with L4 capacity, on the approved list |
| Vertex AI models | EU jurisdictional endpoint |
| Speech recognition | Provider EU endpoints |
Asynchronous work without a broker
There is no Pub/Sub, task queue or Redis. Every asynchronous effect is written to a Postgres outbox in the same transaction as the change that caused it, then drained by an OIDC-authenticated cron endpoint invoked by Cloud Scheduler. Exactly-once-enough delivery comes from idempotency keys and SKIP LOCKED leases rather than from broker semantics, and an outbox row can never describe a write that rolled back.
- Audit outbox
- Carries
- Audit events whose chain write must not block the request
- AI decision outbox
- Carries
- Per-call AI decision records, buffered on disk and drained at boot
- AI provenance outbox
- Carries
- Links from artifacts to the AI decisions that produced them, with dead letters and reconciliation
- Imaging outbox
- Carries
- Ingestion, derivative and inference jobs
- Integration inbox / outbox
- Carries
- Practice-management sync in both directions, with a dead-letter queue
- Clinical document bundle queue
- Carries
- Document generation for newly reviewed sources
| Outbox / queue | Carries |
|---|---|
| Audit outbox | Audit events whose chain write must not block the request |
| AI decision outbox | Per-call AI decision records, buffered on disk and drained at boot |
| AI provenance outbox | Links from artifacts to the AI decisions that produced them, with dead letters and reconciliation |
| Imaging outbox | Ingestion, derivative and inference jobs |
| Integration inbox / outbox | Practice-management sync in both directions, with a dead-letter queue |
| Clinical document bundle queue | Document generation for newly reviewed sources |
Around forty scheduled endpoints cover reminders, appointment lifecycle, KPI snapshots, anomaly scans, backups, audit-chain verification, usage settlement, push reconciliation and purges.
Real-time channels
- General transcription (WebSocket)
- Purpose
- Streaming speech recognition for Scribe, dictation and commands
- Perio transcription (WebSocket)
- Purpose
- Low-latency recognition tuned for probing grammar
- Live voice (WebSocket)
- Purpose
- Speech-to-speech sessions bridged to Vertex AI
- Voice synthesis (WebSocket)
- Purpose
- Streaming text-to-speech
- Server-sent events (8)
- Purpose
- Copilot answers, appointment board changes, job progress
| Channel | Purpose |
|---|---|
| General transcription (WebSocket) | Streaming speech recognition for Scribe, dictation and commands |
| Perio transcription (WebSocket) | Low-latency recognition tuned for probing grammar |
| Live voice (WebSocket) | Speech-to-speech sessions bridged to Vertex AI |
| Voice synthesis (WebSocket) | Streaming text-to-speech |
| Server-sent events (8) | Copilot answers, appointment board changes, job progress |
WebSocket sessions authenticate with a short-lived signed ticket obtained over REST and presented in the subprotocol header; query-string tokens are refused. Every instance re-checks open sessions against the revocation registry every 15 seconds and closes revoked ones.
server/config/approvedEuRegions.tsserver/services/dataResidencyValidator.tsinfra/services/docs/ARCHITECTURE.md