Problem
Next.js App Router supports per-segment error.tsx and not-found.tsx files that gracefully render a UI when a server component throws or a route doesn't match. The repo currently has none — every uncaught server error renders the framework's default error screen, and any unknown route falls back to the framework's default 404. This is jarring for users and makes incident triage harder because there's no opportunity to log a correlation id or render a friendly retry CTA.
Evidence
- A repo-wide search for
error.tsx, not-found.tsx returns no matches under src/app/.
- All segments rely on Next's defaults.
Proposed approach
-
Create src/app/error.tsx (root error boundary):
\"use client\" per Next.js docs.
- Receives
{ error, reset } props.
- Logs
error.digest and error.message via the structured logger (or console.error for now).
- Renders a shadcn/ui
Card with title "Something went wrong", body containing error.digest (collapsed), and a button calling reset().
-
Create src/app/not-found.tsx:
- Renders a shadcn/ui card with "Page not found" + a
Link back to /.
-
Create segment-level error.tsx for each major route group, reusing a shared ErrorState component to keep them DRY:
src/app/assignments/error.tsx
src/app/budget/error.tsx
src/app/invoices/error.tsx
src/app/copilot/error.tsx
src/app/claude/error.tsx
src/app/reports/error.tsx
src/app/settings/error.tsx
-
Extract the shared component to src/components/error-state.tsx so per-segment files are 5–10 lines.
-
Make sure the error boundary preserves the sidebar layout — wrap ErrorState so it renders inside the existing <AppShell> rather than full-page.
-
Add a Playwright smoke test (1 spec, 2 cases) that:
- Navigates to
/__nope__ and asserts the not-found UI renders.
- (Optional) hits a route segment with a deliberately throwing dev-only flag and asserts the error UI renders.
Acceptance criteria
Verification
pnpm dev, navigate to http://localhost:3000/__nope__ → expect the new 404 UI.
- Temporarily throw
new Error(\"boom\") at the top of any server component (e.g. src/app/copilot/page.tsx) → expect the segment error UI with a Try Again button. Revert.
- Click "Try Again" → page re-renders without a hard reload.
Problem
Next.js App Router supports per-segment
error.tsxandnot-found.tsxfiles that gracefully render a UI when a server component throws or a route doesn't match. The repo currently has none — every uncaught server error renders the framework's default error screen, and any unknown route falls back to the framework's default 404. This is jarring for users and makes incident triage harder because there's no opportunity to log a correlation id or render a friendly retry CTA.Evidence
error.tsx,not-found.tsxreturns no matches undersrc/app/.Proposed approach
Create
src/app/error.tsx(root error boundary):\"use client\"per Next.js docs.{ error, reset }props.error.digestanderror.messagevia the structured logger (orconsole.errorfor now).Cardwith title "Something went wrong", body containingerror.digest(collapsed), and a button callingreset().Create
src/app/not-found.tsx:Linkback to/.Create segment-level
error.tsxfor each major route group, reusing a sharedErrorStatecomponent to keep them DRY:src/app/assignments/error.tsxsrc/app/budget/error.tsxsrc/app/invoices/error.tsxsrc/app/copilot/error.tsxsrc/app/claude/error.tsxsrc/app/reports/error.tsxsrc/app/settings/error.tsxExtract the shared component to
src/components/error-state.tsxso per-segment files are 5–10 lines.Make sure the error boundary preserves the sidebar layout — wrap
ErrorStateso it renders inside the existing<AppShell>rather than full-page.Add a Playwright smoke test (1 spec, 2 cases) that:
/__nope__and asserts the not-found UI renders.Acceptance criteria
error.tsxandnot-found.tsxexist and render the shared component.error.tsxfiles cover the major route groups listed above.ErrorStatecomponent is reused everywhere — no copy-pasted JSX.pnpm lint && pnpm typecheckpass.Verification
pnpm dev, navigate tohttp://localhost:3000/__nope__→ expect the new 404 UI.new Error(\"boom\")at the top of any server component (e.g.src/app/copilot/page.tsx) → expect the segment error UI with a Try Again button. Revert.