#100 — Local Review Environment — Hot-Reload Dev Loop + Seeded Playground #99
Labels
No labels
priority/could
priority/must
priority/should
priority/wont
status/blocked
status/claimed
status/done-migrated
type/bug
type/feature
type/infra
type/tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
robert/todo#99
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Story
#100: Local Review Environment — Hot-Reload Dev Loop + Seeded PlaygroundAs a developer (human) reviewing what the agent team just built,
I want to see a feature working in a running app within seconds of it landing on
master, against adatabase that already has realistic data in it,
so that I don't have to wait on the full CI pipeline (build, test, 4-leg Playwright matrix, Docker
image, redeploy) just to look at something, and a red e2e leg doesn't block me from reviewing at all.
Background
Reviewing a feature today means waiting for
masterto go through Gitea CI end-to-end and then pulling anew image to
todo.moekies.de— slow, and doubly so when an e2e leg goes red, since there is currently noway to look at the app without going through that whole pipeline.
Most of the pieces already exist:
docker-compose.dev.ymlalready gives a persisted Postgres + Redis (named volumetodo_dev_postgres)behind a
devboxcontainer with the full toolchain (docs/dev-container.md).MigrationService/Worker.csandCqsTodo/Setup.csalready seed an idempotent test account(
testuser/geheim123!) with one list/todo on every startup — but the two copies of that seed logic areindependently maintained (flagged in a comment on
Worker.cs), and the seed itself is bare-minimum (justenough to satisfy foreign keys), not really "data to play around with."
#33(the dev container itself) explicitly scoped hot-reload out: "Hot-reload configurationinside the container (developers can set this up manually)."
docs/dev-container.mdstill documentsdotnet run(notdotnet watch), i.e. a manual restart per change.This story closes those two gaps: a genuinely fast local loop (hot reload, not rebuild-and-redeploy) and a
seed dataset worth clicking around in — decoupled entirely from CI/e2e status.
Resolved during PO discussion (2026-08-07) — see
docs/roadmap.mdDecisions Log for the full reasoning:The review instance is just kept ready so a human can look, on their own time.
restricted sandbox with no Docker at all (verified: no
dockerbinary), and, on other days, directlyon the human's own Linux or Windows machine with full Docker access (Docker Desktop on Windows, Docker
Engine on Linux). The story must work in both, degrading gracefully rather than failing when Docker isn't
reachable.
convenience step at the end of a cycle — never blocking on it, never failing the cycle if it can't.
exactly as on Linux; only the outer process that runs the backend/frontend differs by OS, not the
database story.
Acceptance criteria
Hot-reload dev loop
docs/dev-container.mddocumentsdotnet watch --project CqsTodo.WebApi --urls http://+:5000(inplace of the current
dotnet run) and the already-hot-reloadingnpm run devas the standard way toreview work — start once, leave running, refresh the browser after each change lands.
that has the .NET 10 SDK and Node 22 installed natively — against
db/redisstarted standalone viadocker compose -f docker-compose.dev.yml up -d db redis(nodevboxcontainer required). Both pathspoint at the same named Postgres volume, so review data doesn't reset depending on which way a given
cycle happened to run.
docs/dev-container.mdgets a short "bare host" section covering both OSes (commands only —dotnet,npm,docker composeare all cross-platform; no OS-specific scripting needed).Docker socket proxy (scoped container access from inside the devbox)
docker-proxyservice is added todocker-compose.dev.ymlusingtecnativa/docker-socket-proxy.It mounts the host Docker socket read-only and exposes a filtered HTTP API on
tcp://docker-proxy:2375inside the
devnetwork. Only theCONTAINERSandPOSTpermissions are enabled; everything else(images, volumes, networks, build, exec, etc.) defaults to denied.
DOCKER_HOST=tcp://docker-proxy:2375in its environment so thatdockerCLI callsinside the container reach the proxy, not the raw socket. The existing raw-socket mount
(
/var/run/docker.sock) is retained as-is for Testcontainers — it connects via the socket pathdirectly and is unaffected by the
DOCKER_HOSTenv var.docker restart <container>anddocker start <container>for containers in the
todo_devcompose project (e.g.todo_dev-db-1,todo_dev-redis-1), butcannot create, delete, or build containers, cannot access volumes or images, and cannot exec into
containers. Verified by attempting a denied operation and confirming it is rejected by the proxy.
docs/dev-container.mdwith a note on what is and isn't permitted.Autonomous, non-blocking lifecycle management
Claude Code checks whether Docker is reachable in its current environment (
docker infoor equivalent).If not (e.g. in the restricted sandbox), it skips this step silently and moves on — the cycle is
unaffected either way.
db/redisvia the proxy as a convenience step(e.g. to pick up a migration after a schema change). This must be idempotent — running it against an
already-running stack must not error.
welcome, never required.
Seed data
CqsTodo/Setup.csandCqsTodo.MigrationService/Worker.cs) are consolidated into one shared method —MigrationServicealready project-references
CqsTodo, so there's no reason for two copies to drift.testuseraccount: a second list with its own category, a few todos in a mix of done/open states, oneshopping list with a couple of products, and one recurring todo. Login stays
testuser/geheim123!— nothing about how you log in changes.
Out of scope for this story
ci.yml), the productionDockerfile/docker-compose.yml, or thetodo.moekies.dedeployment — this story is purely about the local review loop; CI stays the release gatefor the Docker image.
this story must not introduce anything a human has to acknowledge before the loop continues.
Windows, Engine on Linux) is assumed available whenever the bare-host path is used; if it genuinely isn't
on a given machine, that machine simply doesn't get this feature yet.
#33and isunchanged by this story.
Email__Mode=logetc.unchanged.
todo_devcompose project's containers specifically. Thesocket proxy filters by Docker API endpoint type, not by container label or name — Claude could
technically restart any container visible to the daemon via the proxy, not just the stack's own ones.
Accepted: on a personal dev machine this is a low-risk gap, and the alternative (a custom control sidecar)
would require maintaining custom code. If a second stack runs on the same host and isolation matters, that
should be revisited then.
Open questions
None outstanding. The environment/ownership questions this story originally needed a human for were resolved
directly in the 2026-08-07 PO discussion (see Background above and the matching Decisions Log entry in
docs/roadmap.md) before this story was drafted.