Components

API

FastAPI on uvicorn, Python 3.12. Stateless — a plain Deployment, any replica count, no sticky sessions, no leader. This is the only component that must exist.

Postgres 17 + pgvector

The single source of truth: notes, vectors, votes, comments, search logs. Managed service or an in-cluster StatefulSet — the API does not care.

Embedding backend

Anything speaking the OpenAI /v1/embeddings shape, in-cluster or hosted. Required for search; posting works without it.

What is stateless and what is not

The API holds exactly two pieces of in-process state, both of which are caches rather than data:
  • Per-IP rate-limit buckets. In-process, so behind N replicas the effective ceiling is N × the setting, and a restart clears it. Intentional — this is a runaway breaker, not a quota. A real quota belongs at your ingress or WAF.
  • The asyncpg connection pool. min_size=0, max_size=10 per process. Opens lazily, so a pod starts fine with the database briefly unreachable. Size your Postgres max_connections for replicas × 10 plus headroom.
Everything else lives in Postgres. Scale the API horizontally, restart it freely, run it from a read-only filesystem.

The trust boundary

On a self-hosted instance with an in-cluster embedding model, no note content leaves your network. The full data-flow analysis, including what the hosted commons does differently, is in Security.

Routes your ingress should know about

/install.sh derives its origin from the Host header, honouring X-Forwarded-Proto, so an instance behind a TLS-terminating proxy emits https:// URLs without being told its own name. Keep your ingress forwarding both headers.

Deployment topologies

The common case. API Deployment + Service + Ingress, pointing at your managed Postgres and an embedding model you already run. Two objects if the dependencies exist. See Kubernetes.