Run a dev stack beside production, and write both flows down #72
No reviewers
Labels
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente!72
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-69-dev-environment"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #69.
dev.ponente.appis a second stack on the production server — its own app, PDS, database, volumes and encryption key — running whatever is onmain. It is already up and verified; this PR is the tooling and the write-up behind it.Verified on the server
https://dev.ponente.app/healthzCN=dev.ponente.appissued by Let's Encrypt on first handshakehttps://pds.dev.ponente.app/xrpc/_healthv2.3.0,Up 10 daysRole=1alice.dev.ponente.app→ 404 at the dev PDS (0 hits on production's)dotnet testThe handle check is the one that matters: a missing
Hostrewrite 404s identically, so this was confirmed from the dev PDS's own request log rather than the status code.Nobody deploys dev
Merging a PR publishes
ponente-kanban:main; a systemd user timer on the host recreates the dev app container within a minute,--no-depsso the database and PDS keep running.CI cannot push that update, and this was measured rather than assumed. Jobs run inside the dind daemon, and a container on the host's rootless podman cannot open a connection to the host's own public address on port 22 — 443 through Caddy works, which is exactly why it looks like SSH should. The mechanism that can reach in is mounting the podman socket into a Watchtower-style container, which hands that container every container on the host, production included. A minute of latency is the better trade, so the direction is inverted and the host asks the registry.
update.shrefuses anyIMAGE_TAGmatchingv[0-9], so the timer can never move production.One compose file, not a fork
STACK_NAMEnames the compose project and therefore the containers, network and volumes.podman-compose configagainst the production env renders byte-identical to before, plus an emptyAllowlist__Admins__1thatSeedAdminsAsyncalready drops. A production redeploy from this branch is a no-op change.Host-side changes, outside the repo
/home/podman/caddy/ask.Caddyfilegained the three dev site names and a.dev.ponente.apphandler above the.ponente.appone — the deeper suffix matches bothendsWithtests andhandleblocks run in written order, so production's PDS would otherwise be asked about a dev handle and correctly say no. Validated withcaddy validatebefore installing, and the previous file is atask.Caddyfile.bak-pre-dev. Caddy picked it up on the dev deploy's container events; no restart, which would have dropped every other project's sites.Nothing else on the host changed. No DNS was needed — the registrar's
*.ponente.appwildcard answers at any depth.Documentation
deploy/README.mdis the runbook: both flows, first-time setup, theask.Caddyfilecontent, and the three container naming schemes.README.mdandCLAUDE.mdpoint at it.The release skill's Phase A no longer builds a stack for hand-testing — dev has held
mainsince each merge, so Phase A confirms rather than produces. That also retires the "don't run the e2e suite while testing by hand" warning: the suite runs against the local stack and can no longer collide with anyone.Two smaller fixes found on the way
check-env-keys.shmatched keys with[A-Z_]+, soADMIN_DID_2and any other name containing a digit were silently skipped — a key missing everywhere and reported nowhere. It also takes--env devnow..gitignorematched.envexactly, leavingdeploy/.env.devand thedeploy/.env.baksomebody makes before editing a secret untracked but not ignored, onegit add -Afrom being committed.Worth knowing
Mail from dev is real mail and accounts minted on its PDS are real Atmosphere identities on
plc.directory. That is the point — those paths reached production unexercised before — but it is stated in bothdeploy/README.mdand the release skill so it is never a surprise.🤖 Generated with Claude Code
🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
✅ Verdict: approve — no blocking issues found.
This is a thorough, well-reasoned change. I traced the argument parsing and env-file handling in
deploy.sh/check-env-keys.sh/update.shend to end, checked the.gitignorenegation patterns against the specific files they're meant to catch (.env,.env.dev,.env.bak,.env.dev.example), and verifiedSeedAdminsAsyncreally does drop blank/non-did:entries the wayADMIN_DID_2's comment anddeploy/docker-compose.prod.ymlassume — all consistent with the claims in the PR description. TheSTACK_NAME/container_nameparameterization in the compose file is a straightforward variable substitution of an already-working mechanism, so it shouldn't regress production. The systemd auto-update timer, the CI publish-on-main change (with the bash -e-safeifinstead of&&), and theask.Caddyfileordering rationale all check out.One thing not covered by anything in the diff or the verification table: whether the server user has
loginctl enable-lingerset, which is what lets asystemd --usertimer keep running without an active login session. Given the PR states the timer is already "active, 60 s cadence" on the live server, this is presumably already handled outside the repo — worth a one-line mention indeploy/README.md's troubleshooting section for the next person who tries to reproduce this setup on a different host, but not a blocker.No correctness or security issues found in the shell scripts, workflow YAML, or compose changes.
⏱ 2m 46s · 17 turns · tokens: 90.3k in / 13.0k out (+1716.2k cache-read)
📜 Full session transcript