From 81814ac213f7ff7c4f1fcdcb8d862aa05b854e9c Mon Sep 17 00:00:00 2001 From: Lukas May Date: Thu, 5 Feb 2026 07:46:36 +0100 Subject: [PATCH] docs(21): create phase plan for Polish & Integration Phase 21: Polish & Integration - 6 plans in 3 waves - 3 parallel (Wave 1), 2 parallel (Wave 2), 1 sequential (Wave 3) - Ready for execution --- .planning/ROADMAP.md | 11 +- .../21-polish-integration/21-01-PLAN.md | 95 +++++++++++++++ .../21-polish-integration/21-02-PLAN.md | 94 +++++++++++++++ .../21-polish-integration/21-03-PLAN.md | 102 ++++++++++++++++ .../21-polish-integration/21-04-PLAN.md | 101 ++++++++++++++++ .../21-polish-integration/21-05-PLAN.md | 111 ++++++++++++++++++ .../21-polish-integration/21-06-PLAN.md | 104 ++++++++++++++++ 7 files changed, 615 insertions(+), 3 deletions(-) create mode 100644 .planning/phases/21-polish-integration/21-01-PLAN.md create mode 100644 .planning/phases/21-polish-integration/21-02-PLAN.md create mode 100644 .planning/phases/21-polish-integration/21-03-PLAN.md create mode 100644 .planning/phases/21-polish-integration/21-04-PLAN.md create mode 100644 .planning/phases/21-polish-integration/21-05-PLAN.md create mode 100644 .planning/phases/21-polish-integration/21-06-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index df8b6fb..ed28950 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -319,10 +319,15 @@ Plans: **Goal**: Cross-screen navigation, error states, loading states, responsive layout, integration testing **Depends on**: Phase 20 **Research**: Unlikely (polish and integration of existing screens) -**Plans**: TBD +**Plans**: 6 plans Plans: -- [ ] 21-01: TBD (run /gsd:plan-phase 21 to break down) +- [ ] 21-01: Error Boundary & Toast Notifications +- [ ] 21-02: Skeleton Loading States +- [ ] 21-03: Cross-Screen Navigation & Mobile Responsive +- [ ] 21-04: Subscription Error Handling +- [ ] 21-05: Code Splitting & Performance +- [ ] 21-06: Integration Smoke Test ## Progress @@ -353,7 +358,7 @@ Phases execute in numeric order: 1 → 1.1 → 2 → 3 → 4 → 5 → 6 → 7 | 18. Initiative Detail | v2.0 | 4/4 | Complete | 2026-02-04 | | 19. Agent Inbox | v2.0 | 4/4 | Complete | 2026-02-04 | | 20. Real-time Subscriptions | v2.0 | 2/2 | Complete | 2026-02-04 | -| 21. Polish & Integration | v2.0 | 0/? | Not started | - | +| 21. Polish & Integration | v2.0 | 0/6 | Not started | - | --- *Roadmap created: 2026-01-30* diff --git a/.planning/phases/21-polish-integration/21-01-PLAN.md b/.planning/phases/21-polish-integration/21-01-PLAN.md new file mode 100644 index 0000000..f2574a6 --- /dev/null +++ b/.planning/phases/21-polish-integration/21-01-PLAN.md @@ -0,0 +1,95 @@ +--- +phase: 21-polish-integration +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: [packages/web/src/components/ui/sonner.tsx, packages/web/src/components/ErrorBoundary.tsx, packages/web/src/main.tsx, packages/web/src/routes/__root.tsx, packages/web/package.json] +autonomous: true +--- + + +Add global error boundary and toast notification system to the frontend. + +Purpose: Right now render errors crash the app with a white screen, and mutations succeed/fail with no user feedback (SpawnArchitectDropdown, ActionMenu use console.error only). This plan adds the two foundational UX patterns everything else depends on. +Output: ErrorBoundary wrapping the app, Sonner toast provider, and toast utility ready for use. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@packages/web/src/main.tsx +@packages/web/src/routes/__root.tsx +@packages/web/src/layouts/AppLayout.tsx +@packages/web/src/components/SpawnArchitectDropdown.tsx +@packages/web/src/components/ActionMenu.tsx +@packages/web/src/components/CreateInitiativeDialog.tsx + + + + + + Task 1: Add Sonner toast provider and ErrorBoundary component + packages/web/src/components/ErrorBoundary.tsx, packages/web/src/components/ui/sonner.tsx, packages/web/src/main.tsx, packages/web/src/routes/__root.tsx, packages/web/package.json + + 1. Install sonner: `npm install --workspace=packages/web sonner` + 2. Create `packages/web/src/components/ui/sonner.tsx` — thin wrapper exporting Toaster component from sonner, styled to match the app's shadcn theme (use `richColors` prop, `position="bottom-right"`). + 3. Create `packages/web/src/components/ErrorBoundary.tsx` — React class component with `componentDidCatch`. Render a centered error card with: red AlertCircle icon, "Something went wrong" heading, error.message in muted text, and a "Reload" button that calls `window.location.reload()`. Style with existing Tailwind classes matching the app's error patterns (see InitiativeDetailPage error state for reference). + 4. In `packages/web/src/routes/__root.tsx` — add the `` component as a sibling to `` inside the root route component. Also wrap `` (inside AppLayout) with `` so route-level render errors are caught without destroying the nav shell. Import both from their respective paths. + 5. Update the `notFoundComponent` in __root.tsx to include a "Back to Dashboard" Link button (from @tanstack/react-router) pointing to /initiatives. + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + ErrorBoundary catches render errors with recovery UI. Toaster provider available app-wide. NotFound page has navigation back to dashboard. + + + + Task 2: Wire toast notifications into existing mutation flows + packages/web/src/components/SpawnArchitectDropdown.tsx, packages/web/src/components/ActionMenu.tsx, packages/web/src/components/CreateInitiativeDialog.tsx, packages/web/src/routes/inbox.tsx + + 1. In `SpawnArchitectDropdown.tsx`: Replace `console.error` in onError with `toast.error('Failed to spawn architect')`. Add `toast.success('Architect spawned')` in onSuccess. Import `toast` from `sonner`. + 2. In `ActionMenu.tsx`: Replace `console.error` in handleArchive's catch/error with `toast.error('Failed to archive initiative')`. Add success toast on archive complete. + 3. In `CreateInitiativeDialog.tsx`: Add `toast.success('Initiative created')` in the mutation's onSuccess callback (after dialog closes). Add `toast.error(...)` in onError if not already showing inline error. + 4. In `inbox.tsx`: Add `toast.success('Answer submitted')` to resumeAgentMutation.onSuccess. Add `toast.error('Failed to submit answer')` to onError. Same pattern for respondToMessageMutation. + + Import `toast` from `sonner` in each file. Keep it minimal — one success and one error toast per mutation. Do NOT add toasts for query failures (those already have inline error states). + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + All mutation flows show toast feedback on success/failure. No more silent console.error-only failures. + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] `npm run --workspace=packages/web build` succeeds +- [ ] ErrorBoundary component exists and is wired into root route +- [ ] Toaster component rendered in root route +- [ ] All mutation callbacks use toast instead of console.error + + + + +- All tasks completed +- All verification checks pass +- No TypeScript errors introduced +- ErrorBoundary catches render errors with recovery UI +- Toast notifications appear for all mutation success/failure flows + + + +After completion, create `.planning/phases/21-polish-integration/21-01-SUMMARY.md` + diff --git a/.planning/phases/21-polish-integration/21-02-PLAN.md b/.planning/phases/21-polish-integration/21-02-PLAN.md new file mode 100644 index 0000000..19258ec --- /dev/null +++ b/.planning/phases/21-polish-integration/21-02-PLAN.md @@ -0,0 +1,94 @@ +--- +phase: 21-polish-integration +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: [packages/web/src/components/Skeleton.tsx, packages/web/src/components/InitiativeList.tsx, packages/web/src/components/InboxList.tsx, packages/web/src/routes/initiatives/$id.tsx] +autonomous: true +--- + + +Replace plain-text "Loading..." messages with skeleton loading states across all three screens. + +Purpose: Every page currently shows bare "Loading initiatives..." / "Loading inbox..." text. Skeleton placeholders communicate structure and reduce perceived latency. This is purely visual polish — no data-fetching changes. +Output: Skeleton component and skeleton loading states on dashboard, detail, and inbox pages. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@packages/web/src/components/InitiativeList.tsx +@packages/web/src/components/InboxList.tsx +@packages/web/src/routes/initiatives/$id.tsx +@packages/web/src/routes/inbox.tsx + + + + + + Task 1: Create Skeleton component and apply to dashboard + inbox list views + packages/web/src/components/Skeleton.tsx, packages/web/src/components/InitiativeList.tsx, packages/web/src/components/InboxList.tsx + + 1. Create `packages/web/src/components/Skeleton.tsx` — a simple animated placeholder component. Props: `className?: string`. Renders a `
` with classes `animate-pulse rounded-md bg-muted`. The className prop is merged via `cn()` so callers can set width/height. Export as named export. + + 2. In `InitiativeList.tsx`: Replace the "Loading initiatives..." text block with 3 skeleton cards. Each skeleton card should match the InitiativeCard layout shape: a Card with a skeleton title bar (h-5 w-48), skeleton status badge (h-5 w-16), skeleton progress bar (h-2 w-full), and skeleton phase count (h-4 w-24). Wrap in a `
` to match the existing card list spacing. Use `Array.from({ length: 3 })` to render three. + + 3. In `InboxList.tsx`: Replace the "Loading inbox..." text block with 4 skeleton message rows. Each row: a skeleton circle (h-3 w-3 rounded-full), skeleton name (h-4 w-32), skeleton preview (h-3 w-full), skeleton time (h-3 w-16). Match the MessageCard layout. Use `Array.from({ length: 4 })`. + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + Dashboard and inbox show skeleton placeholders instead of text during loading. + + + + Task 2: Add skeleton loading states to initiative detail page + packages/web/src/routes/initiatives/$id.tsx + + 1. Replace the "Loading initiative..." text in InitiativeDetailPage with a skeleton layout that matches the page structure: + - Header skeleton: back arrow placeholder (h-4 w-4), title bar (h-7 w-64), status badge (h-5 w-20) + - Two-column grid matching `grid-cols-1 lg:grid-cols-[1fr_340px]`: + - Left: 2 skeleton phase accordions (each: h-12 w-full border rounded) + - Right: skeleton ProgressPanel (h-24 w-full), skeleton DecisionList (h-20 w-full) + + 2. Replace "Loading phases..." text (inside the phases section) with 3 skeleton phase accordion bars (h-10 w-full with animate-pulse, spaced with gap-1). + + Keep the existing error state as-is (it already has proper UI). + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + Detail page shows structured skeleton layout during all loading states. + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] `npm run --workspace=packages/web build` succeeds +- [ ] No "Loading..." plain text remains in InitiativeList, InboxList, or $id.tsx loading paths +- [ ] Skeleton component exported and used consistently + + + + +- All tasks completed +- All verification checks pass +- All three screens use skeleton loading states +- Skeleton component is reusable + + + +After completion, create `.planning/phases/21-polish-integration/21-02-SUMMARY.md` + diff --git a/.planning/phases/21-polish-integration/21-03-PLAN.md b/.planning/phases/21-polish-integration/21-03-PLAN.md new file mode 100644 index 0000000..74659e9 --- /dev/null +++ b/.planning/phases/21-polish-integration/21-03-PLAN.md @@ -0,0 +1,102 @@ +--- +phase: 21-polish-integration +plan: 03 +type: execute +wave: 1 +depends_on: [] +files_modified: [packages/web/src/layouts/AppLayout.tsx, packages/web/src/routes/inbox.tsx, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/components/InboxList.tsx, packages/web/src/components/InitiativeHeader.tsx, packages/web/src/components/TaskRow.tsx] +autonomous: true +--- + + +Add cross-screen navigation links and fix mobile responsive layout gaps. + +Purpose: Pages are currently isolated — the inbox doesn't link to initiatives, the detail page doesn't link to inbox, and there's no way for users to navigate between related resources. Additionally, the detail panel on inbox and initiative detail pages is completely hidden on mobile with no way to access it. +Output: Cross-screen navigation between related resources and responsive mobile access to detail panels. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@packages/web/src/layouts/AppLayout.tsx +@packages/web/src/routes/inbox.tsx +@packages/web/src/routes/initiatives/$id.tsx +@packages/web/src/components/InboxList.tsx +@packages/web/src/components/InitiativeHeader.tsx +@packages/web/src/components/TaskRow.tsx + + + + + + Task 1: Add cross-screen navigation links + packages/web/src/layouts/AppLayout.tsx, packages/web/src/components/TaskRow.tsx, packages/web/src/routes/inbox.tsx + + 1. In `AppLayout.tsx`: + - Remove the three disabled nav items (Agents, Tasks, Settings). They're stubs that will never be implemented in v2.0 — they create false promises and visual clutter. Keep only Initiatives and Inbox. + + 2. In `TaskRow.tsx`: + - If the task has a non-null agentName prop, make it a clickable link. Use `` from @tanstack/react-router. Style as `text-primary hover:underline` (clickable look). This lets users jump from a task's agent assignment to the inbox to see agent questions. + + 3. In `inbox.tsx`: + - In the detail panel header, where it shows `Task: {selectedAgent.taskId}`, make the taskId a link. If taskId is available, link to `/initiatives` (since we don't have a direct task→initiative mapping on the frontend, link to the dashboard — the user can find it from there). Use `` with `text-primary hover:underline` styling. + - Below the agent name header, add a small "View in context →" Link to `/initiatives` when the agent has a taskId. + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + Users can navigate between inbox and initiative detail via contextual links. Disabled nav stubs removed. + + + + Task 2: Fix mobile responsive layout for detail panels + packages/web/src/routes/inbox.tsx, packages/web/src/routes/initiatives/$id.tsx + + 1. In `inbox.tsx`: + - The empty detail panel placeholder has `hidden lg:flex` — correct (hide on mobile when nothing selected). + - When a detail panel IS showing (selectedAgent is truthy), it currently displays in the grid but the grid only becomes 2-column at `lg:`. On mobile, the list and detail stack vertically which is fine. + - Add a "← Back to list" button at the top of the detail panel that only shows on mobile (`lg:hidden`). When clicked, set selectedAgentId to null to return to the list view. + - On mobile when an agent IS selected, hide the InboxList with `hidden lg:block` on the list column, and show only the detail panel as full-width. This creates a drill-down pattern on mobile. + + 2. In `initiatives/$id.tsx`: + - The right column (ProgressPanel + DecisionList) currently stacks below phases on mobile, which is acceptable. + - The TaskDetailModal already uses Dialog which is responsive. + - No changes needed for detail page — its layout already works on mobile (single-column stacking). + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + Inbox detail panel accessible on mobile via drill-down pattern. Back button returns to list view. + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] `npm run --workspace=packages/web build` succeeds +- [ ] Disabled nav items removed from AppLayout +- [ ] TaskRow agent names are clickable links to inbox +- [ ] Inbox detail panel works on mobile with back button + + + + +- All tasks completed +- All verification checks pass +- Cross-screen navigation present between inbox and initiative detail +- Mobile users can access inbox detail panel + + + +After completion, create `.planning/phases/21-polish-integration/21-03-SUMMARY.md` + diff --git a/.planning/phases/21-polish-integration/21-04-PLAN.md b/.planning/phases/21-polish-integration/21-04-PLAN.md new file mode 100644 index 0000000..92c4194 --- /dev/null +++ b/.planning/phases/21-polish-integration/21-04-PLAN.md @@ -0,0 +1,101 @@ +--- +phase: 21-polish-integration +plan: 04 +type: execute +wave: 2 +depends_on: ["21-01", "21-02", "21-03"] +files_modified: [packages/web/src/routes/initiatives/index.tsx, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/routes/inbox.tsx, packages/web/src/components/SpawnArchitectDropdown.tsx] +autonomous: true +--- + + +Wire SSE subscription error handling with reconnection feedback, and add toast notifications for subscription state changes. + +Purpose: All three pages have `onError: () => {}` on their SSE subscriptions — errors are silently swallowed. When the backend is down, users get no feedback that live updates are paused. This plan adds graceful degradation so users know when real-time updates are working vs. falling back to manual refresh. +Output: Subscription error handling with user feedback on all three pages. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@packages/web/src/routes/initiatives/index.tsx +@packages/web/src/routes/initiatives/$id.tsx +@packages/web/src/routes/inbox.tsx +@packages/web/src/lib/trpc.ts + +# Depends on 21-01 for toast system +@.planning/phases/21-polish-integration/21-01-PLAN.md + + + + + + Task 1: Add subscription error handling with toast feedback on all pages + packages/web/src/routes/initiatives/index.tsx, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/routes/inbox.tsx + + 1. Create a shared pattern (inline — not a separate file) for subscription error handling. In each page's subscription `onError` callback: + - Call `toast.error('Live updates disconnected. Refresh to reconnect.', { id: 'sub-error', duration: Infinity })` — using a fixed toast ID prevents duplicates if multiple subscriptions fail simultaneously. `duration: Infinity` keeps it visible until dismissed. + - The toast is intentionally sticky so the user knows live updates are broken. + + 2. Apply to all subscription hooks: + - `initiatives/index.tsx`: `trpc.onTaskUpdate.useSubscription` — replace `onError: () => {}` with the error toast. + - `initiatives/$id.tsx`: Both `trpc.onTaskUpdate.useSubscription` and `trpc.onAgentUpdate.useSubscription` — replace both `onError: () => {}` with the error toast using the same toast ID (so only one shows). + - `inbox.tsx`: `trpc.onAgentUpdate.useSubscription` — replace `onError: () => {}` with the error toast. + + 3. Import `toast` from `sonner` in each file. + + Do NOT add complex reconnection logic. The tRPC SSE httpSubscriptionLink already handles reconnection automatically via EventSource retry. The toast just informs the user that something went wrong. When the connection re-establishes, `onData` will fire and queries will invalidate — the app self-heals. + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + - Grep confirms no remaining `onError: () => {}` in route files + + All subscription error callbacks show user-facing feedback instead of silently swallowing. Same toast ID prevents duplicate error notifications. + + + + Task 2: Add error toast to SpawnArchitectDropdown inline mutation + packages/web/src/components/SpawnArchitectDropdown.tsx + + NOTE: Plan 21-01 Task 2 already adds toasts to SpawnArchitectDropdown. This task is a verification step — confirm that 21-01 was applied correctly, and if the component still has any `console.error` calls without corresponding toast.error calls, fix them. + + If 21-01 was applied correctly, this is a no-op. Mark as done. + + If for any reason 21-01 didn't cover it, add `toast.error('Failed to spawn architect: ' + err.message)` in the mutation's onError and `toast.success('Architect spawned')` in onSuccess. + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - Grep for `console.error` in SpawnArchitectDropdown.tsx returns no results + + SpawnArchitectDropdown shows toast feedback for all outcomes. + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] `npm run --workspace=packages/web build` succeeds +- [ ] No `onError: () => {}` remaining in any route file +- [ ] No `console.error` without corresponding toast in component files + + + + +- All tasks completed +- All verification checks pass +- Subscription errors show sticky toast notification +- Users know when live updates are disconnected + + + +After completion, create `.planning/phases/21-polish-integration/21-04-SUMMARY.md` + diff --git a/.planning/phases/21-polish-integration/21-05-PLAN.md b/.planning/phases/21-polish-integration/21-05-PLAN.md new file mode 100644 index 0000000..2db0471 --- /dev/null +++ b/.planning/phases/21-polish-integration/21-05-PLAN.md @@ -0,0 +1,111 @@ +--- +phase: 21-polish-integration +plan: 05 +type: execute +wave: 2 +depends_on: ["21-01", "21-02", "21-03"] +files_modified: [packages/web/vite.config.ts, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/components/InitiativeCard.tsx] +autonomous: true +--- + + +Code-split route chunks and optimize data-fetching performance. + +Purpose: The production bundle is 544 KB (a single chunk) — everything loads upfront. Route-based code splitting reduces initial load. The InitiativeCard N+1 query pattern (fetching phases per card) is acceptable for v1 but should be acknowledged with a note for future batching. +Output: Lazy-loaded routes and reduced bundle size warning. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@packages/web/vite.config.ts +@packages/web/src/routes/__root.tsx +@packages/web/src/routes/initiatives/index.tsx +@packages/web/src/routes/initiatives/$id.tsx +@packages/web/src/routes/inbox.tsx +@packages/web/src/components/InitiativeCard.tsx + + + + + + Task 1: Add route-based code splitting via TanStack Router lazy routes + packages/web/src/routes/initiatives/index.tsx, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/routes/inbox.tsx + + TanStack Router file-based routing with the Vite plugin already supports automatic code splitting. The plugin generates lazy routes for files in the routes/ directory. + + Check if the TanStack Router Vite plugin is configured with `autoCodeSplitting: true` in `packages/web/vite.config.ts`. If not, add it to the TanStackRouterVite plugin options. + + If autoCodeSplitting is already enabled or the plugin handles it by default, verify by building and checking if the output has multiple chunks instead of one monolithic JS file. + + If the plugin does NOT support autoCodeSplitting in this version, manually split using TanStack Router's `.lazy.tsx` file convention: + - Create `packages/web/src/routes/initiatives/index.lazy.tsx` — move the DashboardPage component there, export via `createLazyFileRoute('/initiatives/')({ component: DashboardPage })` + - Create `packages/web/src/routes/initiatives/$id.lazy.tsx` — move InitiativeDetailPage and all helper components there + - Create `packages/web/src/routes/inbox.lazy.tsx` — move InboxPage there + - Keep the original files with just the route definition (params, loaders) and remove the component export + + The goal: separate chunks for dashboard, detail, and inbox routes. + + + - `npm run --workspace=packages/web build` succeeds + - Build output shows multiple JS chunks (not just one index-*.js file) + - No chunk exceeds 500 KB warning, or the warning is reduced + + Routes are code-split into separate chunks. Initial load only fetches the active route's code. + + + + Task 2: Optimize PlanTasksFetcher render loop in initiative detail + packages/web/src/routes/initiatives/$id.tsx + + The PlanTasksFetcher component currently calls `onTasks(planId, tasks)` on every render when `tasksQuery.isSuccess` is true (lines 195-199). This is called inside the render body, not in a useEffect, causing potential infinite re-render loops when the parent's state update triggers a re-render. + + Fix: + 1. Move the `onTasks` call into a `useEffect` with `[tasksQuery.data, planId, onTasks]` as dependencies. + 2. Inside the useEffect, only call `onTasks` when `tasksQuery.data` is defined. + 3. This prevents the setState-during-render issue and aligns with React best practices. + + The pattern should be: + ``` + useEffect(() => { + if (tasksQuery.data) { + onTasks(planId, tasksQuery.data as unknown as SerializedTask[]); + } + }, [tasksQuery.data, planId, onTasks]); + ``` + + + - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes + - `npm run --workspace=packages/web build` succeeds + + PlanTasksFetcher no longer triggers setState during render. Data flows through useEffect. + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] `npm run --workspace=packages/web build` succeeds +- [ ] Build output shows multiple chunks (code splitting working) +- [ ] PlanTasksFetcher uses useEffect for data callback + + + + +- All tasks completed +- All verification checks pass +- Bundle split into route-level chunks +- No setState-during-render warnings in PlanTasksFetcher + + + +After completion, create `.planning/phases/21-polish-integration/21-05-SUMMARY.md` + diff --git a/.planning/phases/21-polish-integration/21-06-PLAN.md b/.planning/phases/21-polish-integration/21-06-PLAN.md new file mode 100644 index 0000000..6fb88a5 --- /dev/null +++ b/.planning/phases/21-polish-integration/21-06-PLAN.md @@ -0,0 +1,104 @@ +--- +phase: 21-polish-integration +plan: 06 +type: execute +wave: 3 +depends_on: ["21-04", "21-05"] +files_modified: [] +autonomous: false +--- + + +Full integration smoke test — verify all screens, navigation flows, and error states work end-to-end. + +Purpose: This is the final verification before shipping v2.0. All prior plans in Phase 21 added error handling, loading states, navigation, and performance improvements. This plan verifies everything works together. +Output: Verified frontend ready to ship. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md +@~/.claude/get-shit-done/references/checkpoints.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + + + + + + Task 1: Run full build verification + + + 1. Run `npx tsc --noEmit` (backend) — must pass + 2. Run `npx tsc --noEmit -p packages/web/tsconfig.app.json` (frontend) — must pass + 3. Run `npm run --workspace=packages/web build` — must succeed + 4. Run `npm test` — all existing tests must still pass + 5. Check for any console warnings in the build output beyond expected ones + 6. Verify no `console.error` calls remain in component files (should all be replaced by toast): `grep -r "console.error" packages/web/src/` + + All commands return 0 exit code. No console.error in component source files. + Full build pipeline passes. No regressions. + + + + Complete frontend with error handling, loading skeletons, cross-screen navigation, toast notifications, and code splitting + + 1. Start backend: `npm run dev` (or `node dist/cli.js --server` if applicable) + 2. Start frontend: `npm run --workspace=packages/web dev` + 3. Visit: http://localhost:5173/initiatives + + **Dashboard screen:** + - Verify skeleton loading cards appear briefly before data loads + - Create a new initiative → toast appears "Initiative created" + - Verify only Initiatives and Inbox nav items in header (no disabled stubs) + - Click an initiative card → navigates to detail page + + **Detail screen:** + - Verify skeleton layout appears during loading + - Verify phases and tasks render correctly + - Verify "Back to Dashboard" navigation works + - If tasks have agents, verify agent name is a clickable link + + **Inbox screen:** + - Verify skeleton loading rows appear during loading + - If agents exist with questions, select one → detail panel shows + - On mobile viewport (resize to <1024px): verify detail panel becomes full-width with back button + - Navigate back → list view returns + + **Error handling:** + - Stop the backend server while frontend is running + - Verify "Live updates disconnected" toast appears (sticky) + - Verify pages still show cached data (no crash) + - Restart backend → verify pages resume working + + **404:** + - Visit http://localhost:5173/nonexistent + - Verify "Page not found" with "Back to Dashboard" button + + Type "approved" to continue, or describe issues to fix + + + + + +Before declaring plan complete: +- [ ] Full build passes (TypeScript, Vite build, tests) +- [ ] Human verified all screens work +- [ ] Error handling and loading states confirmed + + + + +- All tasks completed +- Human approved the integration test +- No regressions +- Frontend ready to ship as v2.0 + + + +After completion, create `.planning/phases/21-polish-integration/21-06-SUMMARY.md` +