Module 8: Capstone Project

Capstone Project: Code Review, Debugging, and Correction of a FastAPI Codebase

Capstone Project: Code Review, Debugging, and Correction of a FastAPI Codebase

Capsule overview

You've reached the guide's capstone project. Everything you learned in modules 1-7 — awareness of the AI code trust problem, mental models for supervising output, hallucination detection, professional code review with a checklist, error pattern recognition, debugging with Claude Code, and regenerate vs edit decisions — applies here in a complete and realistic scenario.

The scenario: you receive a codebase for a task management API built with FastAPI. The code was "generated by AI" and contains between 15 and 20 problems distributed across multiple categories. Your job isn't to generate new code — it's to validate, diagnose, and correct the existing code. Exactly what a senior developer does when they receive code from a junior or an AI tool.

This capsule establishes the complete scope of the project, gives you the business requirements against which to evaluate the code, describes the structure of the codebase, and defines exactly what you must deliver.


Project Context

What this project simulates

In your day-to-day work with Claude Code, you're going to generate code constantly. Sometimes it will be perfect. Sometimes it will have subtle problems that go unnoticed until production. This project simulates the second situation: code that looks reasonable but has real problems.

The difference from an individual module exercise is the scale. In module 3 you detected hallucinations in isolated snippets. In module 5 you identified patterns in individual functions. Here you have a complete codebase with 8-12 interconnected files, where the problems hide in the interaction between modules, in the logic that crosses files, and in the details that are easy to ignore when you're reviewing a complete system.

The role you assume

You're a senior developer who receives a codebase for code review before it's merged to the main branch. The code was generated using Claude Code by a teammate. Your responsibility:

  1. Review the code against the business requirements
  2. Identify all the problems (security, logic, edge cases, hallucinations, runtime bugs)
  3. Debug the problems that require execution to confirm
  4. Correct each problem with justification
  5. Document the entire process with a professional findings document
  6. Reflect on your process with a retrospective

Business Requirements: Task Management API

This is the functional requirements document against which you must evaluate the code. Read it carefully — each divergence between these requirements and the implementation is a problem you must document.

Functional Requirements Document

Product: TaskFlow API Version: 1.0 Date: March 2026


FR-01: User Management

IDRequirementPriority
FR-01.1The system must allow registering users with email, name, and passwordHigh
FR-01.2The password must be stored hashed with bcrypt, never in plain textCritical
FR-01.3The email must be unique in the systemHigh
FR-01.4The system must validate email format and minimum password length (8 characters)High

FR-02: Authentication

IDRequirementPriority
FR-02.1Login with email and password, returning a JWT tokenHigh
FR-02.2The JWT must expire in 30 minutesHigh
FR-02.3The JWT secret key must load from environment variables, with no hardcoded fallbackCritical
FR-02.4Protected endpoints must require a valid token in the Authorization headerCritical

FR-03: Task Management (CRUD)

IDRequirementPriority
FR-03.1Create a task with title (required), description (optional), priority (low/medium/high), and status (pending/in_progress/completed)High
FR-03.2List the authenticated user's tasks with pagination (10 per page by default)High
FR-03.3Filter tasks by status and/or priorityMedium
FR-03.4Get the detail of a task by ID (only if it belongs to the user)High
FR-03.5Update a task (only the owner can modify it)High
FR-03.6Delete a task (only the owner, soft delete changing the status to "deleted")High
FR-03.7A user must NOT be able to view, edit, or delete another user's tasksCritical

FR-04: Statistics

IDRequirementPriority
FR-04.1An endpoint that returns the user's statistics: total tasks, tasks by status, tasks by priorityMedium
FR-04.2The statistics must be calculated only on active tasks (not the deleted/soft-deleted ones)Medium
FR-04.3Include the percentage of completed tasks out of the active totalMedium

FR-05: Validations and Edge Cases

IDRequirementPriority
FR-05.1Task titles: minimum 3 characters, maximum 100Medium
FR-05.2Priority only accepts values: "low", "medium", "high"Medium
FR-05.3Status only accepts values: "pending", "in_progress", "completed"Medium
FR-05.4Pagination: page must be >= 1, size must be between 1 and 100Medium
FR-05.5Nonexistent task IDs must return 404 with a descriptive messageMedium
FR-05.6Attempting to access another user's task must return 403, not 404Medium

FR-06: Non-Functional Requirements

