docs: complete domain research
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# Architecture: Custom Workouts & Flexible Sets
|
||||
|
||||
**Project:** Gravl — PPL Workout Tracker
|
||||
**Researched:** 2026-02-15
|
||||
|
||||
## Current State
|
||||
|
||||
Fixed program structure:
|
||||
```
|
||||
Users → Programs (hardcoded id=1) → Program Days (6) → Program Exercises (fixed sets) → Workout Logs
|
||||
```
|
||||
|
||||
## Proposed: Dual Data Paths
|
||||
|
||||
Two parallel workout sources:
|
||||
1. **Program Workouts** (existing): Fixed PPL structure, unchanged
|
||||
2. **Custom Workouts** (new): User-built workouts with flexible sets
|
||||
|
||||
### Schema Additions
|
||||
|
||||
```sql
|
||||
-- User-created workout templates
|
||||
CREATE TABLE custom_workouts (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Exercises in custom workouts
|
||||
CREATE TABLE custom_workout_exercises (
|
||||
id SERIAL PRIMARY KEY,
|
||||
custom_workout_id INTEGER REFERENCES custom_workouts(id) ON DELETE CASCADE,
|
||||
exercise_id INTEGER REFERENCES exercises(id),
|
||||
sets INTEGER DEFAULT 3,
|
||||
sort_order INTEGER DEFAULT 0
|
||||
);
|
||||
```
|
||||
|
||||
Enhanced `workout_logs`:
|
||||
- Add `source_type` column ('program' | 'custom') — defaults to 'program' for backward compat
|
||||
- Add `custom_workout_exercise_id` column (nullable FK)
|
||||
|
||||
### Frontend Components
|
||||
|
||||
**New pages:**
|
||||
- `CustomWorkoutBuilder.jsx` — search exercises, build workout, save template
|
||||
- `ModifyWorkoutPage.jsx` — fork a program workout into custom
|
||||
|
||||
**New components:**
|
||||
- `ExerciseSearchInput.jsx` — searchable exercise list
|
||||
- `SetCountEditor.jsx` — +/- controls for set count
|
||||
- `StepperInput.jsx` — number input with +/- buttons and unit label
|
||||
|
||||
**Enhanced:**
|
||||
- `WorkoutSelectPage.jsx` — show both program and custom workouts
|
||||
- `WorkoutPage.jsx` — flexible set count, stepper inputs
|
||||
|
||||
### Backend Endpoints
|
||||
|
||||
New:
|
||||
- `POST /api/custom-workouts` — create custom workout
|
||||
- `GET /api/custom-workouts` — list user's custom workouts
|
||||
- `GET /api/custom-workouts/:id` — get custom workout with exercises
|
||||
- `PUT /api/custom-workouts/:id` — update custom workout
|
||||
- `DELETE /api/custom-workouts/:id` — delete custom workout
|
||||
- `GET /api/exercises` — list all exercises (for search/selection)
|
||||
|
||||
Enhanced:
|
||||
- `POST /api/logs` — accept both program_exercise_id and custom_workout_exercise_id
|
||||
|
||||
### Data Flow
|
||||
|
||||
1. **Program Workout** (unchanged): Dashboard → WorkoutSelectPage → WorkoutPage → logs
|
||||
2. **Custom Workout Build**: Dashboard → CustomWorkoutBuilder → search exercises → save → POST /api/custom-workouts
|
||||
3. **Modify Program Workout**: WorkoutPage → "Modify" → fork to custom workout → edit exercises/sets
|
||||
4. **Flexible Sets**: User clicks "+Set" → local state adds entry → logs all sets on save
|
||||
|
||||
## Build Order
|
||||
|
||||
1. **Input UX fixes** — stepper inputs, validation, units (no backend changes)
|
||||
2. **Flexible sets** — local state for set count, backend accepts variable sets
|
||||
3. **Exercise list endpoint** — GET /api/exercises for search
|
||||
4. **Custom workout CRUD** — new tables + endpoints
|
||||
5. **Custom workout builder UI** — frontend page + components
|
||||
6. **Modify program workout** — fork program workout to custom
|
||||
|
||||
Each phase builds on the previous. Phase 1 can ship independently.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Features: Workout Logging UX Improvements
|
||||
|
||||
**Project:** Gravl — PPL Workout Tracker
|
||||
**Researched:** 2026-02-15
|
||||
|
||||
## Table Stakes (Must-Have)
|
||||
|
||||
| Feature | Complexity | Dependencies | Notes |
|
||||
|---------|-----------|--------------|-------|
|
||||
| Input validation (no negative reps, weight min 0) | Low | None | Currently broken — allows any value |
|
||||
| Weight unit display (kg suffix) | Low | None | Missing — only placeholder text |
|
||||
| Mobile input layout (44px min touch targets) | Low | None | Currently compressed inputs |
|
||||
| Add/remove sets per exercise | Medium | Backend log changes | Fixed set count is rigid |
|
||||
| Pre-fill last workout's weight/reps | Medium | Progression API | Users need reference for what to lift |
|
||||
| Exercise search/filter | Medium | Exercise list API | Needed for custom workout builder |
|
||||
|
||||
## Differentiators (Competitive Advantage)
|
||||
|
||||
| Feature | Complexity | Dependencies | Notes |
|
||||
|---------|-----------|--------------|-------|
|
||||
| Custom workout builder | High | New DB tables, new endpoints | Build workouts from exercise list |
|
||||
| Modify program workouts | Medium | Custom workout infra | Swap/add exercises mid-workout |
|
||||
| Rapid-fire set logging | Medium | Stepper inputs | Auto-advance, minimal taps per set |
|
||||
| Progressive overload visualization | Medium | History data | Show trend vs last workout clearly |
|
||||
| Rest timer with notifications | Low | Browser APIs | setInterval + Notification API |
|
||||
| Superset/circuit support | High | Schema changes | Group exercises for alternating sets |
|
||||
|
||||
## Anti-Features (Deliberately Avoid)
|
||||
|
||||
| Feature | Why to Avoid |
|
||||
|---------|-------------|
|
||||
| Social features | Users hate mandatory social in workout apps |
|
||||
| Complex periodization | Overcomplicates a personal PPL tracker |
|
||||
| Video exercise demos | Storage/bandwidth cost, not core value |
|
||||
| Gamification (badges, streaks) | Distracts from simple logging |
|
||||
| AI workout generation | Scope creep — user knows their program |
|
||||
|
||||
## Priority for This Milestone
|
||||
|
||||
1. **Input fixes** — validation, units, layout (table stakes, low effort)
|
||||
2. **Flexible sets** — add/remove sets (table stakes, medium effort)
|
||||
3. **Custom workouts** — build from scratch + modify program (differentiator, high effort)
|
||||
@@ -0,0 +1,72 @@
|
||||
# Pitfalls: Workout App UX Improvements
|
||||
|
||||
**Project:** Gravl — PPL Workout Tracker
|
||||
**Researched:** 2026-02-15
|
||||
|
||||
## Critical Pitfalls (Address in This Milestone)
|
||||
|
||||
### 1. Breaking Existing Logging Flow
|
||||
- **Risk:** Custom exercises don't integrate with `program_exercise_id` FK; progression and history break
|
||||
- **Warning signs:** Existing workout logs return empty after schema changes; progression graph gaps
|
||||
- **Prevention:** Add `source_type` column with default 'program'; never modify existing FK relationships; custom workouts use separate `custom_workout_exercise_id`
|
||||
- **Phase:** Database schema changes (early)
|
||||
|
||||
### 2. Competing State on Shared Program
|
||||
- **Risk:** If users modify `program_exercises` directly, it affects ALL users sharing program_id=1
|
||||
- **Warning signs:** One user's set count change appears for another user
|
||||
- **Prevention:** Never modify program_exercises table for per-user changes. Custom modifications create a new custom_workout that forks from the program. Program data stays read-only
|
||||
- **Phase:** Custom workout architecture
|
||||
|
||||
### 3. Backward Compatibility with Existing Logs
|
||||
- **Risk:** Existing logs assume fixed sets; schema changes break progression graphs and workout history
|
||||
- **Warning signs:** Historical workout data disappears or shows incorrectly
|
||||
- **Prevention:** `source_type` defaults to 'program'; all existing queries continue unchanged; new queries handle both source types
|
||||
- **Phase:** Database migration
|
||||
|
||||
### 4. Input Validation Gaps
|
||||
- **Risk:** No validation on negative reps, extreme weights, or invalid set numbers
|
||||
- **Warning signs:** Corrupted data in database; nonsensical progression suggestions
|
||||
- **Prevention:** Frontend: `min=0` on inputs, stepper controls with bounds. Backend: validate before insert
|
||||
- **Phase:** Input UX fixes (Phase 1)
|
||||
|
||||
### 5. Mobile Layout Breakage
|
||||
- **Risk:** Extra buttons (add set, remove set, modify workout) break 600px layout; unusable on small phones
|
||||
- **Warning signs:** Horizontal scroll appears; buttons overlap; touch targets too small
|
||||
- **Prevention:** Design all new controls within existing 600px constraint first; test on 320px width; maintain 44px minimum touch targets
|
||||
- **Phase:** All UI changes
|
||||
|
||||
### 6. Scope Creep from "Add Set" to Full Program Builder
|
||||
- **Risk:** "Flexible sets" requirement grows into full periodization, program editor, template system
|
||||
- **Warning signs:** Conversations about "what if users want to plan a whole week" or "program templates"
|
||||
- **Prevention:** Strict scope: add/remove sets during a workout session. Custom workouts are simple exercise lists, not programs. No scheduling, no periodization
|
||||
- **Phase:** Scope discipline throughout
|
||||
|
||||
### 7. Unclear Completion State
|
||||
- **Risk:** Flexible sets make "workout complete" ambiguous — did they skip a set or just not add one?
|
||||
- **Warning signs:** Users feel guilty about "incomplete" workouts; confusion about what counts as done
|
||||
- **Prevention:** No "complete workout" enforcement. Each logged set is saved independently. Summary shows what was actually done, not what was "expected"
|
||||
- **Phase:** Workout flow UI
|
||||
|
||||
## Gravl-Specific Risks
|
||||
|
||||
### Hardcoded program_id=1
|
||||
Dashboard directly fetches `programs/1`. Custom workouts that aren't program-linked will need their own navigation path in WorkoutSelectPage.
|
||||
|
||||
### Upsert-Only Logging
|
||||
Current `/api/logs` only updates/inserts. If user removes a set, there's no delete mechanism. Need DELETE endpoint for individual log entries.
|
||||
|
||||
### Component-Level State Loss
|
||||
Logs stored in React useState, not localStorage. If app closes mid-workout, all unlogged progress is lost. Consider auto-saving to localStorage as draft.
|
||||
|
||||
### Single-File Backend
|
||||
Adding new endpoints to `backend/src/index.js` (already 425 lines) increases risk of accidentally breaking existing routes. Test existing endpoints after each backend change.
|
||||
|
||||
## Pre-Shipping Checklist
|
||||
|
||||
- [ ] Existing workout logging still works identically
|
||||
- [ ] Historical workout data displays correctly
|
||||
- [ ] Progression suggestions unchanged for program workouts
|
||||
- [ ] All inputs validate (no negative reps, no negative weight)
|
||||
- [ ] Layout works on 320px-600px width range
|
||||
- [ ] Custom workouts don't affect other users' program data
|
||||
- [ ] Set add/remove persists correctly in database
|
||||
@@ -0,0 +1,64 @@
|
||||
# Technology Stack: Workout Logging UX Improvements
|
||||
|
||||
**Project:** Gravl — PPL Workout Tracker (UX Milestone)
|
||||
**Researched:** 2026-02-15
|
||||
**Scope:** UX improvements to existing React 18 + Vite + Express + PostgreSQL app
|
||||
|
||||
## What the Codebase Already Has
|
||||
|
||||
| Layer | Technology | Version | Notes |
|
||||
|-------|------------|---------|-------|
|
||||
| Frontend framework | React | 18.2.0 | JSX, hooks-based |
|
||||
| Build tool | Vite | 5.0.8 | Already fast |
|
||||
| Routing | react-router-dom | 6.21.0 | Mostly unused — App.jsx uses manual `view` state |
|
||||
| Styling | Plain CSS + CSS custom properties | — | Dark fitness theme, `--accent`, `--bg-*` vars defined |
|
||||
| Backend | Express | — | REST API, `/api/*` endpoints |
|
||||
| Database | PostgreSQL | — | workout_logs, programs, exercises tables |
|
||||
| State | React useState | — | Local component state, no global store |
|
||||
| HTTP | Native fetch | — | Direct fetch() calls in App.jsx |
|
||||
|
||||
## Recommended Stack Additions
|
||||
|
||||
### Form Validation: React Hook Form + Zod
|
||||
|
||||
| Technology | Version | Purpose | Why |
|
||||
|------------|---------|---------|-----|
|
||||
| react-hook-form | 7.x | Input registration, validation | Zero re-renders on keystroke. Integrates with native `<input>` without wrapping. |
|
||||
| zod | 3.x | Schema for weight/reps | `z.number().min(0).max(500)` reads as documentation. |
|
||||
| @hookform/resolvers | 3.x | Bridge RHF <-> Zod | Required; maintained by RHF team. |
|
||||
|
||||
**Why not Formik:** Higher re-render cost. Context-based, creates overhead for per-set inline inputs.
|
||||
|
||||
### Number Input Stepper: Custom Component (No Library)
|
||||
|
||||
Build a custom `StepperInput` component with existing CSS variables. The requirement — +/- buttons flanking a number field with a unit label — is ~30 lines of React. Weight step: 2.5 kg. Reps step: 1.
|
||||
|
||||
### Set Count Management: React State Only
|
||||
|
||||
Add a `localSets` state initialized from `exercise.sets`. +/- controls add/remove entries. Copy last set's weight as default for added sets.
|
||||
|
||||
### Custom Workout Creation: Existing Stack
|
||||
|
||||
Use existing React + fetch + PostgreSQL. Add a `WorkoutBuilderPage.jsx`. No new global state needed initially.
|
||||
|
||||
### Touch Target Sizing: CSS Only
|
||||
|
||||
Critical rule: `font-size: 1rem` (minimum 16px) on all inputs prevents iOS Safari auto-zoom. Minimum 44px height on all interactive elements per iOS HIG.
|
||||
|
||||
## What NOT to Add
|
||||
|
||||
| Library | Why to Avoid |
|
||||
|---------|-------------|
|
||||
| Formik | Higher re-render cost; worse DX for inline per-row forms |
|
||||
| Material UI / Chakra UI | Conflicts with custom dark CSS; adds 200KB+ |
|
||||
| TanStack Query | Simple fetch pattern doesn't warrant it yet |
|
||||
| Framer Motion | Minimal animation intent; complex on budget phones |
|
||||
| Redux Toolkit | Overkill for 5-page single-user app |
|
||||
|
||||
## Installation Summary
|
||||
|
||||
```bash
|
||||
npm install react-hook-form zod @hookform/resolvers
|
||||
```
|
||||
|
||||
**Bundle impact:** ~38KB gzipped total addition.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Research Summary: Workout UX Improvements
|
||||
|
||||
**Project:** Gravl — PPL Workout Tracker
|
||||
**Synthesized:** 2026-02-15
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Stack
|
||||
- Keep existing React 18 + Vite + Express + PostgreSQL stack
|
||||
- Add only: `react-hook-form` + `zod` + `@hookform/resolvers` (~38KB gzipped)
|
||||
- Build custom stepper input component (no library needed)
|
||||
- Do NOT add: UI frameworks, Redux, TanStack Query, Framer Motion
|
||||
- CSS-only fix for touch targets: min 44px height, 16px font-size prevents iOS zoom
|
||||
|
||||
### Table Stakes (Must Ship)
|
||||
- Input validation: no negative reps/weights, proper number constraints
|
||||
- Weight unit display (kg suffix visible in input)
|
||||
- Mobile-optimized input layout (larger touch targets)
|
||||
- Add/remove sets per exercise
|
||||
- Pre-fill last workout's values for reference
|
||||
|
||||
### Differentiators (Should Ship)
|
||||
- Custom workout builder (pick exercises, save as template)
|
||||
- Modify program workouts (fork to custom)
|
||||
- Stepper inputs for rapid logging (+/- buttons)
|
||||
|
||||
### Watch Out For
|
||||
1. **Don't break existing flow** — program workout logging must stay identical
|
||||
2. **Don't modify shared program data** — fork to custom_workout for per-user changes
|
||||
3. **Don't let scope creep** — "add set" ≠ "full program builder"
|
||||
4. **Don't break mobile layout** — all new controls must fit 600px width
|
||||
5. **Backward compat** — existing workout_logs must keep working with new schema
|
||||
|
||||
## Architecture Decision
|
||||
|
||||
**Dual data path:**
|
||||
- Program workouts (existing, read-only) — unchanged
|
||||
- Custom workouts (new) — user-created, flexible sets, stored in new tables
|
||||
|
||||
**New tables:** `custom_workouts`, `custom_workout_exercises`
|
||||
**Enhanced:** `workout_logs` gets `source_type` column (default 'program')
|
||||
|
||||
## Suggested Build Order
|
||||
|
||||
1. Input UX fixes (validation, units, stepper, layout) — no backend changes
|
||||
2. Flexible sets (local state + backend accepts variable set count)
|
||||
3. Exercise list endpoint (GET /api/exercises for search)
|
||||
4. Custom workout CRUD (new tables + endpoints)
|
||||
5. Custom workout builder UI (frontend page)
|
||||
6. Modify program workout (fork program → custom)
|
||||
|
||||
Each phase is independently shippable. Phase 1 delivers immediate UX value with zero risk.
|
||||
|
||||
## Research Files
|
||||
|
||||
- `STACK.md` — Technology recommendations and what to avoid
|
||||
- `FEATURES.md` — Feature categorization (table stakes vs differentiators)
|
||||
- `ARCHITECTURE.md` — Schema design, component structure, data flow
|
||||
- `PITFALLS.md` — 7 critical pitfalls with prevention strategies
|
||||
Reference in New Issue
Block a user