Skip to Content
Lab 3 (AI)

Context API Implementation with an AI Architect

In this lab you will build the same Context API Todo application as Lab 3, but you will begin the way many professional teams now begin: an AI architect drafts the architectural plan, and you, acting as the Product Manager, review it, request revisions, and approve it before a single line of code exists. You will then scaffold the approved structure with Claude Code and personally implement all of the application logic. Plan for approximately 2.5 hours of asynchronous work.


Scenario

You are a developer at a small product studio. A client has asked for a polished Todo application, and your engineering lead wants the team to practice a structured AI-assisted workflow on it: an AI architect plans, a Product Manager approves, and a developer implements. You will play both human roles.

Instead of relying on prop drilling or a complex third-party state management library for an application of this scale, the architecture must use React’s Context API to manage the list of todos, the current visibility filter, and a simple theme. This lab gives you practical experience in designing multiple contexts, implementing providers, consuming context values in components, and handling more involved state updates, plus a professional skill that sits above all of that: directing and critically reviewing AI-produced architecture before committing to it.


Learning Objectives

Upon successful completion of this lab, you will be able to:

  • Translate feature requirements into a structured brief that an AI architect can work from.
  • Direct an AI to produce an architectural plan (component hierarchy, context boundaries, state shapes, provider composition, and file structure) without letting it write implementation code.
  • Critically review an AI-drafted plan, request revisions, and document an approval decision as a Product Manager would.
  • Design and implement multiple, independent contexts for different pieces of global state.
  • Create and use Context Providers to make state and update functions available throughout the component tree.
  • Consume context values and functions in components using the useContext hook.
  • Manage complex state (for example, an array of objects and filter states) using useState or useReducer within context providers.
  • Implement features requiring interaction between different contexts (for example, filtering todos).
  • Add a persistence layer to a Context-based application using localStorage.
  • Apply basic performance optimizations (memoized provider values) when working with the Context API.

The AI as Architect Role

This lab uses the AI as Architect role from the course AI framework:

  • Claude drafts the plan. The Architect produces the component hierarchy, the context boundaries and state shapes, the provider composition, the data flow, the persistence strategy, and the file structure.
  • You act as the Product Manager. You write the requirements brief, read the draft closely, ask hard questions, request revisions, and give or withhold approval. The plan is not done until you approve it.
  • The Architect never writes implementation code. If Claude starts producing function bodies or business logic during planning, redirect it back to planning. You will write all implementation code yourself in Part 6.

This mirrors how senior engineers already work: the expensive mistakes in software are architectural, and review skills matter most before implementation begins.


Project Requirements

Build a Todo application with the following features, primarily using the Context API for state management. These are the same requirements as Lab 3; your approved architectural plan must satisfy all of them.

1. Core Todo Management (TodoContext)

  • State: An array of todo items. Each todo item should have at least:
    • id: A unique identifier (string or number).
    • text: The content of the todo (string).
    • completed: A boolean indicating if the todo is completed.
  • Actions (exposed via context):
    • addTodo(text: string): Adds a new todo item to the list.
    • toggleTodo(id: string | number): Toggles the completed status of a todo item.
    • deleteTodo(id: string | number): Removes a todo item from the list.
    • editTodo(id: string | number, newText: string): Edits the text of an existing todo item.
    • clearCompleted(): Removes all completed todos.
  • Components:
    • TodoInput: An input field to add new todos.
    • TodoList: Displays the list of todo items.
    • TodoItem: Represents a single todo item, allowing interaction (toggle, delete, edit).

2. Visibility Filters (FilterContext)

  • State: The current visibility filter. Possible values: ‘all’, ‘active’, ‘completed’.
  • Actions (exposed via context):
    • setFilter(filter: string): Sets the current filter.
  • Functionality:
    • The TodoList should display todos based on the currently active filter from FilterContext.
    • FilterButtons: A component that displays buttons to change the current filter.

3. Theme Switching (ThemeContext)

  • State: The current theme. Possible values: ‘light’, ‘dark’.
  • Actions (exposed via context):
    • toggleTheme(): Switches between ‘light’ and ‘dark’ themes.
  • Functionality:
    • The application should visually change based on the selected theme (for example, background colors and text colors). Apply theme changes to the main app container and ideally a few key components.
    • ThemeToggleButton: A button to toggle the theme.

