In this chapter
We'll learn to read the files that build, package and ship a project — package.json scripts and the build system, Dockerfiles, docker-compose, CI/CD workflows and deployment files — explained as a house's construction plans and moving instructions.
The Problem in Real Life
Anna opens .github/workflows/ci.yml. It runs lint and tests on every pull request — good. At the bottom, there's a deploy: job — every line of it commented out with #, and a note: # deploy manually for now (Mark, 2023).
"So how does it get to production now?" she asks. John checks the cloud console: the dashboard still runs as one old VM — deployed by hand, three years ago, and redeployed by hand twice since. "Remember Act 19?" he says. "Let's fix that while we're here."
The build files tell you how the project really lives — not how anyone remembers it.
John
Guessing How It's Built and Shipped vs. Reading the Instructions
"How do I run this?"
Without docs, the build and deployment files are the only reliable instructions.
Old versions everywhere
A Node 16 Dockerfile and a commented-out deploy job — the project has drifted.
Different paths to production
The main app ships through the pipeline; this one by hand. That's how incidents happen.
Build Systems, Dockerfiles, docker-compose, CI/CD and Deployment Files
The construction plans analogy: if nobody remembers how a house was built, the construction plans in the drawer tell you — the materials, the order of work, the inspections. The moving instructions tell you how everything gets into the house. A project's build and deployment files are those plans: they're executed by machines, so unlike a forgotten wiki page, they're usually true.
- package.json scripts — the short list of jobs:
npm run dev(start for development),npm start(start in production),npm test,npm run build,npm run lint. Readingscriptstells you every command the project expects you to use. Here,backendhas"start": "node server.js"— the entry point, confirmed. - Build system — turning source into something runnable: the build step (Act 19) transforms code: the frontend's
vite buildbundles React into small static files infrontend/dist/; TypeScript projects compile to JavaScript; Java projects use Maven or Gradle. Look for thebuildscript and the tool's config file (vite.config.js,tsconfig.json,webpack.config.js). - Dockerfile — the recipe for the container (Act 21): read it top to bottom:
FROM node:16(the Node version — old!),COPYandRUN npm ci(dependencies),EXPOSE 4000(the port),CMD ["node", "server.js"](the entry point, confirmed a second time). - docker-compose.yml — the whole house in one command: describes several containers that run together locally: here
postgres,backendandfrontend, with their ports, environment variables and volumes (Act 21).docker compose upstarts everything a developer needs. It's often the best "how to run this locally" documentation a project has. - CI/CD workflow files — the inspection and delivery plan (Act 19):
.github/workflows/*.yml(GitHub Actions),.gitlab-ci.yml,Jenkinsfile. They show which checks run on each pull request and how (or whether) the project is deployed. Here: lint and tests run; deploy is commented out. - Deployment files — where it ends up: Infrastructure as Code (Act 20,
infrastructure/*.tf), Kubernetes manifests (Act 21,k8s/*.yaml), platform configs (vercel.json,Procfile,app.yaml). They tell you where the app runs in production and with which settings. Here: none — which is how it ended up as a hand-deployed VM.
| File | Plans version | Tells you | In organiser-dashboard |
|---|---|---|---|
| package.json scripts | List of jobs | Commands to start, test, build | start: node server.js |
| vite.config.js / tsconfig.json | Build method | How source is transformed | Frontend built to dist/ |
| Dockerfile | Container recipe | Runtime version, port, start command | node:16, port 4000 |
| docker-compose.yml | Whole-house setup | Everything needed to run locally | postgres + backend + frontend |
| .github/workflows/ci.yml | Inspection and delivery plan | Checks and deployment | Lint + test; deploy commented out |
| Terraform (.tf), Kubernetes YAML, vercel.json | Where it lives | Production infrastructure | None — hand-deployed VM |
# DockerfileFROM node:16 # old Node version (issue opened)WORKDIR /appCOPY backend/package*.json ./RUN npm ciCOPY backend/ .EXPOSE 4000CMD ["node", "server.js"] # the entry point# docker-compose.ymlservices:postgres:image: postgres:15environment: { POSTGRES_PASSWORD: devpassword }ports: ["5432:5432"]backend:build: .env_file: .envports: ["4000:4000"]depends_on: [postgres]frontend:build: ./frontendports: ["5173:5173"]
Anna's findings and plan: (1) Node 16 is out of support — the counter change will be small, so she won't upgrade Node in the same PR (one idea per PR, Act 24), but she opens an issue for it with the evidence. (2) The deploy job is dead — John will move the dashboard onto the same container platform and pipeline as the main app (Acts 19–21) after Sale Day, not two weeks before it. Until then, they agree to deploy it once more by hand, carefully, with a written checklist. (3) docker-compose.yml looks like the fastest way to run it locally — she'll try that next.
Key Takeaway
Build and deployment files are the project's construction plans and moving instructions — and because machines run them, they're usually true. Read package.json scripts for the commands (and the entry point), the build config for how source becomes runnable, the Dockerfile for runtime version, port and start command, docker-compose.yml for everything needed to run locally, CI workflows for checks and deployment, and IaC or Kubernetes files for where it runs in production.
Why This Matters
The build, Docker and CI files are the most reliable documentation a project has, because they actually run. Reading them tells you how to start a project, which versions it needs, what checks protect it and how it reaches production — and spotting drift like an old runtime or a manual deploy is how you prevent the next incident.
Anna has a map, the hidden systems and the build files. Now she needs a reliable way to read the code itself — without getting lost in it.
