Ctrl K
ComunidadGuías…

docs/PROGRESS_CHARTS_DESIGN.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Progress Charts Design

> **Status:** Planning
> **Last Updated:** 2025-12-23

---

## Overview

This document describes the design for visual progress charts in ActaLog, covering PR calculations, existing components, integration points, and planned enhancements.

---

## PR Calculation System (Existing)

### 1RM Calculation (`pkg/prmath/one_rm.go`)

ActaLog uses a **hybrid formula approach** based on rep count:

| Rep Range | Formula | Description |
|-----------|---------|-------------|
| 1 rep | Actual | Weight lifted is the 1RM |
| 2-10 reps | Epley | `1RM = weight × (1 + reps/30)` |
| 11+ reps | Wathan | `1RM = (100 × weight) / (48.8 + 53.8 × e^(-0.075 × reps))` |

**Additional formulas available** (for comparison display):
- Brzycki: `1RM = weight × (36 / (37 - reps))`
- Lombardi: `1RM = weight × reps^0.10`
- Mayhew: `1RM = (100 × weight) / (52.2 + 41.9 × e^(-0.055 × reps))`
- O'Conner: `1RM = weight × (1 + reps/40)`

**Helper functions:**
- `CompareToBaseline(current1RM, baseline1RM)` → percentage improvement
- `CalculateIntensity(weight, oneRM)` → percentage of 1RM being used

### PR Detection (`internal/service/user_workout_service.go`)

#### Movement PRs (Weight-Based)
```go
func DetectAndFlagMovementPRs(userID int64, movements []*domain.UserWorkoutMovement)
```
- Calculates 1RM for each movement with weight+reps
- Compares against previous best 1RM for that movement
- First time = automatic PR
- Higher 1RM than previous best = PR

#### WOD PRs (Time/Rounds-Based)
```go
func DetectAndFlagWODPRs(userID int64, wods []*domain.UserWorkoutWOD)
```

**Time-based WODs (For Time):**
- Uses `GetBestTimeForWOD(userID, wodID)`
- Faster time = PR

**AMRAP WODs:**
- Uses `GetBestRoundsRepsForWOD(userID, wodID)`
- More rounds = PR
- Same rounds, more reps = PR

---

## Existing Chart Components

### 1. WeightProgressChart.vue
**Location:** `web/src/components/charts/WeightProgressChart.vue`

**Features:**
- Line chart with Chart.js
- Movement selector (filters to Weightlifting type)
- Fetches from `/api/performance/movements/{id}`
- PRs highlighted in gold/warning color (larger points)
- Tooltip shows weight + PR indicator
- Theme-aware colors
- Responsive 250px height

**Data shown:**
- X-axis: Workout dates (MMM DD format)
- Y-axis: Weight (lbs)
- PR points: Highlighted with larger radius and warning color

### 2. WorkoutFrequencyChart.vue
**Location:** `web/src/components/charts/WorkoutFrequencyChart.vue`

**Features:**
- Bar chart with Chart.js
- Time range selector: 30d / 90d / 6m / 1y
- Fetches from `/api/workouts`
- Groups workouts by week
- Summary stats below chart

**Data shown:**
- X-axis: Week start dates (MMM DD format)
- Y-axis: Workout count per week
- Summary: Total Workouts, Avg/Week, Longest Streak

---

## API Endpoints

| Endpoint | Handler | Returns |
|----------|---------|---------|
| `GET /api/performance/search` | UnifiedSearch | Movements + WODs matching query |
| `GET /api/performance/movements/{id}` | GetMovementPerformance | All performances + calculated 1RM + best 1RM |
| `GET /api/performance/wods/{id}` | GetWODPerformance | All WOD performances |
| `GET /api/workouts/personal-records` | GetPersonalRecords | All PRs (movements + WODs) |
| `GET /api/workouts/personal-records/movements` | GetPRMovements | Movement PR summaries |
| `POST /api/workouts/personal-records/toggle` | ToggleMovementPR | Toggle PR flag |

---

## Integration Plan

### Phase 1: Integrate Existing Charts

#### 1.1 Dashboard View (`DashboardView.vue`)
Add WorkoutFrequencyChart below the welcome section:

```
┌─────────────────────────────────────────────┐
│ Welcome back, [User]!                       │
├─────────────────────────────────────────────┤
│ Workout Frequency              30d 90d 6m 1y│
│ ┌─────────────────────────────────────────┐ │
│ │ █   █       █ █ █   █ █     █   █ █     │ │
│ │ █ █ █ █   █ █ █ █ █ █ █ █   █ █ █ █ █   │ │
│ └─────────────────────────────────────────┘ │
│ Total: 24  |  Avg/Week: 4.2  |  Streak: 5   │
├─────────────────────────────────────────────┤
│ Recent Workouts                             │
│ • Dec 22 - Full Body...                     │
│ • Dec 20 - Upper Body...                    │
└─────────────────────────────────────────────┘
```

#### 1.2 Performance View (`PerformanceView.vue`)
Add WeightProgressChart when a movement is selected:

