Add a static /register page (en/es/eu) that calls the Drasl REST API v2 directly from the browser: register -> login -> optional skin upload, all in the pixel design. Guests never touch Drasl's own web UI. Drasl config gains the pieces this needs: - CORSAllowOrigins scoped to the apex (the API has no CORS until set; never "*"). - [RateLimit] for the now public-facing anonymous POST /users. - [RegistrationNewPlayer] with RequireInvite driven by a new REGISTRATION_MODE (invite|open) .env flag. REGISTRATION_MODE has two consumers from one key: render-config.sh derives the TOML boolean for Drasl (drasl is TOML-only, no env), and the landing build reads it to show/hide the invite-code field. render-config.sh halts on any value other than invite/open. Security verified against drasl source: anonymous POST /users cannot set privileged fields (isAdmin/isLocked/chosenUuid/maxPlayerCount are gated on callerIsAdmin in CreateUser), so browser-direct registration is safe. Docs: plan/16-landing-registration.md captures the design + the B1 vs fork decision; build-order, deploy, and the deploy skill wire REGISTRATION_MODE and the landing-rebuild requirement (www/ is gitignored, not updated by a git pull). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.9 KiB
2.9 KiB
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
chore: baseline scaffolding— CLAUDE.md, plan/, docker-compose.yml, runtime/, .gitignore, .env.example.
Phase 1 — config foundation
feat(env): add BASE_DOMAIN + RCON_PASSWORD + CADDY_* to .env.examplefeat(tooling): add render-config.sh (envsubst BASE_DOMAIN, halt on unset)
Phase 2 — ingress (caddy internal router)
feat(caddy): add conf.d snippets (00-core auth+pack, 10-static apex+launcher)feat(compose): add caddy service (127.0.0.1:CADDY_HTTP_PORT) + network aliases
Phase 3 — auth
feat(drasl): add config.toml.tmpl (password login, SignPublicKeys=false)refactor(compose): drasl internal-only behind caddy; authlib URL → auth.
Phase 4 — modpack
feat(pack): packwiz init + initial mod curationfeat(tooling): add render-pack.sh + add-custom-mod.shrefactor(compose): minecraft via PACKWIZ_URL
Phase 5 — landing
feat(landing): Astro+TS onboarding site → www/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; see16-landing-registration.md).
Phase 6 — launcher distribution
feat(tooling): add fetch-launcher.sh (all platforms + stable symlinks)
Phase 7 — extra services
feat(avatar): add nmsr service (Drasl-backed) + 40-avatar.caddyfeat(status): add uptime-kuma service + 50-status.caddyfeat(distribution): add 30-distribution.caddy (static, another repo)
Phase 8 — backups
feat(compose): add mc-backup service (RCON, 6h)
Phase 9 — production ingress / TLS
feat(nginx): add ulicraft-caddy.conf.tmpl + render-nginx.shfeat(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 && set -a && . ../.env && set +a && pnpm run build— sources.envsoBASE_DOMAIN+REGISTRATION_MODEbake into the static output),tooling/fetch-launcher.sh, fetch authlib-injector intoruntime/. - [ops] TLS:
tooling/issue-letsencrypt.sh, thentooling/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).