Course navigationPhase 32
Volume 08 · Phase 32

Docker

Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.

16lessons + labs
3klesson words
10source references
What you will ship

Phase outcome and project increment

Learning outcome

Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.

Concrete deliverable

Dockerfiles and compose/dev verification that build and run TaskFlow services from clean inputs.

Figure 32.1 — Where this phase lives in TaskFlow
source + lockfile
build context
dependency/build stages
runtime image
container process
network/healthcheck
orchestrator
Trace the flow left-to-right for implementation and right-to-left for debugging. At every arrow, ask what data crosses the boundary and what proves it is trustworthy.
Instructor mental model

Principles to keep while coding

01

A Dockerfile should produce a repeatable image from declared inputs rather than depend on a developer machine.

02

Use multi-stage builds to keep runtime images smaller and separate build-time tools from production dependencies.

03

Do not bake secrets into images; inject runtime configuration through the deployment environment.

04

Health checks and graceful shutdown help orchestrators know when a container is ready and when it should be replaced.

Code-along path

Guided phase lab

Do these in order. Each step should end with evidence before the next one starts.

  1. 01

    Write a .dockerignore first so local node_modules, Git history, secrets, and build output do not enter context.

  2. 02

    Create a multi-stage API Dockerfile separating dependencies/build/runtime artifacts.

  3. 03

    Build with frozen lockfile and inspect image layers/size.

  4. 04

    Run the container with runtime env vars and map the service port explicitly.

  5. 05

    Add healthcheck/readiness behavior and test startup plus graceful stop.

  6. 06

    Create a small compose setup only for local integration needs and explain what remains externally managed.

TerminalVerification 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>

Predict what each command proves before running it. A command is useful only when its output answers a question.

Debugging studio

Failures you should know how to diagnose

Failure drill 1

Copying .env into image

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 2

Running development server in production container

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 3

Huge build context invalidating caches

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Failure drill 4

Container listens only on localhost internally

Predict the symptom, capture evidence at the nearest boundary, change one variable, and verify the same reproduction after the fix.

Watch-order style

Lessons

The source chapters come first. Every phase now ends with a guided build, a debugging workshop, and an independent challenge so reading turns into transferable skill.

01

Container Mental Model Images Layers and Processes

Container Mental Model: Images, Layers, and Processes Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, o

2 min
02

Dockerfile Multi Stage Builds and Cache Design

Dockerfile Design: Multi-Stage Builds and Cache Efficiency Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secre

2 min
03

Monorepo pnpm and Turborepo Build Context

Monorepo, pnpm, and Turborepo Build Context Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business

2 min
04

Next.js Standalone Production Image

Next.js Production Image with Standalone Output Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busi

2 min
05

NestJS API Production Image

NestJS + Fastify Production Image Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business responsib

2 min
06

Non Root Runtime and Image Hardening

Non-Root Runtime and Image Hardening Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business respon

2 min
07

Environment Variables Secrets and Build Time Config

Environment Variables, Secrets, and Build-Time Configuration Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, sec

2 min
08

Healthchecks Graceful Shutdown and Readiness

Health Checks, Graceful Shutdown, and Readiness Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busi

2 min
09

Docker Compose Local Integration Environment

Docker Compose for Local Integration Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business respon

2 min
10

Migrations Volumes and Stateful Service Rules

Migrations, Volumes, and Stateful-Service Rules Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busi

2 min
11

Image Testing Debugging and Common Failures

Image Testing, Debugging, and Common Failures Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or busine

2 min
12

Hands On Lab and Phase Exit

Hands-On Lab and Phase Exit Full Stack Developer 2026 - TaskFlow Phase 32 objective: containerize the existing architecture without moving durable state, secrets, or business responsibilitie

2 min
LAB

Guided Build Lab

Purpose Containerize the production API/web artifacts reproducibly with secure runtime configuration, small images, health checks, networking, and graceful shutdown.

3 min
LAB

Debugging Workshop

Goal Learn to diagnose this phase's failures systematically instead of reinstalling packages, changing random configuration, or copying a fix without understanding it.

2 min
LAB

Phase Synthesis & Independent Challenge

Mission Rebuild the capability of Phase 32 without following the exact code line-by-line. The goal is transfer: can you use the ideas when the variable names, UI, or route shape changes?

2 min
LAB

Mastery Capstone Lab

Integrate Phase 32 without following a transcript.

2 min
Practice ladder

Exercises that increase independence

Guided

Write a .dockerignore first so local node_modules, Git history, secrets, and build output do not enter context.

Practice

Build with frozen lockfile and inspect image layers/size.

Debug

reproduce and diagnose — Copying .env into image.

Independent

deliver Dockerfiles and compose/dev verification that build and run TaskFlow services from clean inputs.

Explain-back

Can explain image vs container and Can build multi-stage image.

Mastery gate

Do not leave the phase only because you reached the bottom

Phase exit criteria

Knowledge check

Scenario and concept quiz

These questions test engineering choices rather than whether you remember a lesson title.

0/0 correct · 0/8 answered
01Which practice best matches Phase 32's engineering goal?
02Which practice best matches Phase 32's engineering goal?
03Which practice best matches Phase 32's engineering goal?
04Which practice best matches Phase 32's engineering goal?
05You are working through the Phase 32 lab. Which next action is the most disciplined step?
06You are working through the Phase 32 lab. Which next action is the most disciplined step?
07You are working through the Phase 32 lab. Which next action is the most disciplined step?
08You are working through the Phase 32 lab. Which next action is the most disciplined step?
Source snapshot

