# andysq2023/cycling-coach architecture

> Architecture diagram of the GitHub repository andysq2023/cycling-coach, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-23). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/andysq2023/cycling-coach
- Repository: https://github.com/andysq2023/cycling-coach

## Overview

Cycling Coach is a single-file browser coaching app with local or hosted service endpoints. The main workflow combines athlete data and training feedback in the app’s coach conversation, produces and adapts a schedule, and persists coaching state. The README documents additional workout, route-reconciliation and strength features implemented in the same front end. Source excerpts are partial, so uncertain internal wiring is omitted; the documented integrations and API responsibilities are retained.

Main entry points: [`app/cycling-coach.html`](https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html) (Coach interface), [`proxy/server.js`](https://github.com/andysq2023/cycling-coach/blob/main/proxy/server.js) (Local data proxy), [`api/_auth.js`](https://github.com/andysq2023/cycling-coach/blob/main/api/_auth.js) (API authentication), [`api/chat.js`](https://github.com/andysq2023/cycling-coach/blob/main/api/chat.js) (Coach chat API)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_front["Coaching app"]
  node_app["Coach interface<br/>[cycling-coach.html]"]
  node_schedule["Plan and adaptation<br/>[cycling-coach.html]"]
  node_feedback["Session feedback<br/>[cycling-coach.html]"]
  node_strength["Strength workouts<br/>[cycling-coach.html]"]
  node_routesui["Route planning UI<br/>[cycling-coach.html]"]
end

subgraph group_services["API services"]
  node_chat["Coach chat API<br/>[chat.js]"]
  node_whoop["WHOOP API<br/>[whoop.js]"]
  node_stravaapi["Strava API<br/>[strava.js]"]
  node_routeapi["Route planner API<br/>[route.js]"]
  node_stateapi["State sync API<br/>[state.js]"]
  node_routesapi["Saved routes API<br/>[routes.js]"]
  node_weatherapi["Weather API<br/>[weather.js]"]
  node_intervalsapi["Intervals API<br/>[intervals.js]"]
  node_auth["API authentication<br/>[_auth.js]"]
end

subgraph group_integrations["Data integrations"]
  node_proxy["Local data proxy<br/>[server.js]"]
  node_stravacore["Strava shaping<br/>[strava-core.js]"]
  node_weathercore["Forecast shaping<br/>[weather-core.js]"]
  node_intervalscore["Training metrics<br/>[intervals-core.js]"]
end

subgraph group_storage["Persistence"]
  node_kv[("Vercel KV")]
  node_statehelper["State access<br/>[_state.js]"]
end

node_athlete(("Athlete"))
node_anthropic["Anthropic"]
node_whoopservice["WHOOP"]
node_stravaservice["Strava"]
node_graphhopper["GraphHopper"]
node_openmeteo["Open-Meteo"]
node_icu["intervals.icu"]

node_athlete -->|"uses"| node_app
node_app -->|"sends prompts"| node_chat
node_chat -->|"requests replies"| node_anthropic
node_app -->|"fetches recovery"| node_whoop
node_whoop -->|"refreshes and reads"| node_whoopservice
node_app -->|"fetches rides"| node_stravaapi
node_stravaapi -->|"shapes activities"| node_stravacore
node_stravacore -->|"fetches ride data"| node_stravaservice
node_app -->|"generates and adapts"| node_schedule
node_app -->|"logs sessions"| node_feedback
node_feedback -->|"triggers adaptation"| node_schedule
node_app -->|"manages workouts"| node_strength
node_app -->|"plans and reconciles"| node_routesui
node_routesui -->|"requests routes"| node_routeapi
node_routeapi -->|"requests directions"| node_graphhopper
node_routeapi -->|"reads and writes cache"| node_kv
node_app -->|"syncs coach state"| node_stateapi
node_stateapi -->|"checks access"| node_auth
node_routesapi -->|"checks access"| node_auth
node_chat -->|"checks access"| node_auth
node_whoop -->|"checks access"| node_auth
node_stateapi -->|"reads and writes"| node_statehelper
node_statehelper -->|"stores state"| node_kv
node_routesapi -->|"reads and writes routes"| node_kv
node_proxy -->|"shapes activities"| node_stravacore
node_proxy -->|"builds forecast"| node_weathercore
node_proxy -->|"builds training summary"| node_intervalscore
node_proxy -->|"refreshes and fetches"| node_stravaservice
node_weathercore -->|"fetches forecast"| node_openmeteo
node_intervalscore -->|"fetches metrics"| node_icu
node_app -.->|"requests forecast"| node_weatherapi
node_app -.->|"requests metrics"| node_intervalsapi

click node_app "https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html"
click node_schedule "https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html"
click node_feedback "https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html"
click node_strength "https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html"
click node_routesui "https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html"
click node_chat "https://github.com/andysq2023/cycling-coach/blob/main/api/chat.js"
click node_whoop "https://github.com/andysq2023/cycling-coach/blob/main/api/whoop.js"
click node_stravaapi "https://github.com/andysq2023/cycling-coach/blob/main/api/strava.js"
click node_routeapi "https://github.com/andysq2023/cycling-coach/blob/main/api/route.js"
click node_stateapi "https://github.com/andysq2023/cycling-coach/blob/main/api/state.js"
click node_routesapi "https://github.com/andysq2023/cycling-coach/blob/main/api/routes.js"
click node_weatherapi "https://github.com/andysq2023/cycling-coach/blob/main/api/weather.js"
click node_intervalsapi "https://github.com/andysq2023/cycling-coach/blob/main/api/intervals.js"
click node_proxy "https://github.com/andysq2023/cycling-coach/blob/main/proxy/server.js"
click node_stravacore "https://github.com/andysq2023/cycling-coach/blob/main/shared/strava-core.js"
click node_weathercore "https://github.com/andysq2023/cycling-coach/blob/main/shared/weather-core.js"
click node_intervalscore "https://github.com/andysq2023/cycling-coach/blob/main/shared/intervals-core.js"
click node_statehelper "https://github.com/andysq2023/cycling-coach/blob/main/api/_state.js"
click node_auth "https://github.com/andysq2023/cycling-coach/blob/main/api/_auth.js"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_schedule,node_feedback,node_strength,node_routesui toneBlue
class node_chat,node_whoop,node_stravaapi,node_routeapi,node_stateapi,node_routesapi,node_weatherapi,node_intervalsapi,node_auth toneAmber
class node_proxy,node_stravacore,node_weathercore,node_intervalscore toneMint
class node_kv,node_statehelper toneRose
class node_athlete,node_anthropic,node_whoopservice,node_stravaservice,node_graphhopper,node_openmeteo,node_icu toneIndigo
```

## Components

### Coaching app

- [Coach interface](https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html): `app/cycling-coach.html`
- [Plan and adaptation](https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html): `app/cycling-coach.html`
- [Session feedback](https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html): `app/cycling-coach.html`
- [Strength workouts](https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html): `app/cycling-coach.html`
- [Route planning UI](https://github.com/andysq2023/cycling-coach/blob/main/app/cycling-coach.html): `app/cycling-coach.html`

### API services

- [Coach chat API](https://github.com/andysq2023/cycling-coach/blob/main/api/chat.js): `api/chat.js`
- [WHOOP API](https://github.com/andysq2023/cycling-coach/blob/main/api/whoop.js): `api/whoop.js`
- [Strava API](https://github.com/andysq2023/cycling-coach/blob/main/api/strava.js): `api/strava.js`
- [Route planner API](https://github.com/andysq2023/cycling-coach/blob/main/api/route.js): `api/route.js`
- [State sync API](https://github.com/andysq2023/cycling-coach/blob/main/api/state.js): `api/state.js`
- [Saved routes API](https://github.com/andysq2023/cycling-coach/blob/main/api/routes.js): `api/routes.js`
- [Weather API](https://github.com/andysq2023/cycling-coach/blob/main/api/weather.js): `api/weather.js`
- [Intervals API](https://github.com/andysq2023/cycling-coach/blob/main/api/intervals.js): `api/intervals.js`
- [API authentication](https://github.com/andysq2023/cycling-coach/blob/main/api/_auth.js): `api/_auth.js`

### Data integrations

- [Local data proxy](https://github.com/andysq2023/cycling-coach/blob/main/proxy/server.js): `proxy/server.js`
- [Strava shaping](https://github.com/andysq2023/cycling-coach/blob/main/shared/strava-core.js): `shared/strava-core.js`
- [Forecast shaping](https://github.com/andysq2023/cycling-coach/blob/main/shared/weather-core.js): `shared/weather-core.js`
- [Training metrics](https://github.com/andysq2023/cycling-coach/blob/main/shared/intervals-core.js): `shared/intervals-core.js`

### Persistence

- **Vercel KV**
- [State access](https://github.com/andysq2023/cycling-coach/blob/main/api/_state.js): `api/_state.js`

### Other components

- **Athlete**
- **Anthropic**
- **WHOOP**
- **Strava**
- **GraphHopper**
- **Open-Meteo**
- **intervals.icu**

## Connections

- Athlete → Coach interface: uses
- Coach interface → Coach chat API: sends prompts
- Coach chat API → Anthropic: requests replies
- Coach interface → WHOOP API: fetches recovery
- WHOOP API → WHOOP: refreshes and reads
- Coach interface → Strava API: fetches rides
- Strava API → Strava shaping: shapes activities
- Strava shaping → Strava: fetches ride data
- Coach interface → Plan and adaptation: generates and adapts
- Coach interface → Session feedback: logs sessions
- Session feedback → Plan and adaptation: triggers adaptation
- Coach interface → Strength workouts: manages workouts
- Coach interface → Route planning UI: plans and reconciles
- Route planning UI → Route planner API: requests routes
- Route planner API → GraphHopper: requests directions
- Route planner API → Vercel KV: reads and writes cache
- Coach interface → State sync API: syncs coach state
- State sync API → API authentication: checks access
- Saved routes API → API authentication: checks access
- Coach chat API → API authentication: checks access
- WHOOP API → API authentication: checks access
- State sync API → State access: reads and writes
- State access → Vercel KV: stores state
- Saved routes API → Vercel KV: reads and writes routes
- Local data proxy → Strava shaping: shapes activities
- Local data proxy → Forecast shaping: builds forecast
- Local data proxy → Training metrics: builds training summary
- Local data proxy → Strava: refreshes and fetches
- Forecast shaping → Open-Meteo: fetches forecast
- Training metrics → intervals.icu: fetches metrics
- Coach interface → Weather API: requests forecast
- Coach interface → Intervals API: requests metrics