4. Persistence Layer

  • Functionality:
    • The state of the todos (from TodoContext) and the current theme (from ThemeContext) should be persisted to localStorage.
    • When the application loads, it should attempt to rehydrate these states from localStorage.
    • Updates to todos or theme should automatically update localStorage.

Example Solution

Interact with the example below to see the finished behavior you are aiming for. Understanding the target behavior will help you write a precise requirements brief in Part 2. The example demonstrates expected behavior only; your implementation must follow your own approved architectural plan.

Todo App (Context API)

No todos yet! Add one above.


Part 1: Setup (10 minutes)

  1. Create a new Vite React project (TypeScript is optional but recommended) and confirm it runs:

    npm create vite@latest todo-context-app cd todo-context-app npm install npm run dev

    When prompted, choose the React framework and either the TypeScript or JavaScript variant. Stop the dev server with Ctrl+C once you have confirmed the starter page loads.

  2. Initialize a Git repository and make an initial commit:

    git init git add . git commit -m "Initial Vite scaffold"
  3. Sign in at https://claude.ai  with your Per Scholas-provided Claude Pro account.

  4. Confirm Claude Code is installed by running claude --version in your terminal. If it is not installed:

    npm install -g @anthropic-ai/claude-code

    You will use Claude Code in Part 5. The first time you run claude, use the /login command if prompted and sign in with the same Per Scholas-provided account.

Note

If you do not have access to a Pro-level Claude account through Per Scholas, you may complete this lab using the free tier of Claude or another AI assistant with equivalent capabilities. Free-tier usage limits may require you to complete the lab across more than one session. If limits are a concern, run the entire planning phase (Parts 3 and 4) in a single focused conversation, and complete Part 5 by asking Claude for file skeletons one at a time and creating the files manually instead of using Claude Code.


Part 2: Write the Requirements Brief as Product Manager (15 minutes)

An architect is only as good as the brief. Vague briefs produce vague plans, and vague plans produce rework. Your first Product Manager task is to condense the Project Requirements above into a structured brief with explicit constraints.

  1. Create a file named ARCHITECTURE.md at the root of your repository. This file will grow throughout the lab and is a graded deliverable.

  2. Write the first section, ## 1. Requirements Brief, using this structure. Fill in the feature summaries in your own words; do not paste the entire requirements page:

    ## 1. Requirements Brief ### Product A Todo application with filtering, theming, and persistence. ### Features - Todo management: add, toggle, delete, edit, and clear-completed actions on a list of todo items (id, text, completed). - Visibility filtering: 'all', 'active', 'completed'; the visible list respects the active filter. - Theme switching: 'light' and 'dark'; the UI visibly changes with the theme. - Persistence: todos and theme survive a page reload via localStorage. ### Required components TodoInput, TodoList, TodoItem, FilterButtons, ThemeToggleButton. ### Technical constraints - React function components only (no class components). - State management with the Context API only: three separate contexts (TodoContext, FilterContext, ThemeContext). No Redux, Zustand, or other state libraries. - No routing libraries; this is a single-view application. - Provider values must be memoized (useMemo for value objects, useCallback for stable functions) to avoid unnecessary consumer re-renders. - Persistence uses localStorage with rehydration on load.
  3. Read your brief once as if you were the architect receiving it. If any requirement is ambiguous, tighten it now. Commit the file:

    git add ARCHITECTURE.md git commit -m "Add requirements brief"

Part 3: The Architect Drafts the Plan (20 minutes)

