2.5.3 The `/issues` route — tree-table + header + toolbar + empty/loading
Estimate: 16m · Depends on: 2.5.1, 2.5.2
Replace the ProjectStubPage at app/(authed)/issues/page.tsx with the real surface. The Server Component resolves the active project (getActiveProject() → /dashboard if none), calls getProjectTree (2.5.1), and renders, top to bottom per tree.png: the "Issues" header + "All issues in {project}" subtitle; the toolbar — a [Filter] button (a disabled/placeholder shell here; wired in 2.5.4), the [Tree ▾] view-switcher (renders "Tree" as the active/only v1 mode — the documented seam for a future List mode), and the [+ New issue] button reusing 2.3.3's CreateIssueModal trigger; and the TreeTable (2.5.2) with the three columns — TITLE (IssueTypeIcon + identifier + title, the whole row linking to /issues/{identifier}), ASSIGNEE (avatar + name, "Unassigned" empty), STATUS (Pill by category).
Empty + loading states (mockup panels 2 & 3). A project with no issues renders the centered EmptyState ("No issues yet" / "Create your first issue to start tracking work." / a New-issue CTA). A Suspense/loading boundary renders the skeleton table (header + shimmer rows) drawn in panel 3. Expand/collapse state is client-held (default: roots expanded one level, matching the mockup); no per-row persistence in v1.
Acceptance criteria
/issuesrenders the active project's issues as the nested TreeTable with TITLE/ASSIGNEE/STATUS exactly pertree.png; each row links to its/issues/[key]detail page; rows expand/collapse.- Header + subtitle + the
[Filter]·[Tree ▾]·[+ New issue]toolbar render; "New issue" opens 2.3.3'sCreateIssueModal(no second create path); the view-switcher shows "Tree". - An empty project renders the drawn
EmptyState; a loading boundary renders the skeleton table. - 4-layer + explicit workspace gate (the page never queries Prisma directly); colours via
--el-*; type icons take their type hue, status viaPilltones. - Vitest over the page's data shaping (real PG: project-scoped nesting, empty); the route joins the shell-a11y sweep in 2.5.6 (needs the seeded fixture that spec builds).
Context refs
design/work-items/tree.png— all 3 panels (populated · empty · skeleton)app/(authed)/issues/page.tsx(the stub to replace) +_components/ProjectStubPage;getActiveProject(); the 2.4.1/issues/[key]detail page as the sibling/route convention- 2.3.3
CreateIssueModal/CreateIssueProvider/CreateIssueTrigger;EmptyState/Button/Pill/IssueTypeIcon; 2.5.2TreeTable; 2.5.1getProjectTree motir-core/CLAUDE.md— Server Component / 4-layer /--el-*