Files
phaseflow/specs/dashboard.md
Petru Paler 6a8d55c0b9 Document spec gaps: auth, phase scaling, observability, testing
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>
2026-01-11 07:49:56 +00:00

5.0 KiB

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