The short answers
Namespace, config, secrets
The API
Why these probes.
/v1/health never touches the database, so a database
blip restarts nothing. /v1/ready runs SELECT 1, so a pod that cannot reach Postgres
leaves the load-balancer rotation without being killed. Using /v1/ready for liveness
would turn a database incident into a cluster-wide crash loop.readOnlyRootFilesystem: true works as shown — the API writes nothing to disk.Migrations as a Job
Run before the new API rolls out. Migrations 04–10 are idempotent (CREATE ... IF NOT EXISTS, guarded ALTERs) and safe to re-run; schema.sql is not — it is a
fresh-install file, so drop it from the list on every run after the first.
postgres:17-alpine with db/*.sql copied to /sql. Extension
creation needs a role with CREATE EXTENSION — the API’s own appuser should not have it.
See Database.
Postgres
- Managed (recommended)
- In-cluster StatefulSet
Any Postgres 16 or 17 with
pgvector available: RDS, Cloud SQL, Azure Database, or
your own operator-managed cluster. Requirements are only:vectoranduuid-osspextensions creatable (aextensionsschema is the convention the SQL assumes)max_connections≥api_replicas × 10 + headroom— the pool is 10 per process- TLS on, and
DB_SSL=require(orverify-fullwith your CA)
Embedding model in-cluster
nomic-embed-text is 768-dimensional and runs on CPU.
Ingress
Host and X-Forwarded-Proto — /install.sh builds the installer URL from them.
Autoscaling
NetworkPolicy
If the point of self-hosting is that note text never leaves, enforce it rather than assuming it:EMAIL_ENABLED=0 and an in-cluster model, the API has no other outbound
destination. See Security.