Interview Bank · 2026
The practical slice — Git, Docker, environments, deploys, and CI/CD. Just enough to ship your capstone and talk through it without flinching. Say each answer aloud before you reveal it.
Click a card. Answer first, in one breath, then reveal.
Dockerfile?FROM, COPY, RUN, CMD) that builds an image — your app packaged with its environment..gitignore?node_modules, .env, build output. Keeps junk and secrets out of the repo.main.DATABASE_URL, API keys) — different per environment, never hard-coded.docker compose up starts the whole stack.Keep main always deployable. Branch off it per feature (feat/upload-docs), commit in small steps, open a pull request, let CI run, get a review, then merge — usually a squash-merge for a clean history. For a solo capstone, "branch → PR → merge into main, which auto-deploys" is plenty. Avoid committing straight to main.
An image is the built artifact; a container is a running instance of it. The image is made of stacked, cached layers — one per build step. Layers are shared and reused, so a small code change only rebuilds the layers after it. That's why layer ordering in a Dockerfile matters for build speed.
Locally: a .env file that's git-ignored, loaded by the framework. In production: set them in the host's dashboard (Vercel/Render env vars) or a secrets manager — never in the repo. Commit a .env.example with keys but no values so others know what's needed. Secrets are injected at runtime, not baked into the image.
Roughly: checkout → install deps → lint → test → build → deploy. CI runs on every push/PR and fails fast if a step breaks. CD takes a green build and ships it — to a preview URL on a PR, to production on merge to main. Each stage gates the next, so broken code never reaches users.
A frontend (Next.js) goes to a platform like Vercel/Netlify — it builds, serves static assets from a CDN, and runs any serverless functions; you mostly just connect the repo. A backend (FastAPI) needs a long-running process, so it goes to a container host (Render, Railway, Fly) — you give it a Dockerfile or start command, a port, and env vars.
A managed Postgres (Neon, Supabase, RDS) handles backups, patching, failover, and connection pooling for you — you get a DATABASE_URL and connect. For a capstone and most teams, that's strictly better than babysitting a DB server. You trade a little cost and control for reliability and zero ops.
Keep deploys immutable and versioned so you can redeploy the previous build instantly — most hosts have a one-click "promote previous deployment." Database migrations are the hard part: make them backward-compatible (additive) so old code still runs, and never drop a column the live version still reads. Roll back code freely; roll back schema carefully.
Start with the host's log stream — your app should log structured lines (level, timestamp, request id) so you can trace a request. Add an uptime/health check (a /health endpoint pinged on a schedule) and watch error rate and latency. You don't need a full observability stack for a capstone; you do need to find why a 500 happened quickly.
A VM virtualises hardware and runs a full guest OS — heavy, slow to boot, strongly isolated. A container virtualises the OS: it shares the host kernel and packages just your app plus its libraries — lightweight, starts in milliseconds, dense. Containers won by being fast and reproducible; VMs still matter where you need full isolation or a different kernel.
A set of principles for building portable, deploy-friendly services. The one interviewers love: store config in the environment, not in code — so the same build runs in dev, staging, and prod by swapping env vars. Others: treat backing services as attached resources, run as stateless processes, and ship logs to stdout. It's the mental model behind why .env and managed databases exist.
You never patch a running server in place — you build a new image and replace it. Each deploy is a fresh, identical artifact, so there's no config drift and rollback is just "run the old image." Containers make this the default. It kills the "works on that one server" class of bugs.
Blue-green: run two identical environments, flip all traffic from old (blue) to new (green) at once — instant rollback by flipping back. Canary: route a small slice (say 5%) of traffic to the new version, watch metrics, then ramp up if it's healthy. Blue-green is simpler; canary limits blast radius. Both avoid the all-or-nothing risk of an in-place deploy.
If a service keeps no local session state, any request can hit any instance — so you just add more instances behind a load balancer to handle load. State lives in a shared database or cache, not in the process. The moment a service stores session in memory, you're stuck (sticky sessions, hard to scale). Stateless = scale by copy-paste.
First, rotate the key — assume it's already compromised the moment it hit a remote. Just deleting the file in a new commit does not remove it: it's still in the history and on anyone's clone. To truly purge it you'd rewrite history (git filter-repo / BFG) and force-push, but rotation is the real fix. Then add it to .gitignore so it can't happen again.
Three moves: start from a slim/alpine base instead of the full OS image; use a multi-stage build so build tools stay in an earlier stage and only the runtime artifact ships; and add a .dockerignore so node_modules, .git, and tests never enter the build context. A 1.2 GB image often drops under 200 MB.
Almost always the allowed origin is wrong. Your backend allows http://localhost:3000, but the deployed frontend is https://app.example.com — different scheme/host, so the browser blocks it. Fix: set allowed origins from an env var and include the real production URL (and watch trailing slashes / https).
Usual culprits: it's not actually loaded (no .env in that environment, or the loader isn't called), it's set in the wrong scope (build-time vs runtime — e.g. Next.js needs NEXT_PUBLIC_ for client-side vars), or the app needs a rebuild/redeploy to pick up the new value. Log the var (masked) on boot to confirm what the process actually sees.
Put the things that change least first. Copy the dependency manifest (requirements.txt / package.json) and install deps before copying your source code. Then editing app code only busts the final layer, and the slow dependency install stays cached. Copying everything first means every code change reinstalls everything.
The common stack: frontend on Vercel/Netlify, the API on a container or serverless host (Render, Railway, Fly, or platform functions), and a managed Postgres like Neon or Supabase (often serverless, scale-to-zero). Git-push-to-deploy with preview URLs per PR is the default. That's exactly the shape of DocChat — and saying it shows you can ship, not just code.
GitHub Actions is the de-facto CI for most repos — YAML workflows that run on push/PR, no separate server. And the honest line interviewers respect: most teams don't need Kubernetes. A managed platform (Vercel + Render + Neon) covers the vast majority of apps; reach for K8s only at real scale or strict infra control.
Infrastructure-as-code (Terraform/Pulumi — your infra defined in version-controlled files, not clicked into a dashboard) and observability (structured logs, traces, and metrics through tools like OpenTelemetry/Grafana). You don't need them for a capstone, but naming them as "the next step once it's running" signals you see past the demo.