From 840c2807494d0d955eae58c92bbb27f31fe603c6 Mon Sep 17 00:00:00 2001 From: Lukas May Date: Wed, 4 Feb 2026 20:53:57 +0100 Subject: [PATCH] docs(17): create initiative dashboard phase plan Phase 17: Initiative Dashboard - 4 plans in 3 waves - 2 parallel (Plans 02 + 03 in Wave 2), 2 sequential - Ready for execution --- .../17-initiative-dashboard/17-01-PLAN.md | 118 +++++++++++++++ .../17-initiative-dashboard/17-02-PLAN.md | 132 ++++++++++++++++ .../17-initiative-dashboard/17-03-PLAN.md | 143 ++++++++++++++++++ .../17-initiative-dashboard/17-04-PLAN.md | 129 ++++++++++++++++ 4 files changed, 522 insertions(+) create mode 100644 .planning/phases/17-initiative-dashboard/17-01-PLAN.md create mode 100644 .planning/phases/17-initiative-dashboard/17-02-PLAN.md create mode 100644 .planning/phases/17-initiative-dashboard/17-03-PLAN.md create mode 100644 .planning/phases/17-initiative-dashboard/17-04-PLAN.md diff --git a/.planning/phases/17-initiative-dashboard/17-01-PLAN.md b/.planning/phases/17-initiative-dashboard/17-01-PLAN.md new file mode 100644 index 0000000..81e9cd3 --- /dev/null +++ b/.planning/phases/17-initiative-dashboard/17-01-PLAN.md @@ -0,0 +1,118 @@ +--- +phase: 17-initiative-dashboard +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - packages/web/src/components/StatusBadge.tsx + - packages/web/src/components/ProgressBar.tsx +autonomous: true +--- + + +Create reusable StatusBadge and ProgressBar components for the initiative dashboard. + +Purpose: These are shared UI primitives used by InitiativeCard and potentially other views. Building them first unblocks parallel work on cards and dialogs. +Output: Two tested, styled components matching the wireframe specification. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@docs/wireframes/initiative-dashboard.md +@packages/web/src/components/ui/badge.tsx +@packages/web/src/lib/utils.ts +@packages/shared/src/types.ts + + + + + + Task 1: Create StatusBadge component + packages/web/src/components/StatusBadge.tsx + +Create a StatusBadge component that renders a colored badge for entity statuses. + +The component accepts a `status` string prop and renders it as a styled badge using the shadcn Badge component. + +**Status-to-style mapping (based on actual backend types):** + +Initiative statuses: +- `active` → blue background (use badge `default` variant with blue coloring via className) +- `completed` → green background +- `archived` → gray background + +Phase statuses: +- `pending` → gray background +- `in_progress` → blue background +- `completed` → green background +- `blocked` → red background + +Make this generic — accept any string status, apply Tailwind classes based on a lookup map. Unknown statuses get gray default. + +**Display text:** Uppercase, underscores replaced with spaces. E.g., `in_progress` → `IN PROGRESS`. + +Use the existing Badge component from `@/components/ui/badge` as the base. Apply custom background/text colors via className overrides (not new badge variants — keep shadcn components stock). + +Export as named export: `export function StatusBadge`. + + npx tsc --noEmit -p packages/web/tsconfig.app.json + StatusBadge component renders colored badges for all initiative and phase statuses with correct text formatting + + + + Task 2: Create ProgressBar component + packages/web/src/components/ProgressBar.tsx + +Create a ProgressBar component showing completion percentage. + +**Props:** +- `completed: number` — number of completed items +- `total: number` — total items + +**Display logic:** +- Calculate percentage: `(completed / total) * 100`, or 0 if total is 0 +- Render a horizontal bar with Tailwind: gray track (h-2 rounded-full bg-muted), filled portion (h-2 rounded-full transition-all) with width set via inline style `width: ${percentage}%` +- Show text label next to bar: `{percentage}%` + +**Color variants:** +- 0% (or total=0): Gray track only, no fill +- 1-99%: Blue fill (`bg-primary`) +- 100%: Green fill (`bg-green-500`) + +Keep it simple — a div-based progress bar, not a native `` element. Use `cn()` from `@/lib/utils` for conditional classes. + +Export as named export: `export function ProgressBar`. + + npx tsc --noEmit -p packages/web/tsconfig.app.json + ProgressBar component renders percentage-based bar with correct colors for 0%, partial, and 100% states + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] Both components export named functions +- [ ] No new dependencies needed (uses existing shadcn Badge + Tailwind) + + + + +- StatusBadge renders colored badges for all backend status types +- ProgressBar renders visual progress with percentage label +- Both components use existing shadcn/Tailwind primitives +- TypeScript compiles without errors + + + +After completion, create `.planning/phases/17-initiative-dashboard/17-01-SUMMARY.md` + diff --git a/.planning/phases/17-initiative-dashboard/17-02-PLAN.md b/.planning/phases/17-initiative-dashboard/17-02-PLAN.md new file mode 100644 index 0000000..57e595d --- /dev/null +++ b/.planning/phases/17-initiative-dashboard/17-02-PLAN.md @@ -0,0 +1,132 @@ +--- +phase: 17-initiative-dashboard +plan: 02 +type: execute +wave: 2 +depends_on: ["17-01"] +files_modified: + - packages/web/src/components/InitiativeCard.tsx + - packages/web/src/components/InitiativeList.tsx +autonomous: true +--- + + +Build the InitiativeCard and InitiativeList components that display initiatives with status, progress, and phase counts. + +Purpose: Core display components for the dashboard — the card shows a single initiative, the list renders all initiatives with filtering and empty state. +Output: Card and list components ready for page integration. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@docs/wireframes/initiative-dashboard.md +@packages/web/src/components/ui/card.tsx +@packages/web/src/components/ui/button.tsx +@packages/web/src/components/ui/dropdown-menu.tsx +@packages/web/src/lib/trpc.ts +@packages/shared/src/types.ts +@packages/web/src/components/StatusBadge.tsx +@packages/web/src/components/ProgressBar.tsx + + + + + + Task 1: Create InitiativeCard component + packages/web/src/components/InitiativeCard.tsx + +Create an InitiativeCard component rendering a single initiative row. + +**Props:** +- `initiative: Initiative` (from shared types — id, name, description, status, createdAt, updatedAt) +- `phaseStats: { completed: number; total: number }` — phase completion counts +- `onView: () => void` — navigate to detail +- `onSpawnArchitect: (mode: 'discuss' | 'breakdown') => void` — spawn architect +- `onDelete: () => void` — delete initiative + +**Layout (matching wireframe):** +Use the Card component from shadcn. Single row layout: +- Left: Initiative name (bold, text-base) +- Middle: StatusBadge showing `initiative.status`, ProgressBar showing `phaseStats.completed / phaseStats.total`, text showing `{completed}/{total}` phases +- Right: Action buttons — "View" button (outline variant), "Spawn Architect" dropdown, "..." more actions menu + +**Responsive:** On screens <768px, stack elements vertically (use flex-col). Hide phase count text on small screens. + +**Click behavior:** The entire card is clickable (calls `onView`). Action buttons use `e.stopPropagation()` to prevent card click. + +Use TanStack Router `Link` for the card click (wrap card in Link to `/initiatives/${initiative.id}`), not an onClick handler — this gives proper anchor semantics and hover states. + +Actually, use the card as a clickable div with `onClick={onView}` and `cursor-pointer` class — the View button and Link are redundant. Keep the View button for explicit action. + +Import StatusBadge from `@/components/StatusBadge` and ProgressBar from `@/components/ProgressBar`. + + npx tsc --noEmit -p packages/web/tsconfig.app.json + InitiativeCard renders initiative name, status badge, progress bar, phase count, and action buttons + + + + Task 2: Create InitiativeList component + packages/web/src/components/InitiativeList.tsx + +Create an InitiativeList component that fetches and displays all initiatives. + +**Data fetching:** +- Use `trpc.listInitiatives.useQuery()` to fetch initiatives +- For each initiative, use `trpc.listPhases.useQuery({ initiativeId: initiative.id })` to get phase counts + - Count phases where `status === 'completed'` for completed count + - Total is `phases.length` + - Note: This creates N+1 queries. Acceptable for v1 dashboard with small initiative counts. Wrap each query in the card component or use a helper. + +Actually, to avoid N+1 in the list, fetch phases per-initiative inside InitiativeCard. Pass the initiative to the card, let the card fetch its own phase stats. This keeps the list component clean and each card self-contained. + +**Filter:** +- Accept an optional `statusFilter` prop: `'all' | 'active' | 'completed' | 'archived'` +- Pass to `trpc.listInitiatives.useQuery({ status: filter === 'all' ? undefined : filter })` + +**States:** +- Loading: Show skeleton or "Loading initiatives..." text +- Empty (no initiatives): Show empty state from wireframe — "No initiatives yet" with centered message and "New Initiative" CTA button +- Error: Show error message with retry button +- Data: Map initiatives to InitiativeCard components + +**Empty state props:** +- `onCreateNew: () => void` — callback for the CTA button + +The list renders a vertical stack of InitiativeCards with `space-y-3` gap. + +Export: `export function InitiativeList`. + + npx tsc --noEmit -p packages/web/tsconfig.app.json + InitiativeList fetches initiatives via tRPC, displays cards with loading/empty/error states, supports status filtering + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] InitiativeCard uses StatusBadge and ProgressBar from Plan 01 +- [ ] InitiativeList handles loading, empty, error, and populated states +- [ ] No hardcoded data — all from tRPC queries + + + + +- InitiativeCard displays initiative data with all wireframe elements +- InitiativeList fetches and renders initiatives with proper states +- Filter support via status prop +- Empty state matches wireframe design +- TypeScript compiles without errors + + + +After completion, create `.planning/phases/17-initiative-dashboard/17-02-SUMMARY.md` + diff --git a/.planning/phases/17-initiative-dashboard/17-03-PLAN.md b/.planning/phases/17-initiative-dashboard/17-03-PLAN.md new file mode 100644 index 0000000..80d6cf0 --- /dev/null +++ b/.planning/phases/17-initiative-dashboard/17-03-PLAN.md @@ -0,0 +1,143 @@ +--- +phase: 17-initiative-dashboard +plan: 03 +type: execute +wave: 2 +depends_on: ["17-01"] +files_modified: + - packages/web/src/components/CreateInitiativeDialog.tsx + - packages/web/src/components/SpawnArchitectDropdown.tsx + - packages/web/src/components/ActionMenu.tsx +autonomous: true +--- + + +Build the interactive dialog and dropdown components: CreateInitiativeDialog, SpawnArchitectDropdown, and ActionMenu. + +Purpose: These handle user actions — creating initiatives, spawning architect agents, and managing initiatives (edit/delete). They're independent of the card/list components and can be built in parallel. +Output: Three interactive components ready for page integration. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@docs/wireframes/initiative-dashboard.md +@packages/web/src/components/ui/button.tsx +@packages/web/src/components/ui/dropdown-menu.tsx +@packages/web/src/lib/trpc.ts +@packages/shared/src/types.ts +@src/trpc/router.ts + + + + + + Task 1: Create CreateInitiativeDialog component + packages/web/src/components/CreateInitiativeDialog.tsx + +Create a dialog component for creating new initiatives. + +**First, add shadcn/ui components needed:** +Run `npx shadcn@latest add dialog input label` from `packages/web/` to install the Dialog, Input, and Label components. + +If the shadcn CLI creates files in a literal `@/` directory (known issue from 16-04), move them to `packages/web/src/components/ui/` manually. + +**Component structure:** +- Controlled dialog with `open` and `onOpenChange` props +- Form fields: Name (required text input), Description (optional textarea) +- Buttons: Cancel (closes dialog), Create (submits form) + +**Mutation:** +- Use `trpc.createInitiative.useMutation()` to create the initiative +- On success: close dialog, invalidate `listInitiatives` query via `utils.listInitiatives.invalidate()` +- On error: show error text below form +- While submitting: disable Create button, show "Creating..." text + +**Form handling:** +- Use React `useState` for form fields (name, description) +- Validate name is non-empty before enabling Create button +- Reset form fields when dialog opens (use `useEffect` on `open` prop) + +No external form libraries — useState is sufficient for 2 fields. + +Export: `export function CreateInitiativeDialog`. + + npx tsc --noEmit -p packages/web/tsconfig.app.json + CreateInitiativeDialog opens modal, accepts name/description, creates initiative via tRPC, handles loading/error states + + + + Task 2: Create SpawnArchitectDropdown and ActionMenu components + packages/web/src/components/SpawnArchitectDropdown.tsx, packages/web/src/components/ActionMenu.tsx + +**SpawnArchitectDropdown:** + +Create a dropdown for spawning architect agents in different modes. + +Props: +- `initiativeId: string` +- `initiativeName: string` — used to generate agent name + +Uses the existing DropdownMenu from shadcn/ui. Two menu items: +- "Discuss" — calls `trpc.spawnArchitectDiscuss.useMutation()` with `{ name: initiativeName + '-discuss', initiativeId }` +- "Breakdown" — calls `trpc.spawnArchitectBreakdown.useMutation()` with `{ name: initiativeName + '-breakdown', initiativeId }` + +On success: close dropdown. Optionally show a brief success state (text change on button). +On error: keep dropdown open, show error. Use a simple approach — just console.error for now, toast notifications come in Phase 21. + +The trigger button text: "Spawn Architect" with a chevron-down icon from lucide-react. + +**ActionMenu:** + +Create a "more actions" dropdown for initiative management. + +Props: +- `initiativeId: string` +- `onDelete: () => void` — callback after deletion + +Menu items per wireframe: +- "Edit" — disabled for now (placeholder, no edit form in Phase 17 scope) +- "Duplicate" — disabled for now (placeholder) +- "Archive" — calls `trpc.updateInitiative.useMutation()` with `{ id: initiativeId, status: 'archived' }`, then invalidates queries +- "Delete" — calls `trpc.updateInitiative.useMutation()` or a delete procedure if available. Since there's no `deleteInitiative` tRPC procedure visible, use archive as the destructive action. Add a browser `confirm()` dialog before archive/delete. + +Actually, check if `deleteInitiative` exists on the router. The InitiativeRepository interface has `delete(id)` but the tRPC router may not expose it. If not exposed, skip Delete and only implement Archive as the destructive action. Mark Delete as disabled/placeholder. + +The trigger button: an ellipsis icon (MoreHorizontal from lucide-react) with ghost variant. + +Export both as named exports. + + npx tsc --noEmit -p packages/web/tsconfig.app.json + SpawnArchitectDropdown triggers discuss/breakdown mutations, ActionMenu provides archive action with confirmation + + + + + +Before declaring plan complete: +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] Dialog, Input, Label shadcn components installed +- [ ] CreateInitiativeDialog creates initiatives via tRPC mutation +- [ ] SpawnArchitectDropdown calls correct architect spawn procedures +- [ ] ActionMenu shows archive action with confirmation + + + + +- CreateInitiativeDialog creates initiatives with name and description +- SpawnArchitectDropdown triggers discuss and breakdown modes +- ActionMenu provides archive (and disabled placeholders for edit/duplicate/delete) +- All mutations invalidate relevant queries on success +- TypeScript compiles without errors + + + +After completion, create `.planning/phases/17-initiative-dashboard/17-03-SUMMARY.md` + diff --git a/.planning/phases/17-initiative-dashboard/17-04-PLAN.md b/.planning/phases/17-initiative-dashboard/17-04-PLAN.md new file mode 100644 index 0000000..9894135 --- /dev/null +++ b/.planning/phases/17-initiative-dashboard/17-04-PLAN.md @@ -0,0 +1,129 @@ +--- +phase: 17-initiative-dashboard +plan: 04 +type: execute +wave: 3 +depends_on: ["17-02", "17-03"] +files_modified: + - packages/web/src/routes/initiatives/index.tsx + - packages/web/src/layouts/AppLayout.tsx +autonomous: true +--- + + +Assemble the full Initiative Dashboard page by wiring all components together and connecting the header's "New Initiative" button. + +Purpose: This is the integration plan — the dashboard page replaces the placeholder with a working initiative list, filter dropdown, and create dialog. The AppLayout header button gets connected. +Output: Fully functional Initiative Dashboard matching the wireframe. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +@docs/wireframes/initiative-dashboard.md +@packages/web/src/routes/initiatives/index.tsx +@packages/web/src/layouts/AppLayout.tsx +@packages/web/src/components/InitiativeList.tsx +@packages/web/src/components/InitiativeCard.tsx +@packages/web/src/components/CreateInitiativeDialog.tsx +@packages/web/src/components/SpawnArchitectDropdown.tsx +@packages/web/src/components/ActionMenu.tsx +@packages/web/src/components/StatusBadge.tsx +@packages/web/src/components/ProgressBar.tsx +@packages/web/src/lib/trpc.ts + + + + + + Task 1: Wire Initiative Dashboard page + packages/web/src/routes/initiatives/index.tsx + +Replace the placeholder DashboardPage with a fully functional initiative dashboard. + +**Page layout:** +1. Page header section: + - Title: "Initiatives" (h1, text-2xl font-bold) + - Filter dropdown: Select component (or simple button group) for status filter + - Options: All, Active, Completed, Archived (matching backend enum) + - Default: "All" + - Use a simple `` is fine for now. + +2. Initiative list: + - Render ` setCreateDialogOpen(true)} />` + +3. CreateInitiativeDialog: + - Controlled by `createDialogOpen` state + - Opened by both the page header "New Initiative" button AND the empty state CTA + +**State management:** +- `const [statusFilter, setStatusFilter] = useState<'all' | 'active' | 'completed' | 'archived'>('all')` +- `const [createDialogOpen, setCreateDialogOpen] = useState(false)` + +**Navigation integration:** +- InitiativeCard's `onView` should use TanStack Router's `useNavigate` to go to `/initiatives/${id}` +- Pass this down through InitiativeList to each card + +Wire up all callbacks: +- `onView` → navigate to detail +- `onSpawnArchitect` → handled within SpawnArchitectDropdown (self-contained) +- `onDelete` → handled within ActionMenu (self-contained), but invalidate list queries after + + npx tsc --noEmit -p packages/web/tsconfig.app.json + Dashboard page renders initiative list with filter, create dialog, and all card actions wired + + + + Task 2: Connect AppLayout header button and verify build + packages/web/src/layouts/AppLayout.tsx + +The AppLayout currently has a placeholder "New Initiative" button in the header. There are two approaches: + +**Option A (simpler):** Remove the header button. The "New Initiative" action lives on the dashboard page itself (the filter bar area and empty state CTA are sufficient). + +**Option B:** Keep the header button but it needs to communicate with the dashboard page to open the create dialog. This requires lifting state up or using a global event. + +Go with **Option A** — remove the "+ New Initiative" button from the AppLayout header. The dashboard page owns the create action via its own button in the page header area. This keeps the layout generic (other pages like Inbox shouldn't show "New Initiative"). + +Replace the header button with nothing (or a small spacer). The layout header becomes: logo left, empty right. + +After this change, verify the full frontend build: +- Run `npm run build -w packages/web` to confirm Vite production build succeeds +- Run `npx tsc --noEmit -p packages/web/tsconfig.app.json` to confirm types are clean + + npm run build -w packages/web && npx tsc --noEmit -p packages/web/tsconfig.app.json + AppLayout header simplified, full frontend build and type check pass with all Phase 17 components integrated + + + + + +Before declaring plan complete: +- [ ] `npm run build -w packages/web` succeeds (Vite production build) +- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes +- [ ] Dashboard page shows initiative list from tRPC API +- [ ] Filter dropdown changes displayed initiatives +- [ ] Create dialog opens, creates initiative, list refreshes +- [ ] Card actions (view, spawn architect, archive) all wired +- [ ] Empty state renders when no initiatives exist + + + + +- Initiative Dashboard is fully functional, replacing placeholder +- All wireframe elements present: title, filter, initiative cards, empty state +- tRPC queries and mutations wired correctly +- Build passes without errors +- AppLayout header is clean (no orphaned placeholder buttons) + + + +After completion, create `.planning/phases/17-initiative-dashboard/17-04-SUMMARY.md` +