> For the complete documentation index, see [llms.txt](https://docs.tryterra.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tryterra.co/planned-workouts-api/core-concepts.md).

# Core Concepts

> ⚠️ **Pre-Release / Under Construction**
>
> This page is currently **under active development** and is provided in a **pre-release state**.
>
> Content may be **incomplete, outdated, or inaccurate**, and details may changewithout notice as the implementation evolves.
>
> Please use this documentation for **early reference only**, and avoid relying on it for production-critical decisions until the page is marked as stable.

### Workout Structure

A workout template is a hierarchy of blocks and steps:

```
WorkoutTemplate
├── name: "FTP Intervals"
├── sport: "cycling"
├── environment: "outdoor" (optional — indoor, outdoor, pool)
├── description: "Build threshold power"
├── pool_length_meters: null (only for swimming)
│
└── step_blocks: [
      StepBlock {
        completion_condition: { type: "reps", value: 4 }  ← Repeat 4 times
        steps: [
          WorkoutStep { ... },  ← Do this
          WorkoutStep { ... }   ← Then this
        ]
      }
    ]
```

### Step Blocks

A step block groups one or more steps that execute together. The block's `completion_condition` controls repetition:

| Block Completion                        | Behavior                      |
| --------------------------------------- | ----------------------------- |
| `{ "type": "reps", "value": 4 }`        | Repeat all steps 4 times      |
| `{ "type": "time", "value": 1200 }`     | Repeat until 20 minutes total |
| `{ "type": "distance", "value": 5000 }` | Repeat until 5km total        |
| `{ "type": "open" }` or omitted         | Execute once (no repeat)      |

#### Example: 4x400m Intervals

```json
{
  "step_blocks": [{
    "completion_condition": { "type": "reps", "value": 4 },
    "steps": [
      {
        "completion_condition": { "type": "distance", "value": 400 },
        "intensity_type": "active"
      },
      {
        "completion_condition": { "type": "distance", "value": 200 },
        "intensity_type": "rest"
      }
    ]
  }]
}
```

This creates: 400m fast → 200m easy → 400m fast → 200m easy → 400m fast → 200m easy → 400m fast → 200m easy

### Workout Steps

Each step defines:

| Field                  | Required | Description                            |
| ---------------------- | -------- | -------------------------------------- |
| `completion_condition` | Yes      | When this step ends                    |
| `intensity_type`       | Yes      | How hard (warmup/active/rest/cooldown) |
| `intensity_targets`    | No       | Target metrics (HR, power, pace, etc.) |
| `notes`                | No       | Text shown to athlete                  |
| `strength`             | No       | Exercise details for strength training |
| `swimming`             | No       | Stroke/equipment for swimming          |

### Completion Conditions

How a step (or block) ends:

| Type                 | Value   | Description                                |
| -------------------- | ------- | ------------------------------------------ |
| `time`               | Seconds | End after duration (e.g., 300 = 5 minutes) |
| `distance`           | Meters  | End after distance (e.g., 1000 = 1km)      |
| `reps`               | Count   | End after N repetitions                    |
| `calories`           | kcal    | End after calories burned                  |
| `open`               | —       | Manual end (lap button)                    |
| `hr_less_than`       | BPM     | End when HR drops below                    |
| `hr_greater_than`    | BPM     | End when HR rises above                    |
| `power_less_than`    | Watts   | End when power drops below                 |
| `power_greater_than` | Watts   | End when power rises above                 |

#### Example: Recovery Until HR Drops

```json
{
  "completion_condition": {
    "type": "hr_less_than",
    "value": 120
  },
  "intensity_type": "rest"
}
```

### Intensity Types

| Type       | Display         | Use For                       |
| ---------- | --------------- | ----------------------------- |
| `warmup`   | Warmup          | Gradual start                 |
| `active`   | Work / Interval | Main effort                   |
| `rest`     | Rest            | Full stop between intervals   |
| `recovery` | Recovery        | Easy effort between intervals |
| `cooldown` | Cooldown        | Gradual end                   |

### Intensity Targets

Targets define the goal metric for a step. You can have multiple targets per step (provider-dependent).

#### Target Types

**Absolute Targets:**

| Target Type  | Value Unit | Example                       | Provider Support          |
| ------------ | ---------- | ----------------------------- | ------------------------- |
| `heart_rate` | BPM        | 150-160 BPM                   | All providers             |
| `power`      | Watts      | 250-280W                      | All except Huawei         |
| `speed`      | m/s        | 4.0-4.5 m/s                   | All providers             |
| `pace`       | sec/km     | 270-300 sec/km (4:30-5:00/km) | All providers             |
| `cadence`    | rpm or spm | 170-180 spm                   | All providers             |
| `rpe`        | 1-10       | 7-8 RPE                       | Wahoo, TrainingPeaks only |

**Percentage Targets** (require athlete parameters at scheduling):

| Target Type                       | Requires               | Example                  |
| --------------------------------- | ---------------------- | ------------------------ |
| `heart_rate_max_percentage`       | `max_heart_rate`       | 80-85% of max HR         |
| `heart_rate_threshold_percentage` | `threshold_heart_rate` | 95-100% of threshold     |
| `power_percentage`                | `ftp`                  | 90-95% of FTP            |
| `speed_percentage`                | `threshold_speed`      | 85-90% of threshold pace |

**Zone Targets** (device-configured zones):

| Target Type       | Value | Provider Support                                                                                                          |
| ----------------- | ----- | ------------------------------------------------------------------------------------------------------------------------- |
| `heart_rate_zone` | 1-5   | All providers (Garmin native, others convert to BPM or %). Uses threshold HR (COROS, Zepp) or max HR (others) as baseline |
| `power_zone`      | 1-7   | All except Huawei (Garmin native, others convert to % FTP or watts)                                                       |

#### Target Value Formats

Targets support single values or ranges:

```json
// Range (recommended)
{
  "target_type": "power_percentage",
  "value_low": 90,
  "value_high": 95
}

// Single value (Terra expands to ±5% range automatically, except RPE which stays as a point value)
{
  "target_type": "heart_rate",
  "value": 155
}
```

### Sport Types

| Sport                | Description               | Provider Support                                  |
| -------------------- | ------------------------- | ------------------------------------------------- |
| `running`            | Running                   | All providers                                     |
| `cycling`            | Cycling                   | All except Huawei                                 |
| `swimming`           | Swimming                  | Garmin, COROS, Suunto, TrainingPeaks, Zepp, Apple |
| `strength`           | Weight training           | Garmin, COROS, Suunto, TrainingPeaks, Apple, Hevy |
| `rowing`             | Rowing                    | Garmin, Apple                                     |
| `yoga`               | Yoga                      | Garmin, Apple                                     |
| `pilates`            | Pilates                   | Garmin only                                       |
| `cardio`             | General cardio            | Garmin only                                       |
| `trail_running`      | Trail running             | Garmin, COROS, Wahoo, Suunto, Zepp                |
| `mountain_biking`    | Mountain biking           | Garmin, Wahoo, Suunto, TrainingPeaks              |
| `backcountry_skiing` | Backcountry / ski touring | Garmin, Suunto                                    |

Unsupported sport types are coerced to the provider's default (usually running) with a coercion warning. See Provider Compatibility for details.

### Environment (Optional)

Use the `environment` field to distinguish indoor/outdoor variants:

| Environment | Description                               |
| ----------- | ----------------------------------------- |
| `indoor`    | Indoor (treadmill, stationary bike, etc.) |
| `outdoor`   | Outdoor                                   |
| `pool`      | Pool swimming                             |

If omitted, the provider uses its default. Examples:

```json
{ "sport": "running", "environment": "indoor" }    // Treadmill
{ "sport": "cycling", "environment": "indoor" }    // Stationary bike
{ "sport": "swimming", "environment": "pool" }     // Lap swimming
{ "sport": "swimming", "environment": "outdoor" }  // Open water swimming
{ "sport": "running" }                              // Default (outdoor)
```

### Complete Example

A 30-minute cycling workout with warmup, FTP intervals, and cooldown:

```json
{
  "name": "30min FTP Builder",
  "sport": "cycling",
  "description": "4x4min @ 95-100% FTP with 2min recovery",
  "step_blocks": [
    {
      "steps": [{
        "completion_condition": { "type": "time", "value": 300 },
        "intensity_type": "warmup",
        "intensity_targets": [{
          "target_type": "power_percentage",
          "value_low": 50,
          "value_high": 60
        }]
      }]
    },
    {
      "completion_condition": { "type": "reps", "value": 4 },
      "steps": [
        {
          "completion_condition": { "type": "time", "value": 240 },
          "intensity_type": "active",
          "intensity_targets": [{
            "target_type": "power_percentage",
            "value_low": 95,
            "value_high": 100
          }]
        },
        {
          "completion_condition": { "type": "time", "value": 120 },
          "intensity_type": "rest",
          "intensity_targets": [{
            "target_type": "power_percentage",
            "value_low": 40,
            "value_high": 50
          }]
        }
      ]
    },
    {
      "steps": [{
        "completion_condition": { "type": "time", "value": 300 },
        "intensity_type": "cooldown",
        "intensity_targets": [{
          "target_type": "power_percentage",
          "value_low": 40,
          "value_high": 50
        }]
      }]
    }
  ]
}
```

### Validation Rules

Templates are validated when created. Key rules:

| Field                      | Requirement                                                                                                                        |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `name`                     | Required, non-empty                                                                                                                |
| `sport`                    | Required, must be a valid sport type                                                                                               |
| `step_blocks`              | At least one block required                                                                                                        |
| Each block                 | At least one step required                                                                                                         |
| Each step                  | `intensity_type` required (`warmup`, `active`, `rest`, `recovery`, `cooldown`)                                                     |
| Each step                  | `completion_condition` defaults to `open` if omitted                                                                               |
| `pool_length_meters`       | Only allowed for swimming workouts                                                                                                 |
| `value_low` / `value_high` | Cannot use both `value` and `value_low`/`value_high` on the same target                                                            |
| Range targets              | `value_low` must be strictly less than `value_high`                                                                                |
| Athlete metrics            | All values must be positive if provided (`ftp`, `max_heart_rate`, `threshold_heart_rate`, `threshold_speed`, `pool_length_meters`) |
| `planned_date`             | Format: `YYYY-MM-DD`                                                                                                               |

**Target value sanity checks** (warnings, not hard rejections for most):

| Target Type        | Valid Range |
| ------------------ | ----------- |
| Heart rate (BPM)   | 30–250      |
| Power (watts)      | 1–2000      |
| Speed (m/s)        | 0–15        |
| Pace (sec/km)      | 1–7200      |
| Cadence (rpm/spm)  | 1–300       |
| RPE                | 1–10        |
| Percentage targets | 0–200%      |
