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:
- Review the code against the business requirements
- Identify all the problems (security, logic, edge cases, hallucinations, runtime bugs)
- Debug the problems that require execution to confirm
- Correct each problem with justification
- Document the entire process with a professional findings document
- 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
| ID | Requirement | Priority |
|---|---|---|
| FR-01.1 | The system must allow registering users with email, name, and password | High |
| FR-01.2 | The password must be stored hashed with bcrypt, never in plain text | Critical |
| FR-01.3 | The email must be unique in the system | High |
| FR-01.4 | The system must validate email format and minimum password length (8 characters) | High |
FR-02: Authentication
| ID | Requirement | Priority |
|---|---|---|
| FR-02.1 | Login with email and password, returning a JWT token | High |
| FR-02.2 | The JWT must expire in 30 minutes | High |
| FR-02.3 | The JWT secret key must load from environment variables, with no hardcoded fallback | Critical |
| FR-02.4 | Protected endpoints must require a valid token in the Authorization header | Critical |
FR-03: Task Management (CRUD)
| ID | Requirement | Priority |
|---|---|---|
| FR-03.1 | Create a task with title (required), description (optional), priority (low/medium/high), and status (pending/in_progress/completed) | High |
| FR-03.2 | List the authenticated user's tasks with pagination (10 per page by default) | High |
| FR-03.3 | Filter tasks by status and/or priority | Medium |
| FR-03.4 | Get the detail of a task by ID (only if it belongs to the user) | High |
| FR-03.5 | Update a task (only the owner can modify it) | High |
| FR-03.6 | Delete a task (only the owner, soft delete changing the status to "deleted") | High |
| FR-03.7 | A user must NOT be able to view, edit, or delete another user's tasks | Critical |
FR-04: Statistics
| ID | Requirement | Priority |
|---|---|---|
| FR-04.1 | An endpoint that returns the user's statistics: total tasks, tasks by status, tasks by priority | Medium |
| FR-04.2 | The statistics must be calculated only on active tasks (not the deleted/soft-deleted ones) | Medium |
| FR-04.3 | Include the percentage of completed tasks out of the active total | Medium |
FR-05: Validations and Edge Cases
| ID | Requirement | Priority |
|---|---|---|
| FR-05.1 | Task titles: minimum 3 characters, maximum 100 | Medium |
| FR-05.2 | Priority only accepts values: "low", "medium", "high" | Medium |
| FR-05.3 | Status only accepts values: "pending", "in_progress", "completed" | Medium |
| FR-05.4 | Pagination: page must be >= 1, size must be between 1 and 100 | Medium |
| FR-05.5 | Nonexistent task IDs must return 404 with a descriptive message | Medium |
| FR-05.6 | Attempting to access another user's task must return 403, not 404 | Medium |
FR-06: Non-Functional Requirements
| ID | Requirement | Priority |
|---|---|---|
| FR-06.1 | Sensitive configuration (DB URL, JWT secret) from environment variables | Critical |
| FR-06.2 | SQL queries must use parameters, never string concatenation | Critical |
| FR-06.3 | Internal errors must not expose stack traces to the client | High |
| FR-06.4 | The API must return consistent responses in JSON format | Medium |
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
| Severity | Criterion | Examples |
|---|---|---|
| Critical | Exploitable security vulnerability or data loss | SQL injection, exposed secrets, auth bypass |
| High | Incorrect functionality that affects users | Poorly implemented business logic, incorrectly returned data |
| Medium | Unhandled edge case or robustness problem | Crash with specific inputs, incorrect pagination |
| Low | Quality or maintainability problem | Nonexistent 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)
- Initial reading (15 min): Read all the files to understand the general structure
- Review against requirements (30-45 min): Compare each file against the functional requirements
- Security checklist (15-20 min): Apply the security items from the module 4 checklist
- Document findings (10-15 min): Record each problem found in the findings document format
Phase 2: Debugging (30-45 min)
- Local setup (10 min): Install dependencies and start the application
- Reproduce bugs (15-20 min): Run the endpoints you suspect have problems
- Confirm findings (10-15 min): Verify the code review findings with real tests
Phase 3: Correction (45-60 min)
- Prioritize (5 min): Order the findings by severity
- Fix Critical and High (25-30 min): Implement fixes for the most serious problems
- Fix Medium and Low (15-20 min): Implement the remaining fixes
- Verify fixes (10 min): Test that each fix works
Phase 4: Documentation and Retrospective (30-45 min)
- Complete the findings document (10-15 min): Ensure each finding has all the information
- Write justifications (15-20 min): Document the reasoning for each fix
- 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:
- Security first: Items 1-5 of the checklist (secrets, SQL injection, auth, permissions)
- Business logic: Items 6-10 (correct results, edge cases, validations)
- Robustness: Items 11-15 (error handling, null checks, boundary conditions)
- 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 incorrect | 90% of the code is fine |
| The entire function has problems | The fix is targeted (1-5 lines) |
| There are too many interconnected changes | The change is clear and localized |
| The base logic is wrong | You only need to adjust one detail |
Evaluation Criteria
| Component | Weight | Excellent (90-100%) | Good (70-89%) | Needs improvement (<70%) |
|---|---|---|---|---|
| Findings | 40% | Finds 15+ of 18 problems with correct severity | Finds 12-14 with mostly correct severity | Finds <12 or incorrect severities |
| Corrections | 30% | All the fixes are correct and justified | Most are correct, some weak justifications | Partial or incorrect fixes |
| Process | 20% | Systematic, documented process, appropriate use of tools | Reasonable process, incomplete documentation | Disorganized process, no documentation |
| Retrospective | 10% | Reflective, specific, with concrete actionables | Reflective but generic | Superficial 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