Commit Graph
3 Commits
Author SHA1 Message Date
aneurinandClaude Sonnet 5 a85bb182c7 De-duplicate controller boilerplate: owned-project lookup, reorder validation
requireOwnedProjectId() was copy-pasted identically in CardController
and CardStatusController; ProjectController's own
requireOwnedProject() was the same lookup, just returning the full
row instead of the id. New abstract ProjectScopedController (extends
Controller) holds one copy of both, and all three controllers now
extend it instead of Controller directly, forwarding their
ProjectRepository to its constructor.

Separately, CardController::reorder() (card_ids) and
CardStatusController::reorder() (status_ids) each had the same inline
'must be an array of ids, no duplicates' check. Both now call a new
Validator::intIdArray(), which does the same shape check once.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 21:45:17 +01:00
aneurinandClaude Sonnet 5 c47c800d01 Add per-project card statuses and a kanban board
Statuses
- Migration 006: card_statuses table (project-scoped) and cards.status_id, a
  nullable FK with ON DELETE SET NULL. Every new project is seeded with
  "To do" / "Doing" / "Done"; GET /api/projects/{id}/statuses lists them.
- New cards have no status -- they sit in an "inbox" until moved.

Project view
- Full-width and tabbed: "All tasks" (a flat list, sorted by name
  case-insensitively) and "Kanban" (Inbox plus one column per status).
- Drag a card within or between columns to reorder / restatus; the Inbox
  column has its own name + Add form.

Ordering
- Migration 007: `position` is now a dense 0..n-1 rank within a
  (project_id, status_id) column, not a project-wide order. New composite
  index idx_cards_project_status_position; existing rows re-ranked.
- PUT /api/projects/{id}/cards/order takes { status_id, card_ids } and sets one
  column's contents and order, re-parenting moved-in cards and re-packing their
  source column in a single transaction. PATCH status_id appends the card to the
  end of the destination column.

58 phpunit tests pass; the frontend type-checks and builds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 13:37:17 +01:00
aneurinandClaude Sonnet 5 c66e5ceb9b Rename lists -> projects and items -> cards throughout
Project scope shifts from a todo list to a project-management app. This is a
straight terminology rename across code, comments, migrations, tests, and
docs — no behaviour change.

- DB: table todo_lists -> projects, todo_items -> cards, column
  todo_items.list_id -> cards.project_id, indexes renamed. Migrations 003/004
  rewritten in place (destructive; recreate the volume with `down -v`).
- API: /api/lists -> /api/projects, nested /items -> /cards, reorder body
  item_ids -> card_ids, JSON keys list/lists/item/items -> project/projects/
  card/cards, item_count -> card_count, list_id -> project_id, and the
  matching error messages.
- PHP: TodoList/TodoItem Repository + Controller -> Project/Card; shared SQL
  aliases l/i -> p/c.
- Frontend: stores lists.ts/items.ts -> projects.ts/cards.ts (useProjectsStore
  / useCardsStore, MAX_PROJECTS), ListView -> ProjectView, TodoItemRow ->
  CardRow, route /lists/:id -> /projects/:id (name "project"), types TodoList/
  TodoItem -> Project/Card, and all UI copy. CSS .lists*/.list-head* ->
  .projects*/.project-head*, .item* -> .card-row* (kept the generic .card
  panel class), .items -> .cards.
- Product name in the header, PWA manifest, index.html title and package
  descriptions -> "Project Manager" / "Projects".

Backend suite: 37 passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 11:28:59 +01:00