diff --git a/.planning/STATE.md b/.planning/STATE.md index c3cc6b3..a2d4bdf 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -233,6 +233,10 @@ Recent decisions affecting current work: - 20-02: Subscription-driven invalidation (not local state) — simplest approach, reuses existing React Query cache - 20-02: Silent onError callbacks — pages degrade to manual refresh when backend is not running - 20-02: No new packages needed — splitLink and httpSubscriptionLink ship with @trpc/client v11 +- 21-01: ErrorBoundary wraps Outlet only (not entire AppLayout) so nav shell survives render errors +- 21-01: Toaster outside AppLayout as sibling — available even if layout breaks +- 21-01: notFoundComponent uses shadcn Button with asChild + Link (consistent with component library) +- 21-01: One success and one error toast per mutation — no toasts for query failures (those have inline error states) - 21-02: Skeleton component in components/ (not ui/) — app-specific, not a shadcn primitive - 21-02: Inbox skeleton lives in inbox.tsx route (not InboxList component) since InboxList receives pre-loaded data - 21-03: Removed disabled nav stubs (Agents, Tasks, Settings) — stubs create false promises for v2.0 diff --git a/.planning/phases/21-polish-integration/21-01-SUMMARY.md b/.planning/phases/21-polish-integration/21-01-SUMMARY.md new file mode 100644 index 0000000..d9a6657 --- /dev/null +++ b/.planning/phases/21-polish-integration/21-01-SUMMARY.md @@ -0,0 +1,44 @@ +# Plan 21-01 Summary: Error Boundary & Toast Notifications + +## Result: COMPLETE + +**Duration:** ~3 min +**Commits:** 2 + +## What was done + +1. **Created ErrorBoundary component** (`packages/web/src/components/ErrorBoundary.tsx`) + - React class component with `getDerivedStateFromError` and `componentDidCatch` + - Renders centered error card: red AlertCircle icon, "Something went wrong" heading, error message in muted text, Reload button + - Styled with existing Tailwind classes matching the app's error state patterns + +2. **Created Sonner toast wrapper** (`packages/web/src/components/ui/sonner.tsx`) + - Thin wrapper exporting `Toaster` component from sonner + - Configured with `position="bottom-right"` and `richColors` + +3. **Wired into root route** (`packages/web/src/routes/__root.tsx`) + - `` wraps `` inside AppLayout so route-level render errors are caught without destroying the nav shell + - `` rendered as sibling to AppLayout for app-wide toast availability + - `notFoundComponent` updated with "Back to Dashboard" Button/Link pointing to /initiatives + +4. **Wired toast notifications into all mutation flows** + - `SpawnArchitectDropdown.tsx`: `toast.success("Architect spawned")` on success, `toast.error("Failed to spawn architect")` on error + - `ActionMenu.tsx`: `toast.success("Initiative archived")` on success, `toast.error("Failed to archive initiative")` on error + - `CreateInitiativeDialog.tsx`: `toast.success("Initiative created")` on success (inline error kept for form validation) + - `inbox.tsx`: `toast.success`/`toast.error` for both `resumeAgent` and `respondToMessage` mutations + +## Decisions + +- 21-01: ErrorBoundary wraps Outlet only (not entire AppLayout) so nav shell survives render errors +- 21-01: Toaster outside AppLayout as sibling — available even if layout breaks +- 21-01: notFoundComponent uses shadcn Button with asChild + Link (consistent with component library) +- 21-01: CreateInitiativeDialog keeps inline form error in addition to toast (inline error shows specific validation message) +- 21-01: One success and one error toast per mutation — no toasts for query failures (those have inline error states) + +## Verification + +- [x] `npx tsc --noEmit -p packages/web/tsconfig.app.json` — passes +- [x] `npm run --workspace=packages/web build` — succeeds +- [x] ErrorBoundary component exists and is wired into root route +- [x] Toaster component rendered in root route +- [x] All mutation callbacks use toast instead of (or in addition to) console.error