Add Page
Frontend-only: route + feature UI + API client. Assumes backend endpoints already exist.
Read first: ~/.cursor/skills/webapp-shared/reference.md
Mirror: frontend/src/features/auth/ and routing in frontend/src/app/.
Prerequisites
- Backend endpoints exist and are documented (paths, DTO shapes, auth requirements)
- Dev stack running (
docker compose up) or Vite dev with API reachable - Shared HTTP client in
frontend/src/shared/handles Bearer + refresh
Gather inputs
| Input | Example |
|---|---|
| Feature/page name | todos |
| Route path(s) | /todos, /todos/:id |
| API endpoints | GET /api/todos, POST /api/todos |
| Auth required | yes (default) |
| Page type | list, detail, form, dashboard |
Checklist
Add-page progress:
- [ ] 1. Confirm API contract (paths, JSON shapes)
- [ ] 2. Add types.ts matching DTOs
- [ ] 3. Add {feature}Api.ts using shared client
- [ ] 4. Build page components
- [ ] 5. Register routes in src/app
- [ ] 6. Add nav link (if requested)
- [ ] 7. Loading + error states
- [ ] 8. Vitest smoke test
- [ ] 9. Manual verify in browser
Step 1: Confirm API contract
Before coding, verify against running API or OpenAPI/README:
curl -sf http://localhost:8080/api/health
# Login if needed; test target endpoint with Bearer token
Record request/response JSON for each call the page will make.
Step 2: Types
Create frontend/src/features/{feature}/types.ts:
// Match backend DTO property names (camelCase in JSON if API serializes that way)
export interface TodoItem { id: string; title: string; isDone: boolean }
export interface CreateTodoRequest { title: string }
Check existing auth types for serialization conventions.
Step 3: API module
Create frontend/src/features/{feature}/{feature}Api.ts:
- Import shared HTTP helper from
src/shared/(same as auth feature) - Export typed functions:
listTodos(),createTodo(body), etc. - Do not duplicate refresh logic — shared client handles 401 → refresh → retry
- Do not put access tokens in
localStorage
Mirror features/auth/ API module structure.
Step 4: Pages and components
frontend/src/features/{feature}/
├── pages/
│ ├── {Feature}ListPage.tsx
│ └── {Feature}DetailPage.tsx # if needed
├── components/
│ └── {Feature}Form.tsx
├── {feature}Api.ts
└── types.ts
Each page should handle:
- Loading: skeleton or spinner
- Error: user-visible message (network, 401 → redirect to login via auth provider)
- Empty: sensible empty state
Use existing shared UI primitives from src/shared/ when available.
Step 5: Routes
In frontend/src/app/ router configuration:
// Example pattern — match existing router library (react-router, etc.)
{ path: '/todos', element: <ProtectedRoute><TodoListPage /></ProtectedRoute> }
- Wrap with auth guard if endpoints require
[Authorize] - Follow how
/login,/register, and home routes are registered in auth feature
Step 6: Navigation
If user wants nav entry, add link in app layout/sidebar — same component auth uses for post-login navigation.
Step 7: Tests
Add Vitest + Testing Library test in frontend/tests/ or colocated *.test.tsx:
- Render page with mocked API
- Assert key heading or list item appears
Keep smoke-level — mirror auth form tests.
Step 8: Verify
docker compose up -d web # if only frontend changed
cd frontend && npm test -- --run
Browser check at http://localhost:5173:
- Route loads without console errors
- Authenticated calls succeed (login first if needed)
- 401 redirects to login
If API missing
Stop and tell user to run /add-entity or /add-feature first. Do not invent backend endpoints from the frontend skill.
Do not
- Create backend files in this skill
- Store access tokens in
localStorage - Bypass shared HTTP client for authenticated calls
- Invent routes outside
src/app/+src/features/layout
Related skills
- Need backend too →
add-featureoradd-entity - Local dev issues →
dev-webapp