refactor!: unify into one compose, drop airgap/mirror/dnsmasq/avahi/blessingskin

Collapse the override-file matrix into a single docker-compose.yml holding the
whole stack: drasl, minecraft, mc-backup, caddy, nmsr, uptime-kuma. Bring-up is
now just `docker compose up -d --build`.

Removed features (dead-ends for this deployment):
- airgap / full asset mirror (mirror-airgap.sh, mirror-mods.sh, 20-mirror.caddy,
  caddy local-CA export, /ca.crt)
- dnsmasq + avahi/mDNS + dns-records.sh + mdns-host-setup.sh + ENABLE_MDNS;
  DNS is now handled outside this repo (HOST_LAN_IP dropped)
- Blessing Skin auth variant (compose + 00-core-blessingskin.caddy + BS_* env)
- host-nginx-static variant (docker-compose.nginx.yml, nginx/ulicraft.conf.tmpl)
- build-stack.sh and its run modes (online/airgap/core)

Production ingress is the only path now: host nginx terminates TLS (LE certs)
in front of caddy on a localhost-only port; caddy routes every vhost by Host
header. Launcher downloads move mirror/launcher -> launcher/.

Docs: README, deploy skill, and plan/ rewritten to match; obsolete plan docs
(dnsmasq, blessing-skin, assets-mirror, full-airgap-mirror, dns-and-run-modes)
deleted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 02:14:09 +02:00
parent ff645de2c8
commit 67d1f82e6a
53 changed files with 522 additions and 2244 deletions

View File

@@ -1,59 +1,62 @@
# Build order — one commit per task
Dependency-ordered. Each numbered item = one git commit. `main` currently has
**zero commits**; item 0 is the baseline. Operational steps (pre-bake, capture,
acceptance test) need internet/hardware and are NOT commits — marked `[ops]`.
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.7 (1M context) <noreply@anthropic.com>`.
> `Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>`.
## Phase 0 — baseline
0. `chore: baseline scaffolding`existing untracked tree (CLAUDE.md, plan/,
current docker-compose.yml, extras/, .gitignore, .env.example).
0. `chore: baseline scaffolding`CLAUDE.md, plan/, docker-compose.yml,
runtime/, .gitignore, .env.example.
## Phase 1 — config foundation
1. `feat(env): add BASE_DOMAIN + HOST_LAN_IP to .env.example`
2. `feat(tooling): add render-config.sh (envsubst, halt on unset var)`
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 — DNS + ingress (no app yet, but the backbone)
3. `feat(dnsmasq): add dnsmasq.conf.tmpl (wildcard *.BASE_DOMAIN)`
4. `feat(caddy): add Caddyfile (apex + auth + packwiz vhosts)`
5. `feat(compose): add dnsmasq + caddy services + network aliases`
## 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
6. `feat(drasl): add config.toml.tmpl (password login, SignPublicKeys=false)`
7. `refactor(compose): drasl internal-only behind caddy; authlib URL → 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
8. `feat(pack): packwiz init + initial mod curation`
9. `feat(tooling): add mirror-mods.sh (vendor jars + rewrite .pw.toml URLs)`
10. `refactor(compose): minecraft via PACKWIZ_URL; extras→runtime`
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
11. `feat(landing): Astro+TS onboarding site → www/` (files already drafted)
12. `chore(landing): wire logo + .gitignore for www/ + build output`
10. `feat(landing): Astro+TS onboarding site → www/`
11. `chore(landing): wire logo + .gitignore for www/`
## Phase 6 — launcher distribution
13. `feat(tooling): add fetch-launcher.sh (all platforms + stable symlinks)`
12. `feat(tooling): add fetch-launcher.sh (all platforms + stable symlinks)`
## Phase 7 — full client air-gap (chosen path, plan/11)
14. `feat(tooling): add mirror-airgap.sh (capture + fetch + sha1 verify)`
15. `feat(dnsmasq): add air-gap spoof records for upstream hosts`
16. `feat(caddy): add tls internal vhosts for upstream mirror hosts`
## 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 + orchestration
17. `feat(compose): add mc-backup service (RCON, 6h)`
18. `feat(tooling): add build-stack.sh orchestrator`
## Phase 8 — backups
16. `feat(compose): add mc-backup service (RCON, 6h)`
## Phase 9 — operational (no commits)
- [ops] Run `build-stack.sh --prep` online: render configs, build landing,
mirror mods, mirror air-gap, fetch launcher, **pre-bake** server volume.
- [ops] Offline acceptance test: clean machine, internet cut, LAN DNS = dnsmasq,
Caddy CA trusted → install Fjord, import pack, join.
- [ops] If green: tag `v1-lan-ready`.
## 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 10 — operational (no commits)
- [ops] Prep online (once): `tooling/render-config.sh`, build landing
(`cd landing && pnpm run build`), `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
- Items 35 can be smoke-tested (`docker compose up dnsmasq caddy`) before later
phases exist — Caddy serves a 404/landing, dnsmasq resolves.
- Items 1416 depend on a working online launch to capture the URL set first.
- 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).