Guided Build Lab — Phase 32: Docker
Purpose
Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.
Deliverable
Dockerfiles and compose/dev verification that build and run TaskFlow services from clean inputs.
Before you touch the code
Open the previous phase checkpoint, run the repository's verification commands, and make sure Git is clean. A guided lab is useful only when you know which change introduced a failure. Write down the current browser/API/database behavior you expect before modifying anything.
Architecture trace
source + lockfile -> build context -> dependency/build stages -> runtime image -> container process -> network/healthcheck -> orchestrator
Read this flow left to right, then right to left. For each arrow, say what data crosses the boundary, which side trusts the other, and what evidence would prove that this boundary works. This habit prevents framework APIs from becoming disconnected memorization.
Step 1 — Write a .dockerignore first so local node_modules, Git history, secrets, and build output do not enter context.
Do the smallest version of this step first. After the change, stop and verify it before continuing. Use terminal output, HTTP responses, browser DevTools, tests, or database inspection depending on the boundary. If the result differs from your prediction, do not add more code; explain the mismatch and fix the earliest failing assumption.
Step 2 — Create a multi-stage API Dockerfile separating dependencies/build/runtime artifacts.
Do the smallest version of this step first. After the change, stop and verify it before continuing. Use terminal output, HTTP responses, browser DevTools, tests, or database inspection depending on the boundary. If the result differs from your prediction, do not add more code; explain the mismatch and fix the earliest failing assumption.
Step 3 — Build with frozen lockfile and inspect image layers/size.
Do the smallest version of this step first. After the change, stop and verify it before continuing. Use terminal output, HTTP responses, browser DevTools, tests, or database inspection depending on the boundary. If the result differs from your prediction, do not add more code; explain the mismatch and fix the earliest failing assumption.
Step 4 — Run the container with runtime env vars and map the service port explicitly.
Do the smallest version of this step first. After the change, stop and verify it before continuing. Use terminal output, HTTP responses, browser DevTools, tests, or database inspection depending on the boundary. If the result differs from your prediction, do not add more code; explain the mismatch and fix the earliest failing assumption.
Step 5 — Add healthcheck/readiness behavior and test startup plus graceful stop.
Do the smallest version of this step first. After the change, stop and verify it before continuing. Use terminal output, HTTP responses, browser DevTools, tests, or database inspection depending on the boundary. If the result differs from your prediction, do not add more code; explain the mismatch and fix the earliest failing assumption.
Step 6 — Create a small compose setup only for local integration needs and explain what remains externally managed.
Do the smallest version of this step first. After the change, stop and verify it before continuing. Use terminal output, HTTP responses, browser DevTools, tests, or database inspection depending on the boundary. If the result differs from your prediction, do not add more code; explain the mismatch and fix the earliest failing assumption.
Useful verification commands
docker build -t taskflow-api:dev .
docker run --rm -p 4000:4000 --env-file .env taskflow-api:dev
docker ps
docker logs <container>
docker inspect <container>
Do not run commands mechanically. Before each command, predict what successful output should prove. If it fails, capture the exact message and identify whether the failure is environment, dependency, compile-time, runtime, network, authorization, or persistence related.
Checkpoint
When the lab works, inspect git diff. Remove accidental debugging output and unrelated edits. Run type checking/tests/build commands relevant to this phase. Commit the checkpoint with a message that describes the capability added, not merely the files changed.
Explain-back
Without looking at the lesson, explain why each layer in the architecture trace exists, what this phase added to TaskFlow, and what would break if the new responsibility were moved to the wrong layer. If you cannot explain the boundary, repeat the trace before moving on.