IDRequirementPriority
FR-06.1Sensitive configuration (DB URL, JWT secret) from environment variablesCritical
FR-06.2SQL queries must use parameters, never string concatenationCritical
FR-06.3Internal errors must not expose stack traces to the clientHigh
FR-06.4The API must return consistent responses in JSON formatMedium

Codebase Structure

The codebase you'll receive in the next capsule has this structure:

taskflow-api/
├── main.py                    # FastAPI application entry point
├── config.py                  # Configuration and environment variables
├── database.py                # Database connection and operations
├── models.py                  # Pydantic models (request/response)
├── routes/
│   ├── auth.py                # Registration and login endpoints
│   ├── tasks.py               # Task CRUD endpoints
│   └── users.py               # Profile and statistics endpoints
├── services/
│   ├── auth_service.py        # Authentication and JWT logic
│   └── task_service.py        # Task business logic
└── requirements.txt           # Project dependencies

Description of each file

main.py — Configuration of the FastAPI application, router registration, and middleware. It's where everything connects.

config.py — A configuration class that loads environment variables. Includes database, JWT, and application-parameter configuration.

database.py — Functions to create the SQLite database, get connections, and run queries. This file is critical: it contains the direct interaction with the database.

models.py — Pydantic models to validate request bodies and format responses. Defines the user, task, authentication, and statistics schemas.

routes/auth.py — POST /register and POST /login endpoints. Handles user creation and token generation.

routes/tasks.py — CRUD endpoints: create, list, get, update, and delete tasks. Includes filters and pagination.

routes/users.py — The user statistics and profile endpoint.

services/auth_service.py — Password hashing functions, JWT generation and verification, and current-user extraction.

services/task_service.py — Business logic: create a task, get tasks with filters, calculate statistics, and validations.


How to Read the Requirements: Practical Guide

The functional requirements aren't just a list of features — they're your main verification tool. Here's how to use them effectively during the code review.

Technique: Map requirement → code → verification

For each requirement, follow this process:

1. READ the requirement (e.g., FR-01.2: password hashed with bcrypt)
2. FIND the code that implements it (where is the password stored?)
3. VERIFY that the implementation meets the requirement
4. DOCUMENT whether it meets it or not (and why)

Practical example

Requirement FR-01.2: The password must be stored hashed 
with bcrypt, never in plain text.

1. Where is the password stored?
   → routes/auth.py, register() function
   → Runs an INSERT with the password field

2. Is it hashed before inserting?
   → Does it call hash_password() or bcrypt.hashpw()?
   → Or does it insert user.password directly?

3. Does the hash function exist and is it correct?
   → services/auth_service.py has hash_password()
   → Is it called in the registration flow?

