Week 25: Capstone, Part 1 — Plan, Architect & Implement

The capstone spans this week and next — no new syntax, just everything from Weeks 1–24 applied to one real service you scope, design and build yourself. This week: define the problem and its success criteria before writing code, make and justify every architectural tradeoff — including which of the advanced modules from Weeks 15–24 your project actually needs — and implement it in a sensible, validated order. Week 26 picks up from a working implementation: the full testing and observability pass, a progressive deployment, and the final write-up.

Module 22 of 22 Week 25 of 26 ~8–10 Hours Capstone Project

By the end of this week, you'll be able to

  • Scope a production-shaped FastAPI service and define concrete success criteria before writing code
  • Make and justify architecture decisions, including which advanced modules genuinely fit your project
  • Implement the service incrementally, validating each layer before the next depends on it

1. Plan a Coherent Service & API Contract

Pick one project and commit to it: an issue tracker (projects, issues, comments, status transitions), a booking system (resources, time slots, reservations, cancellation rules), or an inventory service (products, warehouses, stock movements, low-stock alerts) all give you enough surface area to demonstrate everything from Weeks 2–24 without needing to invent scope. Any of the three works equally well as a portfolio piece — what matters is depth on one of them, not breadth across all three.

Before writing a single Pydantic model, sketch the resource model and the endpoints that operate on it. What are the nouns? What relationships exist between them (an issue belongs to a project; a comment belongs to an issue)? What state transitions are legal (an issue moves from open to in_progress to closed, but not directly from closed back to open without a reason)? Writing this down as a short table — resource, endpoint, method, auth requirement, status codes — forces the ambiguous decisions to happen on paper, where they're cheap to change, instead of three files deep into an implementation where they're expensive to unwind.

issue-tracker-contract.md
Resource: Project (owner_id, name, slug)
Resource: Issue   (project_id, title, status, assignee_id, created_by)
Resource: Comment (issue_id, author_id, body)

POST   /api/v1/projects                     auth: any user          -> 201
GET    /api/v1/projects/{id}                auth: member of project -> 200 | 404
POST   /api/v1/projects/{id}/issues         auth: member of project -> 201
GET    /api/v1/projects/{id}/issues         auth: member of project -> 200
PATCH  /api/v1/issues/{id}/status           auth: assignee or owner -> 200 | 409 (illegal transition)
POST   /api/v1/issues/{id}/comments         auth: member of project -> 201
GET    /healthz                             auth: none               -> 200

Over-scoping is the single most common way capstones fail — not technical difficulty, but running out of the week partway through a sprawling schema with no tests, no auth, and nothing deployed. A tightly scoped service with three resources, real authorization, a real test suite, and a working deployment is a dramatically stronger portfolio piece than ten resources with none of that. Decide upfront what's explicitly out of scope and write that decision into your README rather than discovering it by running out of time.

2. Architecture Decisions & Which Advanced Modules Fit

With the service scoped, make deliberate choices — and be ready to justify each one in writing, not just make it. This capstone spans a much wider toolkit than the original 15-week version, which makes restraint the actual skill being tested:

  • Monolith vs. services (Weeks 9–10, 17–18) — a single well-structured FastAPI application is the right default for a capstone-sized domain. Only split into a second service if there's a genuinely separate responsibility, and only reach for gRPC (Week 17) if you're actually calling between two services you control — not because the course covered it.
  • Sync, async, or a saga (Weeks 9–10, 18) — a synchronous httpx call for anything the caller needs an immediate answer to; a Celery task for anything that can happen after the response has gone out; a full saga with compensating actions and a transactional outbox only if a real multi-step, multi-service transaction genuinely exists in your domain.
  • REST, GraphQL, or both (Weeks 3, 16, 21) — REST remains the right default for a capstone-sized API; add GraphQL specifically if your domain has a genuinely nested, client-driven shape (a dashboard needing different fields per view) that would otherwise need several bespoke REST endpoints.
  • What needs caching or a pipeline (Weeks 11, 20) — cache read-heavy, slow-changing data; reach for an Airflow DAG only if there's a real bulk/offline workload (a nightly import, a scheduled aggregation), not for anything that fits comfortably in a normal request.
  • Auth model (Weeks 6–7, 19) — Week 6's JWT-based auth is enough for most capstones; running your own OAuth2 provider or building multi-tenant isolation is only worth the complexity if your domain genuinely has third-party clients or multiple tenants sharing infrastructure.

The justification is the actual work here. "I kept this as one service, with plain JWT auth and no saga, because the domain is small and every one of those techniques would add failure surface for no real benefit" is an architectural decision; using every technique from the course by default is not. Write the reasoning down alongside each choice — Week 26's write-up depends on it.

Two or three deliberately-chosen advanced modules beat ten reached for by default

A capstone that picks Advanced SQLAlchemy (Week 15), a saga with an outbox (Week 18), and a progressive canary rollout (Week 24) — each with a clear, specific reason tied to the domain — demonstrates stronger engineering judgment than one that bolts on gRPC, GraphQL, and Airflow because the syllabus covered them. Depth and justification beat breadth every time a reviewer actually reads the write-up.

3. Implementation, in a Sensible Order

Build in an order that lets you validate each layer before the next depends on it — the same incremental discipline this course used from Week 5 onward, now spanning the whole service and whichever advanced modules Section 2 selected:

a sensible build order
# 1. Models and persistence first (Weeks 4-5, 15) -- get the domain
#    model into a real database with Alembic migrations and any
#    dynamic queries or eager-loading you need, before any HTTP
#    layer exists.
# 2. REST (and GraphQL, if chosen) layer (Weeks 3, 16, 21) -- routers,
#    Pydantic models, validation, versioning and pagination conventions
#    over that persisted model; confirm every core flow works
#    unauthenticated.
# 3. Security (Weeks 6-7, 19) -- add authentication and authorization
#    once the unsecured flows are already correct, not before.
# 4. Service-to-service, messaging, or a saga (Weeks 9-10, 17-18) --
#    ONLY if Section 2's architecture actually calls for it.
# 5. Caching or a data pipeline (Weeks 11, 20) -- applied last, to
#    endpoints or workloads Section 2 identified as needing it, once
#    their unoptimized behavior is already correct.

This order matters for the same reason it mattered in every earlier week's exercises: it's far cheaper to discover your entity relationships or API shape need to change while only the persistence and REST layers exist, than after security, sagas, and caching are all built on top of an assumption that turns out to be wrong. Validate each layer — a passing request against it, by hand or by test — before adding the next.

4. End-of-Week Checkpoint

Before moving into Week 26, confirm all of the following are true and working:

  • ✅ The scope, API surface, and success criteria from Section 1 are written down, not implicit in whatever got built.
  • ✅ Every architectural choice from Section 2 — including which advanced modules were deliberately excluded — has a one- or two-sentence written justification.
  • ✅ The persistence and REST layers work correctly, unauthenticated, exercised by hand or a quick test, before security was added.
  • ✅ Authentication and authorization are in place and correctly restrict access to the operations that need it.
  • ✅ Any chosen advanced modules (a saga, GraphQL, a data pipeline) are implemented and individually validated, not just present in the code.

With all five true, the implementation is solid enough to build Week 26's testing, observability, and deployment pass on top of — and to write the final capstone defense against.