Architecture
AnvilBase is a set of services orchestrated by a central control plane. The control plane is the only component clients talk to; it authenticates requests, enforces per-project isolation, and routes to the right backing service.
Internet │ ▼┌──────────────────────────────────────────────────────────────┐│ Traefik — TLS termination (Let's Encrypt), routing │└───────────────────────────┬──────────────────────────────────┘ │┌───────────────────────────▼──────────────────────────────────┐│ Control Plane (Rust / Axum) ││ • Project lifecycle (create / suspend / delete) ││ • API key + JWT validation, RLS context injection ││ • Rate limiting (per project, per scope) ││ • Built-in REST→SQL engine (replaces PostgREST) ││ • Audit log ingestion, secrets vault API, KMS abstraction │└──┬──────────┬──────────┬──────────┬──────────┬───────────────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼┌──────┐ ┌────────┐ ┌───────┐ ┌──────┐ ┌──────────┐│ Auth │ │Realtime│ │Storage│ │ Deno │ │ Webhooks ││Better│ │Phoenix │ │ MinIO │ │ Edge │ │ (Rust) ││ Auth │ │Channels│ │ /S3 │ │ Funcs│ │ │└──┬───┘ └───┬────┘ └───┬───┘ └──┬───┘ └────┬─────┘ │ │ │ │ │ └──────────┴───────────┴────┬────┴───────────┘ ▼ ┌──────────────────────────────────────────────┐ │ PostgreSQL 15 (one database per project) │ │ platform_<project_id> │ │ + pgvector, PGMQ, pg_cron, pg_net, │ │ pgcrypto, pg_stat_statements │ └───────────────┬──────────────────────────────┘ │ ┌───────────┴───────────┐ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Supavisor│ │ Valkey │ │ (pooler) │ │ (cache) │ └──────────┘ └──────────┘The two planes
AnvilBase exposes two distinct API surfaces on the same host. This split is fundamental — keep it straight.
| Plane | Prefix | Who uses it | Credential |
|---|---|---|---|
| Management plane | /api/v1/* | Operators, the console, the CLI | Admin token or Personal Access Token (anvilbase_pat_…) |
| Data plane | /v1/* | Your applications & end-user traffic | Per-project API key (anon / service_role) or a project JWT |
There are also two unauthenticated platform routes (/health, /health/services,
/openapi.json) and an internal service-to-service surface (/internal/*, guarded
by X-Internal-Secret) you never call directly.
See Core Concepts for the full credential model and Reference → Management API / Data-Plane API for the endpoint catalogs.
Components
Control plane (Rust / Axum)
The heart of the system. Besides routing and auth, it contains the REST→SQL engine — the component that gives every project a PostgREST-compatible API without a per-project process. Internally:
rest/pool_manager.rs— lazy per-project connection pools (deadpool-postgres), created on first request, evicted after ~5 min idle (~2–5 MB each).rest/query_parser.rs— parses PostgREST query syntax (select, filters,order,limit,offset, operators).rest/sql_builder.rs— generates parameterized SQL with validated, quoted identifiers (SQL-injection-safe; never string-interpolates user SQL).rest/handler.rs— the request pipeline: parse → build SQL → acquire pool → inject RLS context (SET LOCAL) → execute → format response.
Auth (Better Auth, TypeScript/Bun)
One shared binary serves all projects, each with its own config and JWT secret. Handles email/password, magic links, OAuth, sessions, refresh tokens, and bans. The control plane proxies and administers it. See Auth.
Realtime (Elixir / Phoenix)
Phoenix Channels on the BEAM VM — built for millions of concurrent WebSockets.
Subscribes to Postgres LISTEN/NOTIFY and fans out change events; also provides
broadcast (pub/sub) and presence. The wire protocol matches
@supabase/realtime-js. See Realtime.
Storage (MinIO, S3-compatible)
Per-project bucket isolation with SSE-S3 encryption. The control plane proxies S3 operations and issues presigned URLs. An opt-in overlay swaps MinIO for RustFS (a Rust S3 server) for a single-binary dependency story. See Storage.
Edge Functions (Deno)
TypeScript/JavaScript functions executed in the Deno runtime, with each project’s functions served by their own isolated OS process (filesystem-scoped to that project). The control plane stores code (metadata in Postgres, body in object storage) and the Deno runtime executes it, with the project’s DB URL, service-role key, and anon key injected as request headers. See Edge Functions and Functions Runtime.
Webhooks (Rust)
A standalone delivery service. The control plane writes a delivery row and a
pg_notify; the webhooks service LISTENs, POSTs the signed payload (HMAC-SHA256
in X-Webhook-Signature, over "{timestamp}.{body}"), retries with exponential
backoff, and dead-letters failures. See Webhooks.
PostgreSQL 15 + extensions
The single source of truth. One database per project (platform_<id>). Bundled
extensions include pgvector (vectors), PGMQ (queues), pg_cron (scheduling),
pg_net (outbound HTTP from SQL), pgcrypto (secrets & column
encryption), and pg_stat_statements. See Extensions.
Supavisor (connection pooling) & Valkey (cache)
Supavisor (Elixir) provides transaction/session pooling. Valkey is the
Apache-2.0 Redis fork used for rate limiting and the per-project namespaced cache
(<project_id>:<key>). See Cache.
Traefik (reverse proxy)
Terminates TLS at the edge (Let’s Encrypt), routes by host/path, and is the only component that should be exposed publicly.
Request lifecycle (data plane)
A typical GET /v1/rest/<project_id>/messages?status=eq.published flows:
- Traefik terminates TLS and forwards to the control plane.
- Auth middleware resolves the API key / JWT, identifies the project and
scope (
anon/authenticated/service_role), and rejects unknown credentials. - Rate limiter checks the per-project, per-scope budget in Valkey.
- REST engine parses the query, acquires the project’s pool, opens a
transaction, and runs
SET LOCALto inject the user/role context. - Postgres evaluates RLS policies against that context and returns only permitted rows.
- The engine formats a PostgREST-compatible JSON response with rate-limit headers.
The same middleware chain fronts auth, storage, functions, realtime, and eIDAS — isolation is enforced before any request reaches a backing service.
Multi-tenancy isolation
Each project is isolated across every layer:
| Resource | Isolation |
|---|---|
| Database | separate platform_<id> database |
| Storage | separate bucket bucket-<id> + separate SSE key |
| Secrets | encrypted vault in the project DB, unique key |
| Auth | separate JWT secret (rotatable) per project |
| Edge functions | separate OS process per project, FS-scoped to /functions/<id> |
| Cache | Valkey key namespace <id>:<key> |
| Queues | PGMQ namespace inside the project DB |
Language strategy (why each piece is what it is)
- Rust (Axum) — control plane, REST engine, webhooks, CLI: lowest memory per connection, single-binary distribution, fast JWT validation.
- Elixir (Phoenix) — realtime + Supavisor: the BEAM is unmatched for massive concurrent WebSocket fan-out.
- TypeScript (Bun) — Better Auth and the Deno edge bridge are TS-native.
- React (Vite + shadcn/ui + Tailwind + TanStack) — the console.
Next: Core Concepts.