Now hand the brief to Claude and have it act as the architect.

  1. Start a new conversation at claude.ai.

  2. Paste the following role-enforcement prompt, replacing the placeholder at the end with your requirements brief from ARCHITECTURE.md:

    You are acting as a senior software architect for my team. I am the Product Manager. Your job in this conversation is to plan, not to build. Rules for this conversation: 1. Do not write implementation code. No function bodies, no JSX beyond one-line illustrative fragments, no business logic. 2. Produce planning artifacts only: text diagrams, lists, tables, and short explanations. 3. If I ask for something that would require implementation code, describe the approach in plain language instead. 4. Stay within the constraints in my brief. Do not introduce additional libraries, tools, or features. 5. When I request a revision, revise the plan and clearly mark what changed. Using the requirements brief below, draft a complete architectural plan containing exactly these sections: A. Component hierarchy: a text tree of every component from root to leaves. B. Contexts: for each context, its state shape, the actions it exposes, and its default value. C. Provider composition: the nesting order of the providers and why. D. Data flow: how each component reads from and writes to each context. E. Persistence strategy: what is saved to localStorage, when it is written, and how state is rehydrated on load. F. File structure: every file you propose, each with a one-line responsibility. Here is the requirements brief: [paste your requirements brief here]
  3. Read the entire draft once, end to end, before responding. Resist the urge to skim. Your review in Part 4 is graded on substance, and substance requires a full read.

  4. If the Architect included implementation code anywhere, reply with a correction, for example: “You included implementation code in section B. Replace it with a plain description of the state shape and actions.” Holding the AI to its role is part of the exercise.


Part 4: Product Manager Review (20 minutes)

A Product Manager does not rubber-stamp a plan. Evaluate the draft against this review checklist:

  • Context boundaries: Are the three contexts kept separate rather than merged into one large context? Lesson 5 explains why splitting contexts that change at different rates prevents unnecessary re-renders.
  • Memoization: Does the plan state that provider values are memoized with useMemo, and functions stabilized with useCallback, as covered in Lessons 5 and 6?
  • Persistence and rehydration: Is the persistence approach compatible with rehydration on load? State must be read from localStorage when the provider initializes, and written when it changes.
  • File organization: Does the file structure separate contexts, components, and any hooks into clear directories?
  • Scope discipline: Has the Architect avoided out-of-scope additions such as Redux, other state libraries, or router libraries?

Then complete the review:

  1. Write at least three substantive review comments in the chat. A substantive comment names a specific part of the plan and either challenges it, asks for a justification, or identifies a gap. “Looks good” is not a review comment. Examples of the expected caliber:

    • “Section C nests ThemeProvider inside TodoProvider. Justify the ordering, or confirm that the order carries no consequence here.”
    • “Section E writes to localStorage on every render. Under what conditions does the write actually run, and how do we avoid writing during the initial rehydration?”
    • “Section B gives FilterContext a default value of null. What happens to a consumer rendered outside the provider?”
  2. Request at least one specific revision and evaluate the revised plan when it arrives. Confirm the Architect marked what changed.

  3. When the plan satisfies the checklist, approve it explicitly in the chat, for example: “Approved as revised. This is the plan of record.”

  4. Record everything in ARCHITECTURE.md by adding three more sections, then commit:

    ## 2. Approved Architectural Plan (paste the final approved plan, sections A through F) ## 3. Product Manager Review Comments (paste your review comments from the chat, at least three) ## 4. Revision Record (what you asked the Architect to change, and how the plan changed)
    git add ARCHITECTURE.md git commit -m "Add approved architectural plan and PM review record"
Note

If your workspace allows it, use the Share button on the planning conversation and paste the public link at the top of ARCHITECTURE.md as supporting evidence. If sharing is disabled in your workspace, the review comments and revision record you copied into ARCHITECTURE.md serve as the evidence.


Part 5: Scaffold the Project with Claude Code (20 minutes)

With the plan approved, use Claude Code to create the skeleton of the approved file structure. Scaffolding only: empty shells, no logic.

  1. Create a CLAUDE.md file at the root of your repository so the boundary applies to the whole session:

    # Project Instructions This is a React Todo application built with the Context API. - The approved architectural plan lives in ARCHITECTURE.md, section 2. Do not deviate from it or create files it does not list. - Scaffolding only: context skeletons with state shapes and empty action stubs, component shells with props defined, and a TODO comment in every stub body. Do not write business logic, state updates, filtering, theming, or persistence logic. - Do not add libraries beyond what the Vite scaffold already includes.
  2. From the project directory, start Claude Code:

    claude
  3. Give it the scaffolding instruction:

    Read ARCHITECTURE.md. Scaffold exactly the file structure in section F of the approved plan, and nothing else. For each context file, create the context with its state shape and empty action stubs. For each component file, create the component shell with its props defined. Every stub body must contain only a TODO comment describing what I will implement there. Do not implement any business logic. Do not create files that are not in the approved plan.
  4. Claude Code asks permission before creating or editing files. Read each request and the proposed content deliberately before approving. Reject anything that is not in the approved plan, including helpful extras. If a proposed file contains implementation logic, reject it and restate the scaffolding-only rule. Rejecting at least one overreach, when one occurs, is exactly the Engineering discipline this course builds.

  5. When Claude Code finishes, review the result with Git before committing:

    git status git add . git diff --cached

    Read the staged diff file by file. Confirm every file matches section F of the plan and contains stubs only. Then commit:

    git commit -m "Scaffold approved architecture (stubs only)"
Note

To preview Claude Code’s intentions before it touches any files, press Shift+Tab to cycle to Plan Mode, review the proposed plan, then cycle back to the default mode to let it create the files.

If you are completing this lab without Claude Code, ask Claude in your claude.ai conversation for the skeleton of each file, one file at a time, and create the files manually. The same rule applies: stubs and TODO comments only.


Part 6: Implement the Application (60 to 75 minutes)

Now switch to the developer role. You personally write all implementation code in this part. You may ask Claude conceptual questions (for example, “Why does my provider value change identity on every render?”), but you may not ask it to write the implementation for you. The implementation must be your own work.

Work through the TODO stubs in this suggested order:

  1. ThemeContext first. It is the simplest: useState for the theme, a toggleTheme function, and a provider value memoized with useMemo. Wire up ThemeToggleButton and confirm the app container visibly changes with the theme.

  2. FilterContext. A useState for the current filter and a setFilter action, again with a memoized value. Wire up FilterButtons.

  3. TodoContext. Implement addTodo, toggleTodo, deleteTodo, editTodo, and clearCompleted. useReducer is a good fit for these state transitions, though a well-managed useState is also acceptable. Keep every update immutable: produce new arrays and objects rather than mutating existing ones. Wire up TodoInput, TodoList, and TodoItem, and make TodoList respect the active filter from FilterContext.

  4. Persistence layer. Rehydrate todos and theme when each provider initializes; passing a function to useState (a lazy initializer) is a clean way to read localStorage exactly once. Write updates back to localStorage whenever the persisted state changes, for example with a useEffect that depends on that state.

  5. Optimization pass. Confirm each provider value is memoized with useMemo and that the functions inside it are stabilized with useCallback, so consumers do not re-render when unrelated state changes. Lesson 5’s Performance Considerations section and Lesson 6’s optimization patterns are your reference.

Implementation guidelines carried over from Lab 3:

  • Provider composition: Wrap the application with the providers, ideally through a single AppProviders component (as shown in Lesson 6) to keep App clean. Follow the composition order in your approved plan.
  • TypeScript (optional but recommended): Define types or interfaces for your todo items, context values, and props.
  • Plan fidelity: If, while implementing, you discover the approved plan has a flaw, do what professionals do: fix the code, then update ARCHITECTURE.md with a dated note in the Revision Record explaining the deviation. Silent drift between plan and code loses points; documented deviation does not.

Commit your work in meaningful increments as you go.


Part 7: Reflection and Final Checks (10 minutes)

  1. Verify the finished application against the Project Requirements and against section 2 of ARCHITECTURE.md. Every context, action, component, and persistence behavior should be accounted for.

  2. Add a reflection section to your README.md (a paragraph or two is enough) describing one Architect proposal you rejected or changed as Product Manager, and why. Address: what the Architect originally proposed, what concern your review raised, and what the plan said after the revision.

  3. Make a final commit:

    git add . git commit -m "Complete Todo application per approved architecture"
  4. Create a new, empty repository on GitHub (do not initialize it with a README or a .gitignore, because your local repository already has its own history). Connect it as a remote and push:

    git remote add origin <your-github-repository-url> git branch -M main git push -u origin main

Submission Guidelines

Submit your project on Canvas via a GitHub repository link. The repository must contain:

  1. ARCHITECTURE.md with all four sections: the Requirements Brief, the Approved Architectural Plan (sections A through F), your Product Manager Review Comments (at least three), and the Revision Record (at least one requested and received revision). Include the shared conversation link at the top if sharing is available in your workspace.
  2. The complete, working Todo application, built to the approved plan and meeting all Project Requirements: three contexts with providers, all todo actions, filtering, theming, and the localStorage persistence layer.
  3. README.md containing the reflection from Part 7.

Grading Rubric

Your submission will be evaluated based on the following criteria.

CriteriaExcellentGoodFairNeeds Improvement
Context Design & Provider Setup
(TodoContext, FilterContext, ThemeContext correctly defined and provided)
15-13 pts
• All contexts clearly defined with appropriate default values.
• Providers correctly wrap the application, making context values accessible.
• TypeScript types (if used) are accurate and comprehensive.
12-10 pts
• Contexts are defined and providers are set up mostly correctly.
• Minor issues in default values or provider placement.
• Basic TypeScript types (if used) are present.
9-7 pts
• Some contexts are missing or incorrectly set up.
• Provider setup might be incomplete or flawed.
• TypeScript types (if used) are minimal or have errors.
6-0 pts
• Contexts and Providers are largely missing or non-functional.
• Core setup requirements not met.
State Management & Reducers/Updaters
(State logic for todos, filters, and theme within contexts)
15-13 pts
• All state update logic (add, toggle, delete, edit todos; set filter; toggle theme) is robust and correct.
useReducer (if used for todos) is implemented effectively.
• State is immutable.
12-10 pts
• Most state update logic is correct.
• Minor bugs may exist in some state transitions.
• State immutability is generally maintained.
9-7 pts
• Significant portions of state logic are missing or incorrect.
• May directly mutate state.
• Several actions might not work as expected.
6-0 pts
• State management logic is fundamentally flawed or largely missing for key features.
Application Functionality & Component Integration
(Todo app works as specified; components consume context correctly)
15-13 pts
• All features (CRUD, filtering, theme switching) work flawlessly.
• Components correctly consume context values and dispatch actions.
• UI is clear and reflects state accurately.
12-10 pts
• Most features work as expected.
• Components consume context generally well, with minor issues.
• UI mostly reflects state, some inconsistencies may exist.
9-7 pts
• Several core features are buggy or non-functional.
• Context consumption is problematic in multiple components.
• UI does not reliably reflect the application state.
6-0 pts
• Application is largely non-functional.
• Components fail to integrate with contexts properly.
Persistence Layer & Optimization
(State persisted to localStorage; basic optimization in context providers)
5 pts
• Todo and Theme states are correctly persisted to and rehydrated from localStorage.
useMemo/useCallback used appropriately in providers to stabilize context values.
4 pts
• Persistence is implemented for at least one major piece of state (e.g., todos).
• Some attempt at context value memoization.
3-2 pts
• Persistence is attempted but buggy or incomplete.
• Little to no context optimization.
1-0 pts
• Persistence and optimization attempts are missing or non-functional.
Architectural Plan & Product Manager Review
(ARCHITECTURE.md brief, review comments, revision record, plan fidelity)
15-13 pts
• Requirements brief is precise, complete, and states all constraints.
• Three or more substantive review comments engage specific parts of the plan.
• At least one revision requested and received, with the change documented.
• Delivered code matches the approved plan, or deviations are documented in the Revision Record.
12-10 pts
• Brief covers the requirements with minor gaps.
• Three review comments, at least two substantive.
• A revision was requested and received.
• Code mostly matches the plan, with small undocumented drift.
9-7 pts
• Brief is vague or missing constraints.
• Fewer than three review comments, or comments lack substance.
• Revision record is thin or unclear.
• Noticeable mismatch between plan and code.
6-0 pts
ARCHITECTURE.md is missing sections or largely incomplete.
• No meaningful evidence of review or revision.

Total Points Possible: 65