4. Result: [MEETS / DOESN'T MEET]
   → Document in the findings document if it doesn't meet it

Requirements that are easy to overlook

Some requirements aren't obvious from just reading the code:

FR-03.6: Soft delete — The word "delete" is misleading. The requirement says deleting must change the status to "deleted", not remove the row from the database. You need to verify the delete implementation, not just that it "works."

FR-04.2: Statistics on active tasks — If the delete doesn't implement soft delete correctly, the statistics could be affected too. The requirements are interconnected.

FR-05.6: 403 vs 404 — The difference is subtle: 404 says "doesn't exist," 403 says "exists but you don't have permission." The authorization implementation determines which is returned. Many developers implement it as 404 for both cases, but the requirement specifically asks for 403 when the task exists but belongs to another user.

FR-06.2: Parameters in SQL — It's not enough to verify that there's a ? in the main query. You need to verify ALL the queries in the codebase, including those for dynamic filters and searches.

The importance of the "Medium" priority requirements

The requirements marked as "Medium" seem less important, but in this project they represent the difference between a good delivery and an excellent one. The most subtle problems in the codebase are in the medium-priority requirements:

  • ✅ Title length validation (FR-05.1)
  • ✅ Validation of priority and status values (FR-05.2, FR-05.3)
  • ✅ Pagination parameters (FR-05.4)
  • ✅ Statistics on active tasks (FR-04.2)

A junior developer finds the Critical ones (hardcoded secrets, SQL injection). A senior developer also finds the Medium ones (incorrect validations, erroneous calculations).


Types of Problems You'll Find

The codebase contains between 15 and 20 problems distributed across 5 categories. You're not told where they are — finding them is part of the exercise. What you are told is what types of problems to look for:

Category 1: Hallucinations (3-4 problems)

Code that references something that doesn't exist or that uses an API incorrectly:

  • ✅ Imports of modules or functions that don't exist
  • ✅ Library functions with parameters they don't accept
  • ✅ APIs with invented signatures that look correct

Reference module: Module 3 — Detecting Hallucinations in Code

Category 2: Security Holes (3-4 problems)

Vulnerabilities that expose the system to attacks or unauthorized access:

  • ✅ Secrets hardcoded in the source code
  • ✅ SQL injection through string concatenation
  • ✅ Endpoints without authentication protection
  • ✅ Passwords stored without adequate protection

Reference module: Module 5, Capsule 04 — Typical Security Holes

Category 3: Unhandled Edge Cases (3-4 problems)

Inputs or conditions that cause unexpected behavior:

  • ✅ Unhandled null/None values
  • ✅ Empty lists that cause errors
  • ✅ Off-by-one errors in pagination

Reference module: Module 5, Capsule 03 — Unhandled Edge Cases

Category 4: Incorrect Logic (3-4 problems)

Code that runs without errors but produces incorrect results:

  • ✅ Filters that include instead of exclude (or vice versa)
  • ✅ Incorrect statistics calculations
  • ✅ Validations that accept data they should reject

Reference module: Module 4, Capsule 05 — Verify Business Logic

Category 5: Runtime Bugs (2-3 problems)

Errors that only appear when running the code with certain inputs:

  • ✅ Type mismatches that only manifest with specific data
  • ✅ Errors that only appear with particular combinations of parameters

Reference module: Module 6 — Debugging with Claude Code


Delivery Format

Your delivery must contain exactly these 4 components:

1. Findings Document (40% of the evaluation)

A table documenting each problem found:

# Findings Document — TaskFlow API Code Review

## Executive Summary
[2-3 sentences describing the overall state of the codebase]

## Findings

| # | Severity | Category | File | Line(s) | Description | Impact |
|---|-----------|-----------|---------|----------|-------------|---------|
| 1 | Critical  | Security  | config.py | 12 | JWT secret hardcoded in source code | Any attacker can forge valid tokens |
| 2 | High      | Logic     | services/task_service.py | 45-52 | [description] | [impact] |
| ... | ... | ... | ... | ... | ... | ... |

## Statistics
- Total findings: X
- Critical: X
- High: X
- Medium: X
- Low: X

Severity guide

SeverityCriterionExamples
CriticalExploitable security vulnerability or data lossSQL injection, exposed secrets, auth bypass
HighIncorrect functionality that affects usersPoorly implemented business logic, incorrectly returned data
MediumUnhandled edge case or robustness problemCrash with specific inputs, incorrect pagination
LowQuality or maintainability problemNonexistent import that isn't used, confusing naming

2. Corrected Code (30% of the evaluation)

The complete codebase with all the fixes applied. Each corrected file must have a comment at the beginning indicating what was changed:

# CORRECTIONS IN THIS FILE:
# - Line 12: Removed hardcoded JWT secret, now uses os.environ
# - Line 45: Fixed status filter (included deleted, now excludes them)
# - Line 78: Added empty list handling in the statistics calculation

3. Justifications (20% of the evaluation)

For each fix, explain:

  • What changed (the concrete fix)
  • Why the original code was incorrect (referencing the functional requirement it violates)
  • Why your fix is correct (how you verified it solves the problem)
  • Regenerate vs edit decision (whether you decided to regenerate the fragment with Claude Code or edit it manually, and why)
## Justification Finding #1: JWT Secret Hardcoded

**What I changed:** I replaced `SECRET_KEY = "my-secret-key"` 
with `SECRET_KEY = os.environ["JWT_SECRET_KEY"]`

**Why it was incorrect:** It violates FR-06.1 (sensitive configuration 
from environment variables) and FR-02.3 (JWT secret with no hardcoded 
fallback). An attacker with access to the source code could 
forge valid tokens.

**Why my fix is correct:** `os.environ[]` raises a KeyError 
if the variable doesn't exist, which is the desired behavior: 
the app shouldn't start if critical configuration is missing.

**Decision:** Edit manually. The fix is targeted (one line) 
and the context is clear. Regenerating would be disproportionate.

4. Retrospective (10% of the evaluation)

A 300-500 word document. Full details in Capsule 05 of this module.


Timeline and Suggested Approach

The project is designed to be completed in 3-4 hours. This is the suggested distribution:

Phase 1: Code Review (60-90 min)

  1. Initial reading (15 min): Read all the files to understand the general structure
  2. Review against requirements (30-45 min): Compare each file against the functional requirements
  3. Security checklist (15-20 min): Apply the security items from the module 4 checklist
  4. Document findings (10-15 min): Record each problem found in the findings document format

Phase 2: Debugging (30-45 min)

  1. Local setup (10 min): Install dependencies and start the application
  2. Reproduce bugs (15-20 min): Run the endpoints you suspect have problems
  3. Confirm findings (10-15 min): Verify the code review findings with real tests

Phase 3: Correction (45-60 min)

  1. Prioritize (5 min): Order the findings by severity
  2. Fix Critical and High (25-30 min): Implement fixes for the most serious problems
  3. Fix Medium and Low (15-20 min): Implement the remaining fixes
  4. Verify fixes (10 min): Test that each fix works

Phase 4: Documentation and Retrospective (30-45 min)

  1. Complete the findings document (10-15 min): Ensure each finding has all the information
  2. Write justifications (15-20 min): Document the reasoning for each fix
  3. Write the retrospective (10-15 min): Reflect on the process

Tools and Techniques to Use

From Module 2: Mental Models

Apply the three mental models throughout the project:

  • Managing an Intern: Focus on reviewing the business logic and the architecture decisions, not every line of code
  • Circuit Breaker: Define clear checkpoints: "I don't move to debugging until I finish the complete code review"
  • Trust Calibration: Trust the boilerplate more (routes, basic config) and distrust the business logic and security more

From Module 3: Hallucination Detection

For each import in the codebase:
1. Does the package exist? → pip show <package>
2. Does the function/class exist in that package? → official documentation
3. Are the parameters correct? → verify the real signature

From Module 4: Code Review Checklist

Use the 20-item checklist from module 4, prioritizing:

  1. Security first: Items 1-5 of the checklist (secrets, SQL injection, auth, permissions)
  2. Business logic: Items 6-10 (correct results, edge cases, validations)
  3. Robustness: Items 11-15 (error handling, null checks, boundary conditions)
  4. Quality: Items 16-20 (naming, structure, maintainability)

From Module 5: Error Patterns

Actively look for the 4 types of common error patterns:

  • Incorrect naming and abstractions
  • Unhandled edge cases
  • Typical security holes
  • Code that "works" but produces incorrect results

From Module 6: Systematic Debugging

For the runtime bugs, follow the 5-step process:

1. REPRODUCE → Create the input that causes the error
2. ISOLATE    → Find the exact line/function
3. DIAGNOSE → Understand WHY it fails
4. FIX       → Implement the correction
5. VERIFY → Confirm the fix works and doesn't break anything

From Module 7: Claude Code as a Tool

You can use Claude Code during the project to:

  • ✅ Analyze stack traces and error logs
  • ✅ Investigate whether an import or API exists
  • ✅ Get diagnostic hypotheses for hard bugs
  • ✅ Generate targeted fixes for clear problems

Don't use Claude Code to:

  • ❌ "Find all the bugs" — that's your job
  • ❌ Accept diagnoses without verifying
  • ❌ Regenerate the entire codebase

From Module 7: Regenerate vs Edit Framework

For each fix, decide:

Regenerate when...Edit when...
The whole approach is incorrect90% of the code is fine
The entire function has problemsThe fix is targeted (1-5 lines)
There are too many interconnected changesThe change is clear and localized
The base logic is wrongYou only need to adjust one detail

Evaluation Criteria

ComponentWeightExcellent (90-100%)Good (70-89%)Needs improvement (<70%)
Findings40%Finds 15+ of 18 problems with correct severityFinds 12-14 with mostly correct severityFinds <12 or incorrect severities
Corrections30%All the fixes are correct and justifiedMost are correct, some weak justificationsPartial or incorrect fixes
Process20%Systematic, documented process, appropriate use of toolsReasonable process, incomplete documentationDisorganized process, no documentation
Retrospective10%Reflective, specific, with concrete actionablesReflective but genericSuperficial or absent

Before You Start

Preparation checklist

Before moving to the next capsule (where you'll receive the codebase), verify:

  • ✅ You read the complete functional requirements (previous section)
  • ✅ You understand the codebase structure (8 files + requirements.txt)
  • ✅ You know what types of problems to look for (5 categories)
  • ✅ You're clear on the delivery format (4 components)
  • ✅ You have Python 3.10+ installed
  • ✅ You have access to Claude Code
  • ✅ You have the module 4 checklist on hand
  • ✅ You've set aside 3-4 hours of uninterrupted time

The right mindset

This project isn't a speed test. It's a simulation of professional work. In real work:

  • You're not rewarded for finding the bugs fastest — you're rewarded for not letting any slip through
  • The documentation is as important as the fix
  • Reflecting on your process makes you better next time
  • Asking tools (like Claude Code) for help is smart, not cheating

Approach the project with the mindset of a senior developer doing code review before a production deploy. Every problem you let slip through is a problem your users are going to encounter.

Environment setup

Before starting, make sure you have everything ready:

# Verify the Python version
python --version
# Must be 3.10 or higher

# Verify that pip is available
pip --version

# Verify that you have SQLite
sqlite3 --version

# Verify Claude Code
claude --version

If something is missing, install it before starting. You don't want to waste time debugging your environment when you should be debugging the codebase.

Suggested file organization

Create this structure for your delivery:

capstone-project/
├── taskflow-api/            # The original codebase (for reference)
├── taskflow-api-fixed/      # Your corrected version
├── findings-document.md     # Findings table
├── justifications.md        # Justification for each fix
├── debugging-log.md         # Log of the debugging process
└── retrospective.md         # Your retrospective

Having the original and the corrected codebase separate lets you easily compare what changed and document each change with reference to the original lines.


Visual Map of the Project

So you have the complete sequence of the project clear, this is the workflow you'll follow:

┌─────────────────────────────────────────────────────────┐
│                    PHASE 1: CODE REVIEW                 │
│                                                          │
│  Read requirements → Read code → Compare → Document      │
│                                                          │
│  Outputs: Findings document (draft)                      │
└───────────────────────┬─────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────┐
│                    PHASE 2: DEBUGGING                   │
│                                                          │
│  Local setup → Run API → Reproduce bugs →                │
│  Confirm findings → Look for additional runtime bugs     │
│                                                          │
│  Outputs: Findings document (updated), Debugging log     │
└───────────────────────┬─────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────┐
│                   PHASE 3: CORRECTION                   │
│                                                          │
│  Prioritize → Fix Critical → Fix High →                 │
│  Fix Medium/Low → Verify → Justify                      │
│                                                          │
│  Outputs: Corrected code, Justifications                 │
└───────────────────────┬─────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────┐
│              PHASE 4: DELIVERY + RETROSPECTIVE          │
│                                                          │
│  Compile deliverables → Write retrospective →            │
│  Self-evaluate → Deliver                                 │
│                                                          │
│  Outputs: Complete delivery with 4 documents             │
└─────────────────────────────────────────────────────────┘

Each phase has its own capsule with detailed instructions. You don't need to memorize everything now — just understand the general flow and trust that each capsule will guide you step by step.


Why This Project Format

You may wonder why the project is "receive code with problems" instead of "generate something with Claude Code." The answer is simple: if the project were to generate code, you'd have an incentive to generate something simple with no problems. You wouldn't practice the real skill.

The real skill is this: receive code that someone else (or AI) generated, evaluate it with professional judgment, and improve it. It's what senior developers do every day. It's what you'll do with every PR you review from a teammate who uses Claude Code. It's what you'll do with your own AI-generated code the next time something feels "off."

This project forces you to practice exactly that. It's not an accident — it's deliberate.


Important Notes

On the use of Claude Code in the project

You can (and should) use Claude Code during the project. The whole guide is about using Claude Code with professional judgment — and the project is where you demonstrate that judgment.

What's evaluated isn't whether you used Claude Code, but how you used it:

  • Did you give it enough context or did you ask it to "fix everything"?
  • Did you verify its suggestions or apply them blindly?
  • Did you use the right tool for each situation?
  • Did you document when it helped and when you had to do the work manually?

On the difficulty

Some problems are obvious (an import that fails when you run it). Others are subtle (a query that returns correct results except in a specific edge case). Don't get frustrated if you don't find everything on the first pass. Senior developers do multiple code review passes for a reason.

On honesty

The retrospective is where the difference is most noticeable between someone who completed the exercise honestly and someone who didn't. There's no wrong answer in the retrospective — but there are superficial answers. "Everything was easy" isn't a useful reflection. "It was hard for me to find the SQL injection because I didn't review the queries in enough detail on the first pass" is.


Next capsule: Code Review Phase — The complete TaskFlow API codebase with the planted problems, and the instructions to apply your professional checklist.


Debugging & Code Review with Claude Code — Module 8, Capsule 01 Claude Code Agentic Development Path — Guide #6 of 11