4.5.3 Scrum board page + sprint header UI — resolve scrum board, render sprint header + points + no-active-sprint state (reuses the 3.2/3.3 board)
Estimate: 30m · Depends on: 4.5.1, 4.5.2, 3.2.6, 4.4
Render the Scrum variant of the board page — the sprint header + per-column point totals + the no-active-sprint empty state — drawn per design/boards/scrum.mock.html, reusing the Story-3.2 board (columns, cards, drag-as-transition, load-more/virtualization) and the Story-3.3 swimlanes/WIP layer wholesale. This is chrome + page resolution, NOT a second board.
Scrum-board resolution. The /boards page (3.2.2) currently renders the project's default Kanban board. Extend it so that when the resolved board's type == scrum (a scrum board provisioned by Story 4.1/4.4) it renders the Scrum variant; a kanban board renders exactly as today. Which board is resolved when a project has both is a board-nav concern (out of scope — see story Out-of-scope, Story 3.7); 4.5 keys purely off the resolved board's type. No new navigation wiring (the "Boards" nav + ⌘K entry already point at /boards, Story 1.5).
Sprint header. Above the reused board, render the header from the 4.5.2 SprintSummaryDto: sprint name + state Pill, the goal (one line, Tooltip/reveal for the full text), the date range + time remaining ("5 days remaining" / "Ends Jun 14" / "Ended" when daysRemaining == 0 and past endDate), and the points summary (committed / completed / remaining as labelled numbers; "—" when the sprint is unestimated). Text+number always, never colour alone (finding #35). The header is a labelled landmark. Per-column point totals render the columnPoints value as the "sprint health" pill in each reused column header (the 3.2.1/3.3 header slots), without crowding the count badge + WIP slot.
Complete-sprint entry point (reuse 4.4, do NOT rebuild). Mount the complete-sprint button in the header. The complete-sprint FLOW (confirm modal + carry-over + sprint report) is Story 4.4: if 4.4 exposes a mountable trigger/action, 4.5 mounts it; otherwise 4.5 renders the button as a seam 4.4 wires (the 3.2 Epic-6 Filter-seam pattern). 4.5 does NOT implement carry-over or the report.
No-active-sprint empty state. When the projection returns sprint: null for a scrum board, render an EmptyState in place of the board — "No active sprint", a one-line explainer, and a CTA linking to the Backlog (Story 4.2 route) to plan/start one (4.5 does NOT start a sprint — that's 4.2/4.4). This is visually distinct from the 3.2.6 "No issues" empty-board state. Loading reuses the 3.2.2 board scaffold (header skeleton + column skeletons); error reuses the 3.2.2 ErrorState.
Reuse, not rebuild (load-bearing). Render the SAME BoardColumn/BoardCard, the SAME dnd-kit DndContext + drop handler (drag is still a workflow transition — unchanged), the SAME 3.2.5 load-more/virtualization, and the SAME 3.3 group-by + swimlanes + WIP — fed the 4.5.2 sprint-scoped projection. Swimlanes/WIP work on the scrum board for free because it is the same component. The only net-new components are SprintHeader + the scrum no-sprint state + the page-level type resolution.
Out of scope here: the projection/aggregates (4.5.2); the sprint lifecycle + complete-sprint flow (4.4); the burndown chart (4.6 — the header shows numeric remaining + leaves a seam); board CRUD / multi-board nav (Story 3.7).
Acceptance criteria
/boardsrenders the Scrum variant when the resolved boardtype == scrumand the existing Kanban view whentype == kanban(no regression); no new navigation wiring.- The sprint header renders name + state pill + goal (with reveal) + date range + time remaining ("Ended" at
daysRemaining == 0pastendDate) + committed/completed/remaining points ("—" when unestimated), as a labelled landmark, text+number not colour-alone (finding #35); per-column point totals render in the reused column headers without crowding the count/WIP slots. - The complete-sprint entry point is mounted in the header and REUSES the Story-4.4 flow (or is a 4.4-wired seam); 4.5 does NOT implement carry-over/report.
- A scrum board with no active sprint shows the "No active sprint"
EmptyState(CTA → Backlog), distinct from the 3.2.6 no-issues state; loading/error reuse the 3.2.2 scaffold/ErrorState. - The board body, drag-as-transition, load-more/virtualization, and swimlanes/WIP are the REUSED 3.2/3.3 components fed the sprint-scoped projection — not reimplemented; a card move still transitions status and does not change the sprint.
- Colours via
--el-*, shape via element tokens, AA-safe; matchesdesign/boards/scrum.mock.html. - Component tests assert the type-resolution (scrum vs kanban), the header render (incl. "Ended" + "—" + points), the per-column point pill, and the no-active-sprint empty state.
Context refs
app/(authed)/boards/page.tsx+app/(authed)/boards/_components/*(Stories 3.2.2–3.2.6) — the board page + container/BoardColumn/BoardCard/dnd-kit/load-more to extend (resolve bytype, mount the header), NOT forkapp/(authed)/boards/_components/*swimlane/WIP additions (Story 3.3.5/3.3.6) — the group-by + WIP layer that composes on the scrum board unchanged- Story 4.5.2 — the
sprint+columnPoints+ sprint-scoped projection this binds to; Story 4.4 — the complete-sprint flow the header reuses; Story 4.2 — the Backlog route the empty-state CTA links to components/ui/*(Pill,Tooltip,EmptyState,ErrorState,Button) +design/boards/scrum.mock.html+ design-notes (4.5.1) — the header/state spec- finding #35 (not colour-alone), #54 (use the palette);
motir-core/CLAUDE.md—--el-*+ element-shape rules (client UI)