Files
soleprint/docs/data/en/station-cabinets.md
2026-09-17 01:12:15 -03:00

107 lines
3.8 KiB
Markdown

# Cabinets
A cabinet is a **dependency container** a room can switch on: postgres, redis,
airflow. The vocabulary already had the word — `execution.container` in every
room's `config.json` is *"Cabinet — tool container"* — and until now nothing
stood behind it.
The problem it solves: a generated artifact knows what it needs and had no way
to say so. A shunt built from a client's spreadsheets holds its rows in memory
happily, but the moment you want them to survive a restart you need postgres,
and wiring postgres in meant hand-editing a room's `docker-compose.yml` and then
hand-editing the cluster too. A cabinet is that declaration, made once and read
by both paths.
## Switching one on
Add `cfg/<room>/data/cabinets.json`, the same shape as its sibling `data/*.json`
files:
```json
[
{ "name": "postgres" },
{ "name": "redis" },
{ "name": "airflow", "env": { "AIRFLOW_ADMIN_PASSWORD": "change-me" } }
]
```
Then build. The compose merge is a step in [Export / Compile](#export):
```bash
python build.py --cfg sample
cd gen/sample && docker compose up -d
```
`build.py` merges each cabinet's compose fragment into the room's
`docker-compose.yml`, declares its named volumes, and appends its settings to
`.env.example` — never to `.env`.
**A service the room already declares wins.** `cfg/amar/docker-compose.yml`
ships its own `db`; switching the postgres cabinet on will not replace it. The
build says so when it skips one:
```
Composing cabinets...
cabinets: redis, airflow
cabinets already declared by the room, left alone: postgres
```
Dependencies come along automatically. Airflow without a metadata database is a
container that exits on boot, so asking for `airflow` brings `postgres` and
`redis` with it, ordered so compose reads them before the thing that needs them.
## On a cluster
Every cabinet names a `rig_addon`. Where a room runs on kind rather than
compose, the same dependency installs as a rig addon of that name:
```bash
cd rig
PROFILE=data make cluster up # installs the addons too
kubectl -n data port-forward svc/postgres 5432:5432
kubectl -n data port-forward svc/airflow 8080:8080
```
The two paths are deliberately separate — compose for a laptop, manifests for a
cluster — and `rig_addon` is the thread between them, so the room declares the
dependency once either way. The addons generate their own passwords on first
install and keep them across re-runs, so re-running never rotates a credential
out from under something already connected.
## What ships
| Cabinet | Image | Notes |
| --- | --- | --- |
| `postgres` | `postgres:16-alpine` | healthcheck wired, so `depends_on: service_healthy` works |
| `redis` | `redis:7-alpine` | cache, and the broker for anything queue-shaped |
| `airflow` | `apache/airflow:2.10.4` | one container on `standalone`; needs postgres and redis |
## Writing one
```
soleprint/station/cabinets/<name>/
cabinet.json what it is, what it needs, what it exports
service.yml the compose service, verbatim
```
`cabinet.json`:
| Key | Purpose |
| --- | --- |
| `name` | must match the directory |
| `title`, `description` | shown on the station index |
| `service` | the key to merge under in `services:` (defaults to `name`) |
| `env` | settings and defaults, written to `.env.example` |
| `volumes` | named volumes to declare at the top level |
| `depends_on` | other cabinets that must come with it |
| `rig_addon` | the matching `rig/ctrl/addons/<name>.sh`, if there is one |
| `notes` | lines written into `.env.example` as comments |
`service.yml` is a plain compose fragment with one top-level key — the service
name. It stays YAML rather than being generated from JSON so it reads like the
file it becomes, and so anything compose supports is available without this tool
learning about it first.
Adding a cabinet is adding a directory. Nothing dispatches on the name.