Back to path
AdvancedTradepost · Project 11 of 12 ~6h· 5 milestones

Find out why it was slow before the merchant does

Continues from the last build: CI runs unit, integration, contract and concurrency tests on every PR.

Every PR now runs unit, integration, contract and concurrency tests, so bad code stops at the door.

structured logging with correlation idschild loggers across process boundariesRED method (rate, errors, duration) instrumentationliveness vs readiness checkslog-driven incident debuggingEXPLAIN ANALYZE query diagnosisload testing methodologycapacity planning

What you'll build

By the end, every request and every worker job carries a correlation id through structured JSON logs, a /metrics endpoint reports request rate, error rate and latency percentiles per route from data kept entirely in process, /healthz and /readyz answer two different questions correctly, you will have found and fixed one deliberately planted slow query using nothing but logs and EXPLAIN ANALYZE, and you will have a written capacity note backed by three autocannon runs.

See how we teach, before you sign up

You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:

src/lib/log.tstypescript
import pino from 'pino';

export const log = pino({
  level: process.env.LOG_LEVEL || 'info'
});

Reading this file

  • import pino from 'pino';Only dependency so far; hooks and redact rules are added this rung.
  • level: process.env.LOG_LEVEL || 'info'The only configuration present before this rung's work.
  • export const log = pino({A single flat logger with no child loggers or correlation ids yet.

No redaction, no request correlation, no per-route recording yet. This is the plain logger carried from earlier rungs.

That's 1 of 8 explained code blocks in this single project.

The build, milestone by milestone

  1. 1

    Give every request and job a paper trail

    4 guided steps

    Without a correlation id, an API log line and a worker log line about the same order are indistinguishable from two unrelated events. You cannot reconstruct what happened to one request across processes, which is exactly what a "checkout was slow yesterday" complaint requires.

  2. 2

    Expose the golden signals at /metrics

    4 guided steps

    Logs answer "what happened on this one request". Metrics answer "how is the whole fleet behaving right now". Without a rate/error/duration view per route, you cannot tell a merchant's 4pm complaint apart from normal variance until you have already dug through thousands of log lines.

  3. 3

    Split /healthz from /readyz

    4 guided steps

    Liveness answers "should this process be restarted". Readiness answers "should traffic be routed here right now". If /healthz also checks postgres, one slow query makes the platform kill and restart a perfectly healthy API process, which is worse than the original slowness.

  4. 4

    Find the slow thing from logs alone

    5 guided steps

    Instrumentation only matters if you can actually use it under pressure. This milestone is the fire drill: the same kind of investigation you would run at 4:05pm with a merchant on the line, except this time you plant the bug yourself so you know the answer and can check your method against it.

  5. 5

    Load test like you mean it

    5 guided steps

    "It felt slow" is not a number a merchant, or your future self at 4pm, can act on. A capacity note that says a concrete req/s at a stated p99 is something you can compare against next quarter's traffic and decide whether you need a second instance before it becomes an incident.

What's inside when you start

3 starter files, ready to clone
5 guided milestones
5 full reference solutions
8 code blocks explained line-by-line
5 "is it working?" checks
5 interview questions it prepares you for

You'll walk away with

Structured pino request/response logging with requestId and merchantId propagated into worker jobs via outbox_events
GET /metrics returning per-route count, errorRate and p50/p95/p99 latency computed from in-process histograms
GET /healthz and GET /readyz wired into docker-compose healthchecks, with readyz checking postgres, redis and a worker heartbeat
A documented incident walkthrough: the jq log query plus the EXPLAIN ANALYZE plan proving the planted slow query, and the fix
Three autocannon result sets (steady, spike, soak) and a one-paragraph written capacity note stating a sustainable req/s

This is portfolio-grade. Build it free.

Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.

Start building