deploy: move diagram into Preparing section, vary admonitions, simplify

- Move the flow diagram up into 'Preparing for Deploy' (was a separate
  section at the bottom); drop that trailing section.
- Use more admonition types for visual variety: success (what can run),
  abstract (the whole flow), example (container-path), success (same file
  both places) — alongside the existing danger/warning/tip.
- Simplify the diagram: libs -> 'libs (rethink-public, pip)', the git edge
  -> 'branch', staging -> 'main'; abstract intro reworded to branch+main.
- Trim the Compose tab: drop the rules list that duplicated the inline
  comments + danger box; tighten the storage tiers.

Verified in-browser: diagram renders with simplified nodes near the top,
six admonition types present; mkdocs build --strict clean.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
2026-07-01 02:58:22 -04:00
parent 823aa7708a
commit 5797248931
+46 -70
View File
@@ -4,27 +4,51 @@
> container to follow a few consistent rules and deploying is mostly handing us a > container to follow a few consistent rules and deploying is mostly handing us a
> `compose.yaml`. > `compose.yaml`.
!!! tip "What can run here" !!! success "What can run here"
APIs, websites, applets, bots, monitors. APIs, websites, applets, bots, monitors.
## Preparing for Deploy ## Preparing for Deploy
Get these three right and your repo is deployable — you don't run any deploy commands !!! abstract "The whole flow"
yourself, the ops tooling takes it from git. Each tab is one piece. You build and test locally — leaning on our libraries, AI, and this handbook —
then push a branch and merge to `main`. From there the ops tooling takes over: it
builds the Docker image and runs it on the fleet. **You don't run any deploy
commands** — your only job is the three pieces in the tabs below.
```mermaid
flowchart LR
subgraph build ["you build"]
direction TB
local["local testing"]
libs["libs<br/>(rethink-public, pip)"]
ai["AI-assisted<br/>(Claude Code)"]
docs["reading the<br/>handbook"]
local --- libs
libs --- ai
ai --- docs
docs --- local
end
build -->|branch| git["git<br/>(Gitea)"]
git --> main["main"]
main --> deploy["deployment<br/>(ops tooling)"]
deploy --> docker["docker<br/>(image built + run on the fleet)"]
classDef ship fill:#061541,stroke:#569bcc,color:#eef1f6;
classDef work fill:#0e1530,stroke:#294274,color:#eef1f6;
class git,main,deploy,docker ship;
class local,libs,ai,docs work;
```
!!! danger "Your compose names nothing repo-specific" !!! danger "Your compose names nothing repo-specific"
**No `container_name`. No hardcoded names, workspace, or `/srv` paths.** The **No `container_name`, no hardcoded names/paths.** The deploy layer injects
deploy layer injects identity and host paths at deploy time — your compose stays identity and host paths so your compose can't collide with any other service on
generic so it can't collide with any other service on the fleet. the fleet:
- the service key is **always `svc`** — it never changes, in any repo - the service key is **always `svc`** — it never changes, in any repo
- named volumes use **bare names** (`cache`, not `myapp_cache`) - named volumes use **bare names** (`cache`, not `myapp_cache`)
- host paths come from **`${LOGS_DIR}` / `${CONFIG_DIR}`** - host paths come from **`${LOGS_DIR}` / `${CONFIG_DIR}`**
Naming things after your repo used to cause **container-name collisions** at
fleet scale — two repos shipping the same name clashed. The generic compose in
the **Compose** tab fixes that.
=== "Compose" === "Compose"
The `compose.yaml` your repo ships. Copy it verbatim — it names nothing The `compose.yaml` your repo ships. Copy it verbatim — it names nothing
@@ -49,38 +73,22 @@ yourself, the ops tooling takes it from git. Each tab is one piece.
cache: # bare name — deploy auto-prefixes it per service cache: # bare name — deploy auto-prefixes it per service
``` ```
**The rules:** !!! example "The container path is where your code reads and writes"
- **Service key is always `svc`** — never a repo-specific name, never a
`container_name`. The ops tooling keys off `svc`; this is what makes services
collision-proof on the fleet.
- **`user: "1337:1337"` and `restart: unless-stopped` are required** — the shared
`services` account (uid/gid 1337, fixed fleet-wide), and Docker's restart policy
recovering a crashed container (the host unit is oneshot).
- **Host paths come from `${...}` variables, never hardcoded.** Write to
`${LOGS_DIR}` and `${CONFIG_DIR}`; `${MOUNTS_DIR}` is optional.
- **Named volumes use bare names** (`cache`, not `myapp_cache`) — deploy
auto-prefixes them per service so they can't collide.
!!! tip "The container path is where your code reads and writes"
`WORKDIR` is `/app`, so the **right-hand side** of each volume line is the path `WORKDIR` is `/app`, so the **right-hand side** of each volume line is the path
your code targets. If your app writes to `./cache` (i.e. `/app/cache`), that's your code targets. Write to `./cache` (i.e. `/app/cache`) the `cache` volume;
the `cache` mount; logs go to `/app/logs`, config is read from `/app/config`. logs go to `/app/logs`, config is read from `/app/config`.
**Three tiers of storage:** **Storage, three tiers:**
- **`logs`** (output) and **`config`** (input you edit) — **we handle these**: - **`logs` + `config`** — we inject and manage these at deploy time.
injected and managed at deploy time. - **`mounts`** (optional) — host dir for arbitrary data. We inject `MOUNTS_DIR` and
- **`mounts`** (optional) — a host dir for arbitrary read/write data. The deploy create the dir; you **uncomment** the line and pick the container path.
layer **injects `MOUNTS_DIR` and auto-creates the dir**, but the mount line is - **Named volumes** (`cache`, …) — yours; Docker owns them, no host paths to manage.
**opt-in**: uncomment it and choose the container path yourself (it's
app-specific, so it can't be auto-mounted).
- **Named volumes** (`cache`, …) — **yours**: anything else your service persists.
Docker owns them, no host paths to manage.
Locally, `docker compose up` needs nothing set — the `${VAR:-./default}` fallbacks !!! success "Same file, both places"
use `./logs`, `./config` (and `./mounts` if you enable it). When deployed, the ops Locally, `docker compose up` needs nothing set — the `${VAR:-./default}`
tooling sets the real values, so the same file works both places. fallbacks use `./logs` / `./config`. When deployed, the ops tooling sets the
real values. One `compose.yaml` works everywhere.
**Subprocess and browser workloads** (bots that spawn Chrome, Xvfb, ffmpeg) need **Subprocess and browser workloads** (bots that spawn Chrome, Xvfb, ffmpeg) need
three extra knobs: three extra knobs:
@@ -173,35 +181,3 @@ yourself, the ops tooling takes it from git. Each tab is one piece.
**Rotating a secret** is a host-side edit — update the file and the service picks **Rotating a secret** is a host-side edit — update the file and the service picks
it up on restart. No rebuild, and nothing you run: flag it and we handle the it up on restart. No rebuild, and nothing you run: flag it and we handle the
restart. restart.
## The path to deploy
You build and test locally — leaning on our libraries, AI, and this handbook — then
push to git. From there it's staging (if you're running gitflow) and, once it's good,
deployment: the ops tooling builds the Docker image and starts it on the fleet.
```mermaid
flowchart LR
subgraph build ["you build"]
direction TB
local["local testing"]
libs["our libraries<br/>(rethink-public)"]
ai["AI-assisted<br/>(Claude Code)"]
docs["reading the<br/>handbook"]
local --- libs
libs --- ai
ai --- docs
docs --- local
end
build -->|push| git["git<br/>(Gitea)"]
git -.->|develop, if gitflow| stage["staging"]
git --> deploy["deployment<br/>(ops tooling)"]
stage --> deploy
deploy --> docker["docker<br/>(image built + run on the fleet)"]
classDef ship fill:#061541,stroke:#569bcc,color:#eef1f6;
classDef work fill:#0e1530,stroke:#294274,color:#eef1f6;
class git,stage,deploy,docker ship;
class local,libs,ai,docs work;
```