# jay-withers/gym-log architecture

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

- Interactive diagram: https://gitdiagram.com/jay-withers/gym-log
- Repository: https://github.com/jay-withers/gym-log

## Overview

gym-log is a server-rendered training log for two weekly full-body workouts. A user enters through the passcode-protected web app, records sessions in an append-only history, and receives next-load suggestions from the progression rule; the same log supports block rotation, achievements, goals, conditions, and insights. Separate paths import spreadsheet blocks and sync Garmin activity and recovery data. The app stores its shared log in one JSON blob in Azure, with a local-file fallback. The README documents scheduled insight and Garmin jobs; some route, store, and Terraform wiring was not sampled, so uncertain calls are omitted.

Main entry points: [`src/gymlog/cli.py`](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/cli.py) (CLI commands), [`src/gymlog/store.py`](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/store.py) (Log storage), [`src/gymlog/api/routes.py`](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/routes.py) (Page routes), [`src/gymlog/api/main.py`](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/main.py) (FastAPI app)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["Web application"]
  node_webapp["FastAPI app<br/>[main.py]"]
  node_pages["Page routes<br/>[routes.py]"]
  node_auth["Passcode gate<br/>[deps.py]"]
  node_views["HTML templates"]
  node_cli["CLI commands<br/>[cli.py]"]
end

subgraph group_training["Training domain"]
  node_logmodel["Log model<br/>[model.py]"]
  node_progression["Load progression<br/>[progression.py]"]
  node_store["Log storage<br/>[store.py]"]
  node_localfile[("Local JSON file")]
  node_blob[("Azure blob")]
  node_importer["Workbook importer<br/>[importer.py]"]
end

subgraph group_integrations["External data"]
  node_insights["AI insights<br/>[insights.py]"]
  node_garmin["Garmin sync<br/>[garmin.py]"]
  node_garminconnect["Garmin Connect"]
  node_deepseek["DeepSeek API"]
end

subgraph group_operations["Scheduled operations"]
  node_insightjob["Insight schedule"]
  node_garminjob["Garmin schedule"]
end

node_athlete(("Athlete"))

node_athlete -->|"opens app"| node_webapp
node_webapp -->|"serves pages"| node_pages
node_webapp -->|"gates routes"| node_auth
node_pages -->|"renders HTML"| node_views
node_pages -->|"reads and writes"| node_store
node_pages -->|"gets suggestions"| node_progression
node_progression -->|"evaluates history"| node_logmodel
node_store -->|"serializes log"| node_logmodel
node_store -->|"reads and writes"| node_blob
node_store -.->|"falls back to"| node_localfile
node_cli -->|"imports workbook"| node_importer
node_cli -->|"loads and saves"| node_store
node_cli -->|"generates insight"| node_insights
node_cli -->|"syncs data"| node_garmin
node_insights -->|"requests summary"| node_deepseek
node_garmin -->|"fetches activity"| node_garminconnect
node_insightjob -->|"runs insight"| node_cli
node_garminjob -->|"runs sync"| node_cli

click node_webapp "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/main.py"
click node_pages "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/routes.py"
click node_auth "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/deps.py"
click node_views "https://github.com/jay-withers/gym-log/tree/main/src/gymlog/templates"
click node_logmodel "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/model.py"
click node_progression "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/progression.py"
click node_store "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/store.py"
click node_importer "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/importer.py"
click node_cli "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/cli.py"
click node_insights "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/insights.py"
click node_garmin "https://github.com/jay-withers/gym-log/blob/main/src/gymlog/garmin.py"
click node_insightjob "https://github.com/jay-withers/gym-log/blob/main/terraform/main.container-apps-job.tf"
click node_garminjob "https://github.com/jay-withers/gym-log/blob/main/terraform/main.container-apps-job.garmin.tf"

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_webapp,node_pages,node_auth,node_views,node_cli toneBlue
class node_logmodel,node_progression,node_store,node_localfile,node_blob,node_importer toneAmber
class node_insights,node_garmin,node_garminconnect,node_deepseek toneMint
class node_insightjob,node_garminjob toneRose
class node_athlete toneIndigo
```

## Components

### Web application

- [FastAPI app](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/main.py): `src/gymlog/api/main.py`
- [Page routes](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/routes.py): `src/gymlog/api/routes.py`
- [Passcode gate](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/api/deps.py): `src/gymlog/api/deps.py`
- [HTML templates](https://github.com/jay-withers/gym-log/tree/main/src/gymlog/templates): `src/gymlog/templates`
- [CLI commands](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/cli.py): `src/gymlog/cli.py`

### Training domain

- [Log model](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/model.py): `src/gymlog/model.py`
- [Load progression](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/progression.py): `src/gymlog/progression.py`
- [Log storage](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/store.py): `src/gymlog/store.py`
- **Local JSON file**
- **Azure blob**
- [Workbook importer](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/importer.py): `src/gymlog/importer.py`

### External data

- [AI insights](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/insights.py): `src/gymlog/insights.py`
- [Garmin sync](https://github.com/jay-withers/gym-log/blob/main/src/gymlog/garmin.py): `src/gymlog/garmin.py`
- **Garmin Connect**
- **DeepSeek API**

### Scheduled operations

- [Insight schedule](https://github.com/jay-withers/gym-log/blob/main/terraform/main.container-apps-job.tf): `terraform/main.container-apps-job.tf`
- [Garmin schedule](https://github.com/jay-withers/gym-log/blob/main/terraform/main.container-apps-job.garmin.tf): `terraform/main.container-apps-job.garmin.tf`

### Other components

- **Athlete**

## Connections

- Athlete → FastAPI app: opens app
- FastAPI app → Page routes: serves pages
- FastAPI app → Passcode gate: gates routes
- Page routes → HTML templates: renders HTML
- Page routes → Log storage: reads and writes
- Page routes → Load progression: gets suggestions
- Load progression → Log model: evaluates history
- Log storage → Log model: serializes log
- Log storage → Azure blob: reads and writes
- Log storage → Local JSON file: falls back to
- CLI commands → Workbook importer: imports workbook
- CLI commands → Log storage: loads and saves
- CLI commands → AI insights: generates insight
- CLI commands → Garmin sync: syncs data
- AI insights → DeepSeek API: requests summary
- Garmin sync → Garmin Connect: fetches activity
- Insight schedule → CLI commands: runs insight
- Garmin schedule → CLI commands: runs sync
