Address 21 previously undefined behaviors across specs: - Authentication: Replace email/password with OIDC (Pocket-ID) - Cycle tracking: Add fixed-luteal phase scaling formula with examples - Calendar: Document period logging behavior (preserve predictions) - Garmin: Clarify connection is required (no phase-only mode) - Dashboard: Add UI states, dark mode, onboarding, accessibility - Notifications: Document timezone batching approach - New specs: observability.md (health, metrics, logging) - New specs: testing.md (unit + integration strategy) - Main spec: Add backup/recovery, known limitations, API updates Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
157 lines
5.0 KiB
Markdown
157 lines
5.0 KiB
Markdown
# Dashboard Specification
|
|
|
|
## Job to Be Done
|
|
|
|
When I open the app each morning, I want to immediately see whether I should train today, so that I can make informed decisions without manual data analysis.
|
|
|
|
## Components
|
|
|
|
### Decision Card (`decision-card.tsx`)
|
|
|
|
Displays the daily training decision prominently.
|
|
|
|
**Required Elements:**
|
|
- Large status indicator (REST / GENTLE / LIGHT / REDUCED / TRAIN)
|
|
- Color-coded background (red for REST, yellow for GENTLE/LIGHT/REDUCED, green for TRAIN)
|
|
- Reason text explaining why this decision was made
|
|
- Icon matching the decision status
|
|
|
|
**Data Source:**
|
|
- `/api/today` endpoint returns current decision
|
|
|
|
### Data Panel (`data-panel.tsx`)
|
|
|
|
Shows the biometric data used to make the decision.
|
|
|
|
**Required Elements:**
|
|
- HRV Status (Balanced/Unbalanced/Unknown)
|
|
- Body Battery Current (0-100)
|
|
- Body Battery Yesterday Low (0-100)
|
|
- Cycle Day (e.g., "Day 12")
|
|
- Current Phase (MENSTRUAL, FOLLICULAR, OVULATION, EARLY_LUTEAL, LATE_LUTEAL)
|
|
- Week Intensity Minutes (accumulated)
|
|
- Phase Limit (weekly cap based on phase)
|
|
- Remaining Minutes until limit
|
|
|
|
**Visual Indicators:**
|
|
- Color-code HRV status (green=Balanced, red=Unbalanced, gray=Unknown)
|
|
- Progress bar for week intensity vs phase limit
|
|
|
|
### Nutrition Panel (`nutrition-panel.tsx`)
|
|
|
|
Displays seed cycling and macro guidance.
|
|
|
|
**Required Elements:**
|
|
- Current seeds to consume (Flax+Pumpkin OR Sesame+Sunflower)
|
|
- Carb range for the day (e.g., "20-100g")
|
|
- Keto guidance (OPTIONAL / No / NEVER with reason)
|
|
- Seed switch alert on day 15
|
|
|
|
**Data Source:**
|
|
- `getNutritionGuidance(cycleDay)` from `src/lib/nutrition.ts`
|
|
|
|
### Override Toggles (`override-toggles.tsx`)
|
|
|
|
Emergency modifications to the standard decision.
|
|
|
|
**Override Types:**
|
|
- `flare` - Hashimoto's flare (force REST)
|
|
- `stress` - High stress day (force REST)
|
|
- `sleep` - Poor sleep (<6 hours) (force GENTLE)
|
|
- `pms` - PMS symptoms (force GENTLE)
|
|
|
|
**Behavior:**
|
|
- Toggle buttons for each override
|
|
- Active overrides persist until manually cleared
|
|
- Active overrides override the algorithmic decision
|
|
- Store in `user.activeOverrides[]`
|
|
|
|
### Mini Calendar (`mini-calendar.tsx`)
|
|
|
|
Visual cycle overview for the current month.
|
|
|
|
**Required Elements:**
|
|
- Monthly grid view
|
|
- Today highlighted
|
|
- Phase colors for each day
|
|
- Period days marked distinctly
|
|
- Quick navigation to previous/next month
|
|
|
|
## UI States
|
|
|
|
### Loading States
|
|
|
|
Use skeleton loaders during data fetching:
|
|
- Decision card: Shimmer placeholder for status and reason
|
|
- Data panel: Skeleton rows for each metric
|
|
- Mini calendar: Placeholder grid
|
|
|
|
### Error Handling
|
|
|
|
Toast notifications for errors with actionable feedback:
|
|
- Network errors: "Unable to fetch data. Retry?"
|
|
- Garmin sync failed: "Garmin data unavailable. Using last known values."
|
|
- Save errors: "Failed to save. Try again."
|
|
|
|
Toast position: Bottom-right, auto-dismiss after 5 seconds (errors persist until dismissed).
|
|
|
|
## Dark Mode
|
|
|
|
Auto-detect system preference via CSS `prefers-color-scheme`:
|
|
- No manual toggle
|
|
- Respect OS-level dark mode setting
|
|
- Ensure all phase colors maintain contrast in both modes
|
|
|
|
## Onboarding
|
|
|
|
First-time users see inline prompts/banners for missing setup:
|
|
|
|
| Missing State | Banner Message | Action |
|
|
|---------------|----------------|--------|
|
|
| Garmin not connected | "Connect your Garmin to get started" | Link to /settings/garmin |
|
|
| Last period not set | "Set your last period date for accurate tracking" | Opens date picker |
|
|
| Notification time not set | "Set your preferred notification time" | Link to /settings |
|
|
|
|
Banners appear at top of dashboard, dismissable once action completed.
|
|
|
|
## Responsive Design
|
|
|
|
Mobile-responsive layout:
|
|
- Single-column layout on mobile (<768px)
|
|
- All critical metrics visible without scrolling
|
|
- Touch-friendly toggle buttons (min 44x44px tap targets)
|
|
- Collapsible sections for secondary content
|
|
|
|
## Accessibility
|
|
|
|
Basic accessibility requirements:
|
|
- Semantic HTML (proper heading hierarchy, landmarks)
|
|
- Keyboard navigation for all interactive elements
|
|
- Focus indicators visible
|
|
- Color contrast minimum 4.5:1 for text
|
|
- Phase colors supplemented with icons/text (not color-only)
|
|
|
|
## Success Criteria
|
|
|
|
1. User can determine training status within 3 seconds of opening app
|
|
2. All biometric data visible without scrolling on mobile
|
|
3. Override toggles accessible but not accidentally activated
|
|
4. Phase colors consistent across all components
|
|
5. Dashboard usable with keyboard only
|
|
6. Loading states display within 100ms of navigation
|
|
|
|
## Acceptance Tests
|
|
|
|
- [ ] Dashboard loads decision from `/api/today`
|
|
- [ ] Decision card shows correct status and color
|
|
- [ ] Data panel displays all 8 required metrics
|
|
- [ ] Nutrition panel shows correct seeds for cycle day
|
|
- [ ] Override toggles update user record immediately
|
|
- [ ] Mini calendar renders current month with phase colors
|
|
- [ ] Skeleton loaders appear during data fetch
|
|
- [ ] Toast notifications display on error
|
|
- [ ] Dark mode activates based on system preference
|
|
- [ ] Onboarding banner shows when Garmin not connected
|
|
- [ ] Dashboard renders correctly on mobile viewport
|
|
- [ ] All interactive elements keyboard-accessible
|