Architecture
The production stack (docker-compose.prod.yml) is a set of containers, all
driven by the same .env. The app image is served with
FrankenPHP.
Services
Section titled “Services”| Service | Role |
|---|---|
app |
FrankenPHP web server (serves HTTP; runs migrations on boot) |
reverb |
WebSocket server for real-time broadcasting |
queue |
Queue worker (queue:work) — sends mail, delivers jobs |
scheduler |
Scheduled tasks (schedule:work) — due scheduled messages, invitation pruning |
pgsql |
PostgreSQL database (named volume pgsql-data) |
meilisearch |
Full-text search index (version-scoped named volume) |
redis |
Cache, session, and queue backend (named volume redis-data) |
Every app process (app, reverb, queue, scheduler) waits for pgsql,
redis, and meilisearch to report healthy before it starts.
Data flow
Section titled “Data flow”- HTTP requests hit
app(FrankenPHP) behind your reverse proxy. - Real-time updates are broadcast over WebSockets by
reverb; the browser connects to it through your TLS proxy. - Background work (email, scheduled message delivery) runs on
queueandscheduler. - Search queries go to
meilisearch; the index is derived from Postgres and rebuilt withphp artisan search:syncwhen needed.
Storage backends
Section titled “Storage backends”Cache, session, and the queue all use the Redis driver
(CACHE_STORE / SESSION_DRIVER=redis, QUEUE_CONNECTION=redis, with
REDIS_HOST=redis). Broadcasting uses Reverb. Redis persists to a named
volume with appendonly enabled, so queued jobs survive a restart.
Persistent volumes
Section titled “Persistent volumes”| Volume | Contents |
|---|---|
pgsql-data |
PostgreSQL database |
the-desk-meili-<version> |
Meilisearch index (version-scoped) |
redis-data |
Cache, session, queued jobs |
storage-app |
Uploaded files |
These survive docker compose down / up. See
Upgrading for how the version-scoped Meilisearch
volume behaves across upgrades.