Architecture Overview
In Falcone is a multi-tenant BaaS assembled from a small set of cooperating services in front of standard data backends. The design has three throughlines:
- One gateway, two privilege domains. Everything enters through APISIX, which classifies a request by its credential and routes it to either the control plane (
structural_admin) or the executor (data_access). - Identity derives the tenant — never the client. The tenant/workspace come from a verified credential (API key → JWT → gateway-injected headers, in that order). Client-supplied
x-tenant-idis never trusted. Invalid credentials fail closed. - Isolation is enforced at the data layer, not just at the edge. PostgreSQL Row-Level Security with a non-
BYPASSRLSrole, MongoDB adapter-injected predicates, and tenant-scoped realtime matching mean a routing mistake cannot leak data.
Request lifecycle
┌──────────────────────────────────────────────────────┐
Browser / │ APISIX (API gateway) │
App / CLI ───▶│ • classify credential: apikey: flc_… | Bearer JWT │
│ • enforce scope (structural_admin | data_access) │
│ • rate-limit per key • inject verified identity hdrs │
└───────────────┬───────────────────────┬──────────────┘
│ structural_admin │ data_access
▼ ▼
┌────────────────────┐ ┌──────────────────────────────┐
│ Control Plane │ │ Executor │
│ tenants/workspaces│ │ resolveIdentity() │
│ schemas/functions │ │ build*Plan() → run on driver│
│ api-keys/quotas │ └───┬─────┬─────┬─────┬─────┬───┘
│ /v1/flows /v1/mcp │ │ │ │ │ │
└─────────┬──────────┘ │ │ │ │ │
│ Postgres Mongo Kafka MinIO Funcs
▼ │ │ │ │ │
┌────────────────────┐ ▼ ▼ ▼ ▼ ▼
│ Platform metadata │ (per-workspace data backends, tenant-scoped)
│ (tenants, plans…) │
└────────────────────┘
Identity: Keycloak (OIDC) · Secrets: Vault + External Secrets · Metrics: Prometheus- A data-plane call (e.g.
GET /v1/collections/todos/documentswithapikey: flc_anon_…) is routed by the gateway to the executor. The executor verifies the key, resolves the tenant/workspace and DB role from it, builds an adapter query plan, and runs it against the workspace's real database — under RLS. - A structural-admin call (e.g.
POST /v1/tenantswith a Bearer admin token) is routed to the control plane, which mutates platform metadata and reconciles downstream resources (gateway routes, identity realm, provisioning).
The two privilege domains
The public route catalog (services/gateway-config/public-route-catalog.json) tags every route with a privilege_domain. The gateway's scope-enforcement plugin checks the caller's domain before forwarding:
| Domain | Examples | Typical caller |
|---|---|---|
structural_admin | POST /v1/tenants, POST /v1/workspaces, POST /v1/schemas, POST /v1/functions, POST /v1/api-keys, PUT /v1/quotas, POST /v1/services/configure | Operators, tenant admins (Bearer JWT) |
data_access | …/collections/{name}/documents, …/collections/{name}/query, …/objects/{bucket}/{key}, …/functions/{id}/invoke, …/events/publish, …/events/subscribe, …/analytics/query | Applications (API keys / JWT) |
Identity resolution (precedence)
The executor's resolveIdentity() (apps/control-plane/src/runtime/server.mjs) applies a strict order. Each authoritative credential derives the tenant from itself:
1. API key (apikey: flc_… | Authorization: ApiKey/Bearer flc_… | x-api-key)
→ tenant, workspace, and DB role come from the verified key
→ invalid key ⇒ 401 (never falls back to headers)
2. Bearer JWT (when a verifier is configured)
→ identity from verified token claims
→ invalid token ⇒ 401
3. Gateway-injected headers (x-tenant-id / x-workspace-id / x-auth-subject / x-pg-role)
→ only trusted when no credential was presented; the gateway validated the
token upstream and stripped any client-supplied context headersThis precedence is the reason a client cannot spoof a tenant: the only way to set x-tenant-id is through the gateway, after it has validated a token — and any presented flc_… key or Bearer JWT overrides headers entirely.
Data isolation strategy
In Falcone uses a shared-database, tenant-scoped model with defense in depth:
- PostgreSQL — RLS policies on tenant-scoped tables, plus a dedicated non-
BYPASSRLSapplication role (falcone_app, withanon/servicevariants). The executor runs queries viaSET LOCAL ROLEso even a buggy query is constrained by RLS. (A superuser would bypass RLS — which is exactly why the app role is not a superuser.) - MongoDB — the data adapter injects a
tenantIdpredicate into every read and stamps it on every write; the realtime change-stream pipeline$matches on the verified tenant. - Every layer — caches, queues, object keys, events and logs are keyed by tenant so isolation holds beyond the database.
See Security & Auth for the full model.
AI-native layer (Flows & MCP) — Preview
Two capabilities make a tenant's backend consumable by AI agents, both served by the control plane and both off by default:
Control Plane
├─ /v1/flows/workspaces/{ws}/… ──▶ Temporal ◀──poll── workflow-worker
│ (durable workflow definitions, (DslInterpreterWorkflow +
│ versions, executions) first-party activity catalog)
└─ /v1/mcp/workspaces/{ws}/servers/… ──▶ mcp-engine ──▶ Knative ksvc (per-tenant MCP server)
(create · curate · publish · call · audit) served over Streamable HTTP, OAuth 2.1- Flows — a durable workflow engine on Temporal (chart components
temporal+workflowWorker, enabled byTEMPORAL_ADDRESS). Tenants author a YAML DSL; the control plane stores immutable versions and runs each execution as a Temporal workflow. Isolation is by server-generated workflow ids ({tenantId}:{workspaceId}:{flowId}:{runUuid}) prefix-checked on every command. - MCP server hosting — the control-plane runtime serves the MCP management API (
mcp-engine, enabled byMCP_ENABLED). Instant MCP and the official server are live (Preview); custom (BYO-image) hosting and workflows-as-tools are Experimental; per-tenant OAuth 2.1 + per-tool scopes via Keycloak; MCP-server pods are internal-only.
Where to go next
- Services & Components — a subsection per component (gateway, control plane, executor, adapters, console, realtime, data backends, Flows, MCP hosting, identity, secrets, observability).
- Flows · Workflow DSL Reference · MCP Server Hosting — the AI-native capabilities.
- Domain Model — tenants, workspaces, members, plans, quotas.
- Deployment Topology — how it all maps to a cluster.