docs(01-foundation-dashboard): create phase 1 plans
This commit is contained in:
286
.planning/phases/01-foundation-dashboard/01-01-PLAN.md
Normal file
286
.planning/phases/01-foundation-dashboard/01-01-PLAN.md
Normal file
@@ -0,0 +1,286 @@
|
||||
---
|
||||
phase: 01-foundation-dashboard
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/app/stores/sensorStore.ts
|
||||
- src/app/api/client.ts
|
||||
- src/app/App.tsx
|
||||
- vitest.config.ts
|
||||
- src/test/setup.ts
|
||||
- package.json
|
||||
autonomous: true
|
||||
requirements:
|
||||
- DASH-01
|
||||
- DASH-02
|
||||
- DASH-03
|
||||
- DASH-04
|
||||
- DASH-05
|
||||
- DASH-06
|
||||
- DASH-07
|
||||
- UI-04
|
||||
must_haves:
|
||||
truths:
|
||||
- Zustand store exists with sensor data types
|
||||
- API client with mock fallback works
|
||||
- Port-based mode detection works (8080=kiosk, 9090=remote)
|
||||
- Test infrastructure is ready
|
||||
artifacts:
|
||||
- path: src/app/stores/sensorStore.ts
|
||||
provides: Zustand store for sensor data
|
||||
exports: useSensorStore, SensorState
|
||||
- path: src/app/api/client.ts
|
||||
provides: API client with mock fallback
|
||||
exports: fetchSensorData, mockSensorData
|
||||
- path: src/app/App.tsx
|
||||
provides: Mode detection and app root
|
||||
min_lines: 30
|
||||
- path: vitest.config.ts
|
||||
provides: Test configuration
|
||||
key_links:
|
||||
- from: sensorStore
|
||||
to: client.ts
|
||||
via: fetchSensorData updates store
|
||||
- from: App.tsx
|
||||
to: sensorStore
|
||||
via: Initializes data polling
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the foundational infrastructure for the RTU dashboard: Zustand state management, API client with mock fallback, port-based mode detection, and test infrastructure (Wave 0).
|
||||
|
||||
Purpose: This infrastructure enables all subsequent dashboard features. Without these foundations, individual components cannot share data or communicate with the backend.
|
||||
|
||||
Output: Working store, API client, mode detection, and test setup that subsequent plans build upon.
|
||||
</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
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/REQUIREMENTS.md
|
||||
@sample_interface/src/app/App.tsx
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
**Mode Detection:**
|
||||
- Port 8080 → kiosk mode (fixed 1024x600)
|
||||
- Port 9090 → remote mode (responsive Full HD)
|
||||
- Use `window.location.port` for detection
|
||||
|
||||
**Sensor Data Structure:**
|
||||
```typescript
|
||||
interface SensorData {
|
||||
rainfall: {
|
||||
today: number;
|
||||
hourly: number;
|
||||
monthlyAcc: number;
|
||||
yearlyAcc: number;
|
||||
};
|
||||
voltage: {
|
||||
solar: number;
|
||||
battery: number;
|
||||
batteryStatus: 'HIGH' | 'LOW';
|
||||
};
|
||||
station: {
|
||||
id: string;
|
||||
version: string;
|
||||
};
|
||||
communication: {
|
||||
asu: number;
|
||||
dBm: number;
|
||||
percentage: number;
|
||||
};
|
||||
timestamp: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Polling Strategy:**
|
||||
- Default 5 second interval
|
||||
- Configurable via settings
|
||||
- Pause when document.hidden
|
||||
- Use AbortController for cleanup
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 1: Create Wave 0 test infrastructure</name>
|
||||
<files>vitest.config.ts, src/test/setup.ts, package.json</files>
|
||||
<behavior>
|
||||
- Test config extends Vite config
|
||||
- Setup file provides test utilities
|
||||
- Test command works: `npm test`
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create vitest.config.ts extending vite.config.ts:
|
||||
- Use @vitejs/plugin-react
|
||||
- Configure test environment as jsdom
|
||||
- Set setupFiles to src/test/setup.ts
|
||||
|
||||
2. Create src/test/setup.ts:
|
||||
- Import @testing-library/jest-dom matchers
|
||||
- Configure cleanup after each test
|
||||
- Add mock for window.matchMedia if needed
|
||||
|
||||
3. Update package.json scripts:
|
||||
- "test": "vitest run"
|
||||
- "test:watch": "vitest"
|
||||
- Add devDependencies: vitest, @testing-library/react, @testing-library/jest-dom, jsdom
|
||||
|
||||
4. Run `pnpm install` to add dependencies
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm test -- --run 2>&1 | head -20</automated>
|
||||
</verify>
|
||||
<done>Test infrastructure ready, `npm test` runs successfully</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 2: Create Zustand sensor store</name>
|
||||
<files>src/app/stores/sensorStore.ts, src/app/stores/__tests__/sensorStore.test.ts</files>
|
||||
<behavior>
|
||||
- Store initializes with default/mock data
|
||||
- setSensorData updates all fields
|
||||
- Store can be subscribed to
|
||||
- Selectors work for derived data
|
||||
</behavior>
|
||||
<action>
|
||||
1. Install zustand: `pnpm add zustand`
|
||||
|
||||
2. Create src/app/stores/sensorStore.ts:
|
||||
- Define SensorData interface per context
|
||||
- Create store with initial state
|
||||
- Export useSensorStore hook
|
||||
- Add actions: setSensorData, updatePollingInterval
|
||||
- Include selector for last update timestamp
|
||||
|
||||
3. Create tests verifying:
|
||||
- Store initializes with defaults
|
||||
- setSensorData updates state
|
||||
- Subscribers receive updates
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm test -- --run stores/sensorStore 2>&1 | grep -E "(PASS|FAIL|✓|✗)"</automated>
|
||||
</verify>
|
||||
<done>Zustand store created with SensorData interface, tests pass</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 3: Create API client with mock fallback</name>
|
||||
<files>src/app/api/client.ts, src/app/api/__tests__/client.test.ts</files>
|
||||
<behavior>
|
||||
- fetchSensorData returns SensorData
|
||||
- On API failure, returns mock data
|
||||
- Uses AbortController for cancellation
|
||||
- Logs errors but doesn't throw
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create src/app/api/client.ts:
|
||||
- Define API endpoint URL (configurable)
|
||||
- Create fetchSensorData function with AbortSignal
|
||||
- Create mockSensorData generator with realistic values
|
||||
- Implement fallback: try API → catch → return mock
|
||||
- Add request timeout (5s)
|
||||
|
||||
2. Create tests verifying:
|
||||
- Returns data on successful fetch
|
||||
- Returns mock on network error
|
||||
- Respects AbortController
|
||||
- Mock data has valid structure
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm test -- --run api/client 2>&1 | grep -E "(PASS|FAIL|✓|✗)"</automated>
|
||||
</verify>
|
||||
<done>API client with mock fallback created, tests pass</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 4: Implement port-based mode detection</name>
|
||||
<files>src/app/App.tsx, src/app/hooks/useDisplayMode.ts</files>
|
||||
<behavior>
|
||||
- Port 8080 → returns 'kiosk'
|
||||
- Port 9090 → returns 'remote'
|
||||
- Other ports → defaults to 'kiosk'
|
||||
- Mode available via hook
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create src/app/hooks/useDisplayMode.ts:
|
||||
- Read window.location.port
|
||||
- Return 'kiosk' for 8080, 'remote' for 9090
|
||||
- Default to 'kiosk' for other ports
|
||||
- Memoize result (port won't change)
|
||||
|
||||
2. Update src/app/App.tsx:
|
||||
- Import useDisplayMode hook
|
||||
- Pass mode to DashboardLayout
|
||||
- Initialize data polling on mount
|
||||
- Clean up polling on unmount (useEffect cleanup)
|
||||
- Add data-attr or class based on mode for CSS targeting
|
||||
</action>
|
||||
<verify>
|
||||
<automated>grep -n "useDisplayMode\|window.location.port\|displayMode" src/app/App.tsx src/app/hooks/useDisplayMode.ts 2>/dev/null | head -20</automated>
|
||||
</verify>
|
||||
<done>Mode detection implemented, App.tsx uses display mode hook</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 5: Set up data polling with cleanup</name>
|
||||
<files>src/app/App.tsx, src/app/hooks/useSensorPolling.ts</files>
|
||||
<behavior>
|
||||
- Polls every 5 seconds by default
|
||||
- Pauses when document.hidden
|
||||
- Resumes when visible again
|
||||
- Properly cleans up on unmount
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create src/app/hooks/useSensorPolling.ts:
|
||||
- Accept polling interval (ms) parameter, default 5000
|
||||
- Use setInterval for polling
|
||||
- Listen for visibilitychange event
|
||||
- Pause interval when document.hidden
|
||||
- Resume when visible
|
||||
- Use AbortController per fetch
|
||||
- Return cleanup function
|
||||
|
||||
2. Update App.tsx:
|
||||
- Call useSensorPolling in component
|
||||
- Pass polling interval from settings (or default)
|
||||
- Ensure cleanup happens on unmount
|
||||
</action>
|
||||
<verify>
|
||||
<automated>grep -n "useSensorPolling\|setInterval\|visibilitychange\|AbortController" src/app/App.tsx src/app/hooks/useSensorPolling.ts 2>/dev/null | head -20</automated>
|
||||
</verify>
|
||||
<done>Polling implemented with visibility awareness and cleanup</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
After completing all tasks:
|
||||
1. Run `npm test` — all tests should pass
|
||||
2. Check store exists: `ls src/app/stores/sensorStore.ts`
|
||||
3. Check API client exists: `ls src/app/api/client.ts`
|
||||
4. Check mode detection: `grep "useDisplayMode" src/app/App.tsx`
|
||||
5. Verify no console errors on build: `npm run build 2>&1 | grep -i error || echo "Build clean"`
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Zustand store with SensorData interface exists and is tested
|
||||
- API client with mock fallback exists and is tested
|
||||
- Port-based mode detection works (8080=kiosk, 9090=remote)
|
||||
- Data polling with cleanup and visibility awareness implemented
|
||||
- Test infrastructure ready (`npm test` runs)
|
||||
- All files committed
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-foundation-dashboard/01-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user