358 lines
11 KiB
Markdown
358 lines
11 KiB
Markdown
---
|
|
phase: 01-foundation-dashboard
|
|
plan: 04
|
|
type: execute
|
|
wave: 3
|
|
depends_on:
|
|
- 01-01
|
|
- 01-02
|
|
- 01-03
|
|
files_modified:
|
|
- src/app/components/Sidebar.tsx
|
|
- src/app/components/LoginIndicator.tsx
|
|
- src/app/components/Navigation.tsx
|
|
- src/app/routes.ts
|
|
- vite.config.ts
|
|
- .bundlesize.json
|
|
- src/app/components/__tests__/Sidebar.test.tsx
|
|
- src/app/components/__tests__/LoginIndicator.test.tsx
|
|
autonomous: true
|
|
requirements:
|
|
- DASH-07
|
|
- UI-02
|
|
- UI-03
|
|
- UI-04
|
|
- UI-05
|
|
must_haves:
|
|
truths:
|
|
- Sidebar navigation has Settings, Calibration, Flash Memory links
|
|
- Login indicator shows logged-in state
|
|
- Bundle size is under 170KB (target) / 200KB (limit)
|
|
- All routes defined and working
|
|
- Touch-friendly navigation (44px+ targets)
|
|
artifacts:
|
|
- path: src/app/components/Sidebar.tsx
|
|
provides: Navigation sidebar
|
|
exports: Sidebar
|
|
min_lines: 50
|
|
- path: src/app/components/LoginIndicator.tsx
|
|
provides: Login status indicator
|
|
exports: LoginIndicator
|
|
- path: src/app/routes.ts
|
|
provides: Route definitions
|
|
exports: router
|
|
- path: .bundlesize.json
|
|
provides: Bundle size budget config
|
|
key_links:
|
|
- from: Sidebar
|
|
to: routes.ts
|
|
via: Link components
|
|
- from: LoginIndicator
|
|
to: Header
|
|
via: Header composition
|
|
- from: routes.ts
|
|
to: RainfallView
|
|
via: Route configuration
|
|
---
|
|
|
|
<objective>
|
|
Complete the dashboard with navigation, login indicator, route configuration, and verify performance budget (<170KB bundle size).
|
|
|
|
Purpose: Navigation provides access to other sections (Settings, Calibration, Flash Memory). Login indicator shows authentication status. Performance verification ensures Pi Zero 2 W compatibility.
|
|
|
|
Output: Working navigation, login indicator, routes configured, bundle size verified under budget.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@./.opencode/get-shit-done/workflows/execute-plan.md
|
|
@./.opencode/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/phases/01-foundation-dashboard/01-CONTEXT.md
|
|
@.planning/phases/01-foundation-dashboard/01-RESEARCH.md
|
|
@sample_interface/src/app/components/Sidebar.tsx
|
|
@sample_interface/src/app/routes.ts
|
|
|
|
## Key Implementation Details
|
|
|
|
**Navigation Items:**
|
|
- Dashboard (home)
|
|
- Settings (with sub-items)
|
|
- Calibration
|
|
- Flash Memory
|
|
|
|
**Sidebar Design:**
|
|
- Fixed width (64px icons-only or 240px expanded)
|
|
- Touch-friendly items (44px+ height)
|
|
- Active state highlighting
|
|
- Collapsible on mobile
|
|
|
|
**Login Indicator:**
|
|
- Green dot/icon when logged in
|
|
- Gray/red when logged out
|
|
- Text label: "Logged In" / "Logged Out"
|
|
- Small and compact for header
|
|
|
|
**Routes:**
|
|
- `/` → Dashboard (RainfallView)
|
|
- `/utility/*` → Settings (placeholder for Phase 2)
|
|
- `/calibration` → Calibration (placeholder)
|
|
- `/flash-memory` → Flash Memory (placeholder)
|
|
|
|
**Bundle Size Budget:**
|
|
- Target: <170KB gzipped initial JS
|
|
- Limit: <200KB gzipped
|
|
- Tools: bundlesize, rollup-plugin-analyzer
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>task 1: Create LoginIndicator component</name>
|
|
<files>src/app/components/LoginIndicator.tsx, src/app/components/__tests__/LoginIndicator.test.tsx</files>
|
|
<behavior>
|
|
- Shows green status when isLoggedIn=true
|
|
- Shows gray/red status when isLoggedIn=false
|
|
- Compact size for header placement
|
|
- Accessible (aria-label)
|
|
</behavior>
|
|
<action>
|
|
1. Create src/app/components/LoginIndicator.tsx:
|
|
- Props: isLoggedIn (boolean), className (optional)
|
|
- Use shadcn/ui Badge or custom indicator
|
|
- Logged in: Green dot + "Logged In" text
|
|
- Logged out: Gray dot + "Login" text
|
|
- Compact: h-6, text-xs
|
|
- Use Lucide User icon
|
|
- Add aria-label for accessibility
|
|
|
|
2. Create tests:
|
|
- Shows correct state for logged in/out
|
|
- Has accessible label
|
|
- Accepts custom className
|
|
</action>
|
|
<verify>
|
|
<automated>npm test -- --run LoginIndicator 2>&1 | grep -E "(PASS|FAIL|✓|✗)"</automated>
|
|
</verify>
|
|
<done>LoginIndicator with accessible states created</done>
|
|
</task>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>task 2: Update Sidebar navigation</name>
|
|
<files>src/app/components/Sidebar.tsx, src/app/components/__tests__/Sidebar.test.tsx</files>
|
|
<behavior>
|
|
- Shows Dashboard, Settings, Calibration, Flash Memory links
|
|
- Touch-friendly items (44px+ height)
|
|
- Active state for current route
|
|
- Collapsible sections
|
|
</behavior>
|
|
<action>
|
|
1. Update src/app/components/Sidebar.tsx:
|
|
- Import NavLink from react-router
|
|
- Define navigation items array:
|
|
* Dashboard (Home icon) → /
|
|
* Settings (Settings icon) → /utility
|
|
* Calibration (Gauge icon) → /calibration
|
|
* Flash Memory (HardDrive icon) → /flash-memory
|
|
- Map items to NavLink components
|
|
- Item height: min-h-[44px]
|
|
- Active state: bg-accent class
|
|
- Icon + label layout
|
|
- Collapsible on mobile with hamburger
|
|
|
|
2. Create tests:
|
|
- Renders all navigation items
|
|
- Items have correct links
|
|
- Touch target size adequate
|
|
- Active state applied correctly
|
|
</action>
|
|
<verify>
|
|
<automated>npm test -- --run Sidebar 2>&1 | grep -E "(PASS|FAIL|✓|✗)"</automated>
|
|
</verify>
|
|
<done>Sidebar with 4 navigation items created</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>task 3: Configure routes for all views</name>
|
|
<files>src/app/routes.ts, src/app/components/views/SettingsView.tsx, src/app/components/views/CalibrationView.tsx, src/app/components/views/FlashMemoryView.tsx</files>
|
|
<behavior>
|
|
- All routes defined in routes.ts
|
|
- Settings, Calibration, Flash Memory have placeholder views
|
|
- Routes use lazy loading where appropriate
|
|
- Navigation between routes works
|
|
</behavior>
|
|
<action>
|
|
1. Create placeholder views:
|
|
- src/app/components/views/SettingsView.tsx: "Settings - Phase 2" placeholder
|
|
- src/app/components/views/CalibrationView.tsx: "Calibration - Phase 3" placeholder
|
|
- src/app/components/views/FlashMemoryView.tsx: "Flash Memory - Phase 3" placeholder
|
|
|
|
2. Update src/app/routes.ts:
|
|
- Import all views
|
|
- Define routes array:
|
|
* path: "/", element: RainfallView
|
|
* path: "/utility/*", element: SettingsView
|
|
* path: "/calibration", element: CalibrationView
|
|
* path: "/flash-memory", element: FlashMemoryView
|
|
- Use createBrowserRouter
|
|
- Add error boundary for 404s
|
|
</action>
|
|
<verify>
|
|
<automated>grep -n "SettingsView\|CalibrationView\|FlashMemoryView" src/app/routes.ts 2>/dev/null | head -10</automated>
|
|
</verify>
|
|
<done>Routes configured for all 4 main sections</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>task 4: Integrate LoginIndicator into Header</name>
|
|
<files>src/app/components/Header.tsx</files>
|
|
<behavior>
|
|
- Header displays LoginIndicator
|
|
- Gets login state from sensor store
|
|
- Compact placement in header row
|
|
</behavior>
|
|
<action>
|
|
1. Update src/app/components/Header.tsx:
|
|
- Import LoginIndicator
|
|
- Get isLoggedIn from sensor store (or mock for now)
|
|
- Place LoginIndicator in header layout
|
|
- Ensure proper spacing and alignment
|
|
|
|
2. Test integration:
|
|
- Login indicator visible in header
|
|
- Updates when login state changes
|
|
</action>
|
|
<verify>
|
|
<automated>grep -n "LoginIndicator" src/app/components/Header.tsx 2>/dev/null | head -5</automated>
|
|
</verify>
|
|
<done>LoginIndicator integrated into Header</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>task 5: Configure bundle size checking</name>
|
|
<files>.bundlesize.json, vite.config.ts, package.json</files>
|
|
<behavior>
|
|
- Bundle size limit configured (170KB target, 200KB max)
|
|
- Build fails if bundle exceeds limit
|
|
- Size checking integrated in CI
|
|
</behavior>
|
|
<action>
|
|
1. Create .bundlesize.json:
|
|
```json
|
|
{
|
|
"files": [
|
|
{
|
|
"path": "dist/assets/*.js",
|
|
"maxSize": "200kb",
|
|
"compression": "gzip"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
2. Update package.json scripts:
|
|
- "build:check": "npm run build && bundlesize"
|
|
- Add bundlesize as devDependency
|
|
|
|
3. Update vite.config.ts for optimization:
|
|
- Manual chunks for vendor code
|
|
- Drop console in production
|
|
- Minification settings
|
|
|
|
4. Install bundlesize: `pnpm add -D bundlesize`
|
|
</action>
|
|
<verify>
|
|
<automated>test -f .bundlesize.json && echo "Config exists" || echo "Config missing"</automated>
|
|
</verify>
|
|
<done>Bundle size checking configured</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>task 6: Build and verify bundle size</name>
|
|
<files>dist/</files>
|
|
<behavior>
|
|
- Production build succeeds
|
|
- Bundle size under 200KB limit
|
|
- Ideally under 170KB target
|
|
- No build errors or warnings
|
|
</behavior>
|
|
<action>
|
|
1. Run production build:
|
|
- `npm run build`
|
|
- Check for errors
|
|
|
|
2. Analyze bundle size:
|
|
- `npm run build:check` or check dist/ folder
|
|
- Look at main JS file size
|
|
- Use rollup-plugin-visualizer if needed
|
|
|
|
3. If over budget, investigate:
|
|
- Run `npx vite-bundle-visualizer`
|
|
- Identify large dependencies
|
|
- Consider code splitting
|
|
|
|
4. Document actual size in SUMMARY
|
|
</action>
|
|
<verify>
|
|
<automated>ls -lh dist/assets/*.js 2>/dev/null | awk '{print $5, $9}' | head -5</automated>
|
|
</verify>
|
|
<done>Bundle built and size verified (target: <170KB, limit: <200KB)</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>task 7: Final integration test</name>
|
|
<files>src/app/App.tsx</files>
|
|
<behavior>
|
|
- Full app renders without errors
|
|
- Navigation works between routes
|
|
- Dashboard shows all data
|
|
- No console errors
|
|
</behavior>
|
|
<action>
|
|
1. Verify App.tsx integration:
|
|
- RouterProvider with routes
|
|
- DashboardLayout with Header and Sidebar
|
|
- Outlet for route content
|
|
|
|
2. Run all tests:
|
|
- `npm test` — should pass
|
|
|
|
3. Verify no TypeScript errors:
|
|
- `npx tsc --noEmit`
|
|
|
|
4. Check for console errors:
|
|
- Review any warnings in test output
|
|
</action>
|
|
<verify>
|
|
<automated>npm test 2>&1 | tail -5</automated>
|
|
</verify>
|
|
<done>Full integration verified, all tests passing</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
After completing all tasks:
|
|
1. Run `npm test` — all tests should pass
|
|
2. Run `npm run build` — should succeed
|
|
3. Verify bundle size: Check dist/ folder, should be <200KB
|
|
4. Check routes: `grep -r "path:" src/app/routes.ts | wc -l` should be 4+
|
|
5. Verify navigation: `grep -r "NavLink\|Link" src/app/components/Sidebar.tsx`
|
|
6. Check LoginIndicator in Header: `grep "LoginIndicator" src/app/components/Header.tsx`
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- LoginIndicator component shows logged-in state
|
|
- Sidebar has navigation to Settings, Calibration, Flash Memory
|
|
- All routes configured and working
|
|
- Bundle size under 200KB (target <170KB)
|
|
- No TypeScript errors
|
|
- All tests passing
|
|
- Full app integrates without errors
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/01-foundation-dashboard/01-04-SUMMARY.md`
|
|
</output>
|