🗄️ Infrastructure

Core services & environment

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.

ℹ️
One file holds the secrets

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.

🗄️DatabasesAuth + tenant
RedisPub/sub
📦Object storageMinIO / Supabase
🧠LLM + embeddingsKeys + pgvector
The core datastore and AI layer, in the order you stand them up.

PostgreSQL — the dual databases

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.

  1. Provision two PostgreSQL databases

    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.

  2. Record the connection details

    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.

  3. Set the password and host/port

    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.

  4. Apply migrations

    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.

Where the values go

ValueFileKey
Auth DB passwordcommand_center_server/config/passwords.yamldevelopment.database
Auth DB host / port / namecommand_center_server/config/development.yamldatabase.host / .port / .name
Tenant DB passwordcommand_center_tenant_server/config/passwords.yamldevelopment.database
Tenant DB host / port / namecommand_center_tenant_server/config/development.yamldatabase.host / .port / .name
⚠️
Shared JWT secret

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 — real-time pub/sub

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.

  1. Provision Redis

    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.

  2. Set the password and host/port

    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.

  3. Required once you scale out

    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.

ValueFileKey
Tenant Redis passwordcommand_center_tenant_server/config/passwords.yamldevelopment.redis
Tenant Redis host / portcommand_center_tenant_server/config/development.yamlredis.host / redis.port

Object storage

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.

  1. Pick an S3-compatible store

    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.

  2. Create buckets

    Create the buckets the app uses (for example uploads and avatars). In Supabase Storage, mark avatar-style buckets Public and keep upload buckets private.

  3. Set access policies

    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.

💡
MinIO is free and local

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.

LLM providers — six in one organisation

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.

ProviderTypeExample model
OpenAIHostedgpt-4o-mini
AnthropicHostedclaude-sonnet-4-5
GoogleHostedgemini-2.0-flash
GroqHosted (fast inference)Llama / Mixtral family
OllamaLocal / privatellama3.2
Ollama CloudHosted Ollamagpt-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 URL

Ollama Cloud's host is api.ollama.com — the .ai domain does not resolve. Use the .com host in every config value.

Embedding model — grounding Knowledge

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.

⚠️
Don't mix embedding providers

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.

Environment summary

Where the core values live, at a glance:

ConcernServerFile
Auth database, emailAuth servercommand_center_server/config/passwords.yaml
Tenant database, Redis, LiveKit, LLM + embedding keys, NangoTenant servercommand_center_tenant_server/config/passwords.yaml
Host / port / non-secret settingsBothconfig/development.yaml (or staging / production)
Storage URL + anon keyFlutter appcommand_center_flutter Supabase init
ℹ️
Next

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.