1. Spec
Wrote docs/spec.md: a small Kanban (boards, columns, cards), must-haves, API paths, and the four-step build (mock UI → OpenAPI → FastAPI in-memory → SQLite later).
2. Frontend + mock backend
Built a React/Vite app in frontend/. Every API call goes through frontend/src/services. The first client was createMockBoardService() (in-memory + localStorage), so the board ran with no server. Added Vitest tests (15 passing now).
3. Design record
Captured those choices as completed items in docs/tasks.md (single service layer, camelCase contract, seeded columns, reindex, no auth, and so on).
4. .gitignore
Added a root ignore file (and tightened the frontend one) for node_modules, env files, Python/venv caches, and editor junk.
5. OpenAPI contract
Read the service interface and wrote openapi.yaml at the repo root: 12 endpoints, camelCase JSON, { "detail": string } errors, no auth, server http://localhost:8091.
6. FastAPI backend (in-memory)
Implemented backend/ with models, store, and routers. Startup seeds a Workshop board. Tests: 8 passed. CORS allows the Vite app on 5173.
7. Repo layout
Confirmed frontend/, backend/, docs/, and openapi.yaml. Added the missing AGENTS.md (uv/make commands, service-layer rule, keep OpenAPI in sync).
8. make run
make run (and make backend) starts Uvicorn on 8091. make dev is the frontend; make test runs both test suites.
9. /docs vs openapi.yaml
Opened http://localhost:8091/docs. Paths, methods, and operationIds match. Swagger still advertises 422 and FastAPI validation schemas instead of spec 400/404 + Error; the app itself already returns 400/404 at runtime.

10. Connect frontend to backend
Switched the default client to createHttpBoardService() (http://localhost:8091, or VITE_API_URL). Mock stays for tests. In the browser, the seeded Workshop board loaded and a new card posted to FastAPI (POST .../cards 201).