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.
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
httpxcall 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.
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:
# 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.