Fold files./filestash into the docs that carry the service list, the vhost
map and the deploy procedure — README stack table, 00-overview, 02-caddy,
12-build-order, 14-deploy, and the deploy skill.
Two real gaps the filestash deploy exposed, now guardrails in the skill:
- update-all.sh never touches host nginx, so a NEW SUBDOMAIN silently 404s
after deploy. It needs issue-letsencrypt.sh + render-nginx.sh --install.
- a new service with ${FOO:?} guards fails the WHOLE compose file, so a
missing .env var means `up` starts nothing — and --hard has already run
`down`. Check the host's .env BEFORE tearing the stack down.
Also: filestash/config.json is a single-file bind mount re-rendered every
run, so a rolling update-all leaves it on a stale inode (same trap as the
caddy conf) — force-recreate after any FILES_* change.
Correct the cochi divergence section: `git diff HEAD` on the host is now
empty (verified this deploy — the ff-pull succeeded). The documented
docker-compose.yml/package.json divergence was converged; only untracked
dnsmasq/, caddy-root-ca.crt and a stale pack/ remain. The stash-pull-pop
procedure it prescribed is no longer needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
3.4 KiB
Markdown
76 lines
3.4 KiB
Markdown
# Build order — one commit per task
|
|
|
|
Dependency-ordered. Each numbered item = one git commit. Operational steps
|
|
(prep, acceptance test) need internet/hardware and are NOT commits — marked
|
|
`[ops]`.
|
|
|
|
> Commit message convention: Conventional Commits, scope = service. Footer:
|
|
> `Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>`.
|
|
|
|
## Phase 0 — baseline
|
|
0. `chore: baseline scaffolding` — CLAUDE.md, plan/, docker-compose.yml,
|
|
runtime/, .gitignore, .env.example.
|
|
|
|
## Phase 1 — config foundation
|
|
1. `feat(env): add BASE_DOMAIN + RCON_PASSWORD + CADDY_* to .env.example`
|
|
2. `feat(tooling): add render-config.sh (envsubst BASE_DOMAIN, halt on unset)`
|
|
|
|
## Phase 2 — ingress (caddy internal router)
|
|
3. `feat(caddy): add conf.d snippets (00-core auth+pack, 10-static apex+launcher)`
|
|
4. `feat(compose): add caddy service (127.0.0.1:CADDY_HTTP_PORT) + network aliases`
|
|
|
|
## Phase 3 — auth
|
|
5. `feat(drasl): add config.toml.tmpl (password login, SignPublicKeys=false)`
|
|
6. `refactor(compose): drasl internal-only behind caddy; authlib URL → auth.`
|
|
|
|
## Phase 4 — modpack
|
|
7. `feat(pack): packwiz init + initial mod curation`
|
|
8. `feat(tooling): add render-pack.sh + add-custom-mod.sh`
|
|
9. `refactor(compose): minecraft via PACKWIZ_URL`
|
|
|
|
## Phase 5 — landing
|
|
10. `feat(landing): Astro+TS onboarding site → www/`
|
|
11. `chore(landing): wire logo + .gitignore for www/`
|
|
11b. `feat(landing): /register page → Drasl API (B1) + REGISTRATION_MODE flag`
|
|
(CORS/RateLimit/RegistrationNewPlayer in drasl config.toml.tmpl; see
|
|
`16-landing-registration.md`).
|
|
|
|
## Phase 6 — launcher distribution
|
|
12. `feat(tooling): add fetch-launcher.sh (all platforms + stable symlinks)`
|
|
|
|
## Phase 7 — extra services
|
|
13. `feat(avatar): add nmsr service (Drasl-backed) + 40-avatar.caddy`
|
|
14. `feat(status): add uptime-kuma service + 50-status.caddy`
|
|
15. `feat(distribution): add 30-distribution.caddy (static, another repo)`
|
|
|
|
## Phase 8 — backups
|
|
16. `feat(compose): add mc-backup service (RCON, 6h)`
|
|
|
|
## Phase 9 — production ingress / TLS
|
|
17. `feat(nginx): add ulicraft-caddy.conf.tmpl + render-nginx.sh`
|
|
18. `feat(tls): add issue-letsencrypt.sh (OVH DNS-01) + LE env block`
|
|
|
|
## Phase 11 — file share (DONE, 2026-07-14)
|
|
19. `feat(files): add Filestash player file share at files.${BASE_DOMAIN}` —
|
|
compose service (digest-pinned) + `60-files.caddy` + nginx vhost (2g uploads,
|
|
`/admin` rate limit) + `filestash/config.json.tmpl` rendered `:ro` +
|
|
`FILES_*` env block. One shared htpasswd login, writable. See `20-files.md`.
|
|
- [ops] `files` added to `LE_SUBDOMAINS` → `issue-letsencrypt.sh`, then
|
|
`render-nginx.sh --install` (a new subdomain needs BOTH; `update-all.sh`
|
|
does not touch host nginx).
|
|
|
|
## Phase 10 — operational (no commits)
|
|
- [ops] Prep online (once): `tooling/render-config.sh`, build landing
|
|
(`cd landing && set -a && . ../.env && set +a && pnpm run build` — sources
|
|
`.env` so `BASE_DOMAIN` + `REGISTRATION_MODE` bake into the static output),
|
|
`tooling/fetch-launcher.sh`, fetch authlib-injector into `runtime/`.
|
|
- [ops] TLS: `tooling/issue-letsencrypt.sh`, then
|
|
`tooling/render-nginx.sh --install`.
|
|
- [ops] Bring up: `docker compose up -d --build`.
|
|
- [ops] Acceptance: install Fjord, add drasl account, import pack, join.
|
|
- [ops] If green: tag `v1-ready`.
|
|
|
|
## Notes
|
|
- Bring-up is a single command — no run modes, no override compose files.
|
|
- Each commit should leave the tree in a non-broken state (compose still parses).
|