Reference files

Attempt the work first. Use snapshots to compare a checkpoint, not as a substitute for understanding.

reference/TaskFlow_Docker_Snapshot/.dockerignore
# Git / editor
.git
.github
.vscode
.idea

# local dependencies and outputs
**/node_modules
**/.next
**/dist
**/coverage
**/playwright-report
**/test-results

# secrets / local config
.env
.env.*
!.env.example

# misc
reference/TaskFlow_Docker_Snapshot/README.md
# TaskFlow Docker Snapshot

This is a teaching/reference snapshot for Phase 32. Adapt paths to the exact final repository layout before production use.

Production architecture keeps managed Supabase services external. `compose.yaml` uses local PostgreSQL only to demonstrate a repeatable local integration topology.
reference/TaskFlow_Docker_Snapshot/SOURCES.md
# Official sources used for Phase 32

- Docker multi-stage builds: https://docs.docker.com/build/building/multi-stage/
- Docker build best practices: https://docs.docker.com/build/building/best-practices/
- Docker build cache: https://docs.docker.com/build/cache/optimize/
- Docker Compose startup/readiness: https://docs.docker.com/compose/how-tos/startup-order/
- Next.js standalone output: https://nextjs.org/docs/app/api-reference/config/next-config-js/output
reference/TaskFlow_Docker_Snapshot/VERSION_LOCK.md
# Phase 32 version line

- Node runtime image: Node 24 LTS line (`node:24-bookworm-slim`)
- pnpm: 12.3.4 (course lock)
- PostgreSQL local integration image: 18-alpine
- Next.js: existing course lock (16.x) with `output: "standalone"`
- NestJS: existing course lock (12.x)
- Prisma: hard lock 7.9.1

Docker Desktop / Engine / Compose are environment tools rather than npm dependencies. Validate current stable releases on the machine used for the course.
reference/TaskFlow_Docker_Snapshot/apps/api/Dockerfile
# syntax=docker/dockerfile:1.7
FROM node:24-bookworm-slim AS base
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
RUN corepack enable && corepack prepare pnpm@12.3.4 --activate
WORKDIR /workspace

FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/api/package.json apps/api/package.json
COPY packages packages
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
    pnpm install --frozen-lockfile

FROM deps AS builder
COPY . .
RUN pnpm --filter api exec prisma generate
RUN pnpm --filter api build
RUN pnpm --filter api deploy --prod /out/api
reference/TaskFlow_Docker_Snapshot/apps/web/Dockerfile
# syntax=docker/dockerfile:1.7
FROM node:24-bookworm-slim AS base
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
RUN corepack enable && corepack prepare pnpm@12.3.4 --activate
WORKDIR /workspace

FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/web/package.json apps/web/package.json
COPY packages packages
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
    pnpm install --frozen-lockfile

FROM deps AS builder
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm --filter web build

FROM node:24-bookworm-slim AS runner
reference/TaskFlow_Docker_Snapshot/apps/web/next.config.phase32.ts
import path from "node:path";
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "standalone",
  outputFileTracingRoot: path.join(__dirname, "../.."),
};

export default nextConfig;
reference/TaskFlow_Docker_Snapshot/infra/compose.yaml
name: taskflow

services:
  db:
    image: postgres:18-alpine
    environment:
      POSTGRES_DB: taskflow
      POSTGRES_USER: taskflow
      POSTGRES_PASSWORD: taskflow_local_only
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U taskflow -d taskflow"]
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 10s
    volumes:
      - taskflow-db:/var/lib/postgresql/data

  api:
    build:
reference/TaskFlow_Docker_Snapshot/infra/migration-runbook.md
# Migration runbook

Production rule: run `prisma migrate deploy` once as an explicit deployment/release step before new API replicas begin serving traffic. Do not run it independently in every replica startup command.

Local example from the repository root:

```powershell
pnpm --filter api exec prisma migrate deploy
```

For a fully containerized local workflow, build a dedicated migration target/job that includes Prisma CLI and the schema, waits for PostgreSQL readiness, runs once, and exits successfully.
reference/TaskFlow_Docker_Snapshot/tests/docker-test-matrix.md
# Phase 32 verification matrix

- [ ] `docker build` succeeds for web with the committed lockfile.
- [ ] `docker build` succeeds for api with the committed lockfile.
- [ ] Runtime processes run as non-root users.
- [ ] Production images do not contain `.env`, `.git`, local `node_modules`, or source test output.
- [ ] Web container serves the production Next.js build on port 3000.
- [ ] API container serves `/health/live` on port 3001.
- [ ] API readiness fails when PostgreSQL is unavailable and recovers when PostgreSQL is ready.
- [ ] `docker compose up` uses `db` service DNS instead of localhost for API database access.
- [ ] Database state survives recreation of the db container when the named volume remains.
- [ ] SIGTERM produces a graceful NestJS shutdown.
- [ ] Rebuilding after a source-only change reuses dependency-install cache.
- [ ] Secrets are injected at runtime and not visible in image history.