```
┌─────────────────────────────────────────────┐
│ Search for a WOD or Movement...             │
├─────────────────────────────────────────────┤
│ [Quick Log Back Squat]                      │
├─────────────────────────────────────────────┤
│ Weight Progress         Select Movement ▼   │
│ ┌─────────────────────────────────────────┐ │
│ │        *                                │ │
│ │      /   \    *  <- PR (gold)           │ │
│ │    /       \/                           │ │
│ │  /                                      │ │
│ └─────────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Heaviest Lifts: 315 | 305 | 295            │
├─────────────────────────────────────────────┤
│ Performance History (table)                 │
└─────────────────────────────────────────────┘
```

#### 1.3 Profile View (`ProfileView.vue`)
Add WorkoutFrequencyChart in workout summary section:

```
┌─────────────────────────────────────────────┐
│ [Avatar] John Doe                           │
│ Member since Jan 2024                       │
├─────────────────────────────────────────────┤
│ Workout Activity              30d 90d 6m 1y │
│ ┌─────────────────────────────────────────┐ │
│ │ [WorkoutFrequencyChart]                 │ │
│ └─────────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ Personal Records Summary                    │
└─────────────────────────────────────────────┘
```

---

### Phase 2: New Charts

#### 2.1 Estimated1RMChart.vue
**Purpose:** Track calculated 1RM progression over time for a movement

**Data source:** `/api/performance/movements/{id}`

**Display:**
- Line chart showing estimated 1RM over time
- Current formula shown (Epley/Wathan/Actual)
- Percentage improvement from first data point
- Goal line (optional user-set target)

**Features:**
- Time range selector (3m/6m/1y/all)
- Compare formulas toggle
- Show actual weights as secondary series

#### 2.2 WODTimeChart.vue
**Purpose:** Track time progression for "For Time" WODs

**Data source:** `/api/performance/wods/{id}`

**Display:**
- Line chart with time (inverted - lower is better)
- PRs highlighted in gold
- Time format: MM:SS or H:MM:SS

**Use case:** Track Fran, Murph, Grace times

#### 2.3 WODAMRAPChart.vue
**Purpose:** Track rounds+reps progression for AMRAP WODs

**Data source:** `/api/performance/wods/{id}`

**Display:**
- Bar or line chart showing total score (rounds × reps_per_round + extra_reps)
- Or stacked bar: rounds + remaining reps
- PRs highlighted

**Use case:** Track Cindy, Mary scores

#### 2.4 VolumeChart.vue
**Purpose:** Track total training volume over time

**Calculation:** `Σ (weight × reps × sets)` per session

**Data source:** `/api/workouts` with movement details

**Display:**
- Area or bar chart by week/month
- Filter by movement type (all, upper, lower, full body)
- Compare periods

#### 2.5 PRDistributionChart.vue
**Purpose:** Show distribution of PRs by movement type

**Data source:** `/api/workouts/personal-records/movements`

**Display:**
- Pie or donut chart
- Segments: Weightlifting, Gymnastics, Cardio, etc.
- Click segment to filter PR list

---

### Phase 3: Enhanced Analytics

#### 3.1 MonthlyComparisonChart.vue
**Purpose:** Compare this month vs last month

**Display:**
- Side-by-side bars
- Metrics: workouts, PRs, total volume, avg frequency
- Trend arrows (up/down/same)

#### 3.2 BodyweightMovementProgressChart.vue
**Purpose:** Track progress on movements without weight (pullups, pushups, etc.)

**Metrics:**
- Max unbroken reps
- Total reps per session
- Time to complete fixed reps

---

## Implementation Priority

### Priority 1 (Quick Win - 1-2 hours)
1. Add `WorkoutFrequencyChart` to `DashboardView.vue`
2. Add `WeightProgressChart` to `PerformanceView.vue`

### Priority 2 (Medium - 4-6 hours)
3. Create `Estimated1RMChart.vue`
4. Create `WODTimeChart.vue`
5. Create `WODAMRAPChart.vue`

### Priority 3 (Enhanced - 4-6 hours)
6. Create `VolumeChart.vue`
7. Create `PRDistributionChart.vue`
8. Create `MonthlyComparisonChart.vue`

---

## Technical Notes

### Chart.js Configuration
All charts use:
- `vue-chartjs` wrapper
- Theme-aware colors via `useTheme()`
- Responsive sizing with `maintainAspectRatio: false`
- Custom tooltips for contextual data

### Color Scheme
| Element | Color | CSS Variable |
|---------|-------|--------------|
| Primary data | Theme primary | `--v-theme-primary` |
| PR highlights | Warning/Gold | `--v-theme-warning` |
| Fill areas | Primary @ 10% opacity | Computed RGBA |
| Grid lines | Surface variant | `--v-theme-surface-variant` |

### Accessibility
- Charts should have aria-labels
- Color alone should not convey meaning (use shapes/labels)
- Provide data tables as alternative

---

## Future Considerations

1. **Export charts as images** - For sharing on social media
2. **Comparison mode** - Compare two time periods or two movements
3. **Goal tracking** - User-set targets with progress indicators
4. **Prediction lines** - Extrapolate trends to predict future PRs
5. **Coach view** - Aggregate charts for multiple athletes