Architecture
How a request flows through the Vessios system.
Vessios follows Clean Architecture throughout the backend: dependencies point inward (domain ← application ← infrastructure/api), and each service has a single, clear responsibility.
Request flow
Client
│ HTTPS (external HTTPS LB + Cloud Armor WAF)
▼
wiki-gateway (Rust / Axum — thin reverse proxy)
│ Pre-auth edge defense: per-IP rate limiting, body size limits,
│ CORS authority, spoofed-header stripping, JWT verification,
│ x-request-id issuance
▼ Cloud Run platform OIDC (worker runs with --no-allow-unauthenticated)
wiki-worker (Python / FastAPI — sole authority for business logic)
│ Post-auth: RBAC, per-tenant rate/quota, idempotency, JTI revocation
├─ Firestore … tenants / pages / sources / knowledge-graph triples
│ (per-tenant subcollection isolation)
├─ Vertex AI … embeddings + Vector Search / Claude (direct API or via Vertex)
├─ Redis … cache, rate limiting, semantic cache
├─ Pub/Sub … async pipelines (file-ingest, export)
└─ BigQuery … full 3-tier logging (query_logs, usage/audit logs)
Why the gateway is “thin”
wiki-gateway intentionally holds no business logic. Its job is edge defense that must happen before authentication — rate limiting by IP, stripping headers a client shouldn’t be able to set, and verifying JWTs — so that wiki-worker only ever sees traffic that has already passed a first line of defense. Per-tenant concerns (quotas, RBAC) are enforced in the worker, not the gateway, keeping the responsibility split clean: per-IP is the gateway’s job, per-tenant is the worker’s job.
Services
| Service | Language / framework | Responsibility |
|---|---|---|
wiki-gateway |
Rust / Axum | Edge defense, reverse proxy (passthrough — does not parse or type request bodies) |
wiki-worker |
Python / FastAPI | All business logic: domain, application (use cases), infrastructure, API |
wiki-front |
Next.js / TypeScript | Page tree UI, history diff, Markdown live preview, SSE query UI |
Clean Architecture layers (wiki-worker)
domain/— entities and theWikiErrorerror type used across the codebase.application/— ports (interfaces), use cases (50+, covering ingest, search, billing, wiki maintenance, evaluation, and more), and cross-cutting concerns like SSRF prevention and circuit breaking.infrastructure/— concrete adapters: Firestore, Redis, Vertex AI, embeddings, BigQuery, connectors (Notion/Confluence), Slack, GCS, email, extractors, and the LLM client factory.api/— the FastAPI application that wires everything together.
Container/wiring code depends only on the LLM factory, never on a concrete LLM client — see Tech stack for how the backend is selected.