We learn best by doing.
Let’s build something.
Mini feature: Toggle “completed” on a Todo
New endpoint: POST /todos/:id/complete
completed = true, return 200404Why this feature?
Small enough to finish in one session. Rich enough to exercise the full workflow.
Stack: Express + TypeScript
Tiny in-memory Todo API at examples/express-todo-ts
src/
models/todo.ts # Type definition
routes/todos.ts # Route handlers (GET, POST)
services/todoService.ts # In-memory store
tests/
todos.test.ts # Jest + supertest
Existing endpoints: GET /todos and POST /todos.
We’ll add the completion endpoint together.
What you need:
cd examples/express-todo-ts
pnpm install
Open the project in Cursor and notice:
src/models, src/routes, src/services, tests/.cursorrules or AGENTS.md – AI has zero project-specific context“There are no rules files. The AI doesn’t know our conventions. Keep that in mind as you review what it generates.”
Open Cursor chat in Ask mode:
We're in the Express + TypeScript project at @examples/express-todo-ts.
Where is the Todo API implemented?
Please:
- List the main files (models, routes, services, tests).
- Summarize in 3-5 bullet points how it currently works.
Do not change any code yet.
What to notice:
@src and @tests to give contextWe want to add a feature to the Express + TypeScript Todo API:
- Endpoint: POST /todos/:id/complete
- Behavior:
- If exists -> set completed = true, return 200
- If not found -> return 404
- If already completed -> return current state (idempotent)
Tasks:
1. Propose 3-5 Jest test cases for this behavior.
2. Write the test functions in the test file, matching existing style.
3. Stop after the tests — do not implement the endpoint yet.
Run pnpm test — they should fail. That’s the point.
Once tests are failing:
Now implement the feature so that the new tests pass.
Constraints:
- Keep existing behavior of the Todo API unchanged.
- If you need to touch multiple files, list them first.
- Prefer small, focused changes.
Use either:
Cmd/Ctrl+K) inside route/service filesReview the proposed changes before accepting:
Apply the edits and run the full test suite.
Review checklist:
Commit small and descriptive:
git commit -m "test: add tests for POST /todos/:id/complete"
git commit -m "feat: implement todo completion endpoint"
After implementing, review the AI-generated code. The AI likely put the logic directly in the route handler:
// Business logic in the route — works, but doesn't scale
todosRouter.post("/:id/complete", (req, res) => {
const todo = listTodos().find((t) => t.id === id);
todo.completed = true;
return res.status(200).json(todo);
});
Prompt for refactoring:
Move the completion logic from the route handler into a
completeTodo(id) function in src/services/todoService.ts.
Keep route handlers thin. Keep tests passing.
Think about: Is the new structure easier to test? Easier for a new developer to understand?
What felt fast?
Boilerplate, test scaffolding, repetitive patterns.
Where did human judgment matter most?
Deciding the endpoint behavior. Reviewing the implementation and edge cases.
Which golden rules did we actually use?
Context-first, iterative, plan mode, tests first, mandatory review.
Where would AI have gone wrong
if nobody reviewed the code?
If you have more time:
Error handling & logging
Add structured logs to the new endpoint. Ask AI to propagate consistent logging across related routes.
Security checks
Require authentication for the /complete endpoint. Ask AI for potential security pitfalls in the new code.
Database migration
Replace the in-memory store with SQLite. See how the service-layer abstraction makes this easier.
Each extension reinforces the same core habits: think first, prompt with context, keep steps small, review everything.
The workflow
Ask -> Plan -> Agent -> Review
The habits
The mindset
AI accelerates the work — you own the decisions.
From writing code to owning the design.