Feature #1546
closedFeature #1511: Replace ticket view with Kanban board for CTO and assigned developers
Frontend: Kanban board replaces the ticketing list view
0%
docs/superpowers/specs/2026-08-03-kanban-board-design.md
Description
**Surface:** frontend (`src/` + `app/`)
**Depends on:** "API: per-viewer visibility matrix and per-card drag capability", "API: per-user board column preferences", "Design: Kanban board section in the design system"
**Blocks:** "Frontend: board polling, manual refresh and card-move animation"
Replace the master–detail list at `app/projects/[id]/ticketing/page.tsx` with the Kanban board — **in place, for every viewer** (decision **D1**). No overlay, no new tab, no toggle back to a list. This supersedes the epic's original AC #2 ("visible only to the CTO and the assigned developer"): the board is visible to all, and *card scope and drag rights* follow the D2 matrix, which the server already applied to the payload.
- Add **dnd-kit** to `package.json` — no DnD library exists in the tree today.
- Columns from the existing `STAGE_ORDER` (`src/features/overview/kpis.ts:313`). Do not re-derive or hard-code an order.
- Cards render title, assignee, priority and parent from the extended list payload, per the approved design section.
- **Drag rights come only from the server fields** on each card (`can_move_forward`, `next_status_id`, `allowed_statuses`). No role predicate, no status-order array, no client-side transition rules — the internal-roles rule in `docs/superpowers/specs/2026-07-31-internal-roles-design.md`.
- Drops go through the shipped `useTransitionTask` hook (`src/features/tasks/useTransitionTask.ts`), optimistically, with rollback and a visible localised error on 403 and 409.
- Column filter reads/writes the preferences endpoints, optimistic locally and reconciled against the server.
- Build with Atomic Design placement under `src/components/`; no recharts import.
## Acceptance criteria
- [ ] `/projects/[id]/ticketing` renders the board; the previous list/table is **gone** — no overlay, no new tab, no toggle back to it. Every viewer lands on the board.
- [ ] Columns follow `STAGE_ORDER` with no locally redefined status order; Shipped is hidden on first visit.
- [ ] Cards display title, assignee, priority and parent, with defined fallbacks for null assignee, null priority and no parent.
- [ ] Drag enablement and legal targets derive **exclusively** from the server capability fields; a grep-level or lint assertion proves no `internal_role` check and no status-order array was added under `src/`.
- [ ] **A client cannot initiate a drag at all** — no drag handle rendered and the pointer sensor never activates; asserted by a test that fires pointer-down + move and expects no drag-start. Not merely a rejected drop.
- [ ] The same holds for any card whose `can_move_forward` is false, including every Backlog card.
- [ ] A developer's board shows only their assigned tickets, each accepting only its single server-provided forward target.
- [ ] A CTO's board accepts the full server-allowed set including backward moves.
- [ ] Backlog and Blocked columns render but reject every drop for every role, showing the designed invalid-target state, and **fire zero network calls** when a drop is attempted on them.
- [ ] A legal drop moves the card optimistically; on 403 or 409 it rolls back to its origin column and surfaces the designed localised error. Both outcomes covered by tests.
- [ ] Over-cap: a column whose `has_more` is true renders the designed "+N more" affordance; no infinite scroll in v1.
- [ ] The column filter persists via the preferences endpoints, applies optimistically, reverts on write failure, and survives a full page reload.
- [ ] A keyboard-only alternative to moving a card works per the design section, driven in a test with keyboard events only.
- [ ] Every visible string comes from next-intl; **both** `en.ts` and `fr.ts` updated with identical keys and ICU placeholders/plural branches, `fr.ts` a real French translation. A test asserts no hardcoded user-facing literal in the board components.
- [ ] Gates green: `npx vitest run && npx tsc --noEmit && npx eslint . && npm run build` (node 20.20.2 via nvm).
Files