The datastores and AI provider keys every Your Office AI deployment needs: two PostgreSQL databases, Redis, S3-compatible object storage, and the six LLM providers plus an embedding model. This page covers what to provision and exactly where each value goes.
Tenant-server secrets (databases, Redis, LLM keys, embeddings) live in command_center_tenant_server/config/passwords.yaml; auth secrets in command_center_server/config/passwords.yaml. Non-secret host/port settings live in the matching config/development.yaml (or staging / production). Keep passwords.yaml out of version control.
Your Office AI is a multi-tenant platform with a two-server backend, and each server owns its own database. Keeping them separate means the Auth server (identity) and the Tenant server (per-organisation data) can be operated, scaled, and even hosted by different parties.
Your Office AI runs two independent databases: an auth database for the Auth server (users, organisations, global settings) and a tenant database for the Tenant server (chat, knowledge, integrations, LiveKit tokens). For local development both run in Docker via each server's docker-compose.yaml. For production use managed Postgres — Supabase, AWS RDS, or Cloud SQL.
For each database note the host, port, database name, user, and password. From a Supabase project these are under Settings → Database → Connection string. Pick the region closest to your users — the EU DB hosts use LUKS / AES-256 volume encryption at rest.
Put each password in the matching server's config/passwords.yaml under the right environment (development.database) and the host/port/name in config/development.yaml (or staging / production). The auth values live in command_center_server; the tenant values in command_center_tenant_server.
Run migrations against both databases (from the repo root, make both-migrate). This also enables the PostgreSQL vector extension used by Knowledge for pgvector semantic search. Seed test data with make both-seed if you want a populated environment.
| Value | File | Key |
|---|---|---|
| Auth DB password | command_center_server/config/passwords.yaml | development.database |
| Auth DB host / port / name | command_center_server/config/development.yaml | database.host / .port / .name |
| Tenant DB password | command_center_tenant_server/config/passwords.yaml | development.database |
| Tenant DB host / port / name | command_center_tenant_server/config/development.yaml | database.host / .port / .name |
The Auth and Tenant servers must share an identical TENANT_JWT_SECRET (env var, or shared.tenantJwtSecret in passwords.yaml). The Auth server signs tenant JWTs with it and the Tenant server verifies them; if the two differ, every tenant API call returns 401. Use the same byte-for-byte value on both, even across different hosts.
Redis backs Serverpod's real-time streams on the tenant server. It is also the linchpin of horizontal scaling: with Redis as a shared message bus, any replica can broadcast an event that every other replica receives.
The tenant server uses Redis for Serverpod real-time streams (pub/sub). Locally it ships in docker-compose.yaml. For production use a managed Redis — ElastiCache, Upstash, or Redis Cloud.
Set the Redis password in config/passwords.yaml (development.redis) and the host/port in config/development.yaml under redis:. The auth server has its own Redis container available with the same key layout.
A single instance can run without Redis, but pub/sub is mandatory the moment you run more than one tenant-server replica — it is how replicas broadcast events to each other. See the Multi-instance Deployment guide.
| Value | File | Key |
|---|---|---|
| Tenant Redis password | command_center_tenant_server/config/passwords.yaml | development.redis |
| Tenant Redis host / port | command_center_tenant_server/config/development.yaml | redis.host / redis.port |
Uploads, knowledge documents, and avatars live in S3-compatible object storage. Self-hosted deployments typically run MinIO; managed deployments use Supabase Storage. Document downloads are server-mediated — the app fetches bytes through the tenant server rather than exposing a storage URL directly — so private buckets never need to be public.
File uploads, knowledge documents, and avatars are stored in object storage. Self-hosted deployments run MinIO (S3-compatible, free, local Docker); managed deployments use Supabase Storage. Either works — the app speaks the S3 API.
Create the buckets the app uses (for example uploads and avatars). In Supabase Storage, mark avatar-style buckets Public and keep upload buckets private.
For Supabase Storage, add Row-Level Security policies so authenticated users can read and write only their own folder (path prefixed with their user id), with public read on avatar buckets. Downloads of knowledge documents are server-mediated, so private buckets never need a public URL.
For development and air-gapped self-hosting, MinIO runs in Docker at zero cost and speaks the same S3 API as cloud storage. Reserve managed Supabase Storage for deployments that want a hosted bucket.
Your Office AI is provider-agnostic. A single organisation can offer six AI providers, and administrators choose which models are available and set spend limits per organisation. Hosted models come from OpenAI, Anthropic, Google, and Groq; private and local inference runs through Ollama and Ollama Cloud.
| Provider | Type | Example model |
|---|---|---|
| OpenAI | Hosted | gpt-4o-mini |
| Anthropic | Hosted | claude-sonnet-4-5 |
| Hosted | gemini-2.0-flash | |
| Groq | Hosted (fast inference) | Llama / Mixtral family |
| Ollama | Local / private | llama3.2 |
| Ollama Cloud | Hosted Ollama | gpt-oss:120b |
Add the provider API keys you intend to use to the tenant server's passwords.yaml. Each provider has its own key (for example openaiApiKey); Ollama and Ollama Cloud take a base URL and model name rather than a secret key. The OpenAI key also powers image generation in workflows. There is no hardcoded default provider — availability is whatever an admin configures.
Ollama Cloud's host is api.ollama.com — the .ai domain does not resolve. Use the .com host in every config value.
Knowledge answers are grounded with pgvector semantic search: uploaded documents and linked websites are chunked, embedded, and retrieved with citations. That requires an embedding model in addition to the chat LLMs. Configure an embedding provider key (for example an OpenAI embeddings key) in the tenant server's passwords.yaml.
The pgvector column has a fixed dimension that must match your embedding model (for example 1536 for OpenAI). Pick one embedding provider and stay on it — switching providers changes the vector dimension and invalidates stored embeddings. The platform deliberately does not auto-failover between embedding providers.
Where the core values live, at a glance:
| Concern | Server | File |
|---|---|---|
| Auth database, email | Auth server | command_center_server/config/passwords.yaml |
| Tenant database, Redis, LiveKit, LLM + embedding keys, Nango | Tenant server | command_center_tenant_server/config/passwords.yaml |
| Host / port / non-secret settings | Both | config/development.yaml (or staging / production) |
| Storage URL + anon key | Flutter app | command_center_flutter Supabase init |
With datastores and AI keys in place, set up OAuth & integrations via Nango to connect the integration catalog, or jump to LiveKit setup for real-time video and voice.