# Cursor: Plan-File API Refactor Playbook

> Extract a monolithic Express app into route modules and typed services using Cursor's Composer with an explicit plan.md contract.

**Platform:** Cursor  
**Category:** coding  
**Difficulty:** Advanced  
**Tags:** cursor, refactor, typescript, coding  
**Updated:** 2026-06-04  
**Source:** https://promptfoo.tech/workflows/cursor-plan-file-api-refactor

## Overview
A 3,000-line index.js is not a codebase, it's a hostage situation. This playbook uses Cursor's Composer with a plan.md file to extract routes into modules, introduce a services layer, and add zod-validated request schemas — while running tests between each phase.

## How it works
1. Author plan.md with target file structure, naming rules, and validation contract.
2. Composer processes one route group per phase (auth, users, orders, admin).
3. Between phases: typecheck + integration tests must pass before continuing.
4. Each phase becomes a commit; the plan file is the north star and doc.

## Benefits
- Refactors ship in days, not months.
- Plan.md is the review artifact reviewers actually engage with.
- Type safety introduced without stopping the world.

## Use cases
- Legacy Express/Koa APIs with growing complexity.
- Consolidating microservices back into a modular monolith.
- Preparing a codebase for a new team to inherit.

## Step-by-step
### Step 1: Write plan.md
Target: src/routes/{group}/index.ts, src/services/{name}.ts. Every route validates input with zod. No inline SQL.

### Step 2: Phase 1: skeleton
Create empty folders/files. Composer generates the barrel exports and app.ts wiring. Commit.

### Step 3: Phase 2: extract routes group by group
Auth first (highest risk). Move handlers into the new file, keep tests green, delete the old code. Commit per group.

### Step 4: Phase 3: services layer
Extract business logic into src/services. Route handlers become 5-10 lines: validate → call service → shape response.

### Step 5: Phase 4: zod validation
Add request schemas per route. Fail fast on invalid input. Update tests to expect 400s for missing fields.

### Step 6: Phase 5: enforce with lint
ESLint rule to ban route files > 80 lines and services with unvalidated input. Locks in the pattern.

## Example
```
plan.md rule: 'Every route file must export default a router. Handlers must be < 15 lines and call at most one service method.'
```

## FAQs
**How long?**

1-2 days for a 3-5K LOC monolith with tests. Longer if tests are thin (add them first).

**Framework agnostic?**

Same plan structure works for Fastify, Hono, or NestJS. Only the wiring differs.

**Which model?**

Sonnet 4 for all phases. Opus for edge cases where the model gets stuck.

---
Licensed under CC-BY-4.0. Attribution: PromptFoo.tech