# robrosk/oura-coach architecture

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

- Interactive diagram: https://gitdiagram.com/robrosk/oura-coach
- Repository: https://github.com/robrosk/oura-coach

## Overview

Oura Coach is a wellness web app whose visible workflow is: enter from the public home page, pass the terms-and-privacy gate, then visit the app or begin Oura authorization. Its landing page also advertises sleep/readiness/activity insights, experiments, and context logging, but the supplied excerpts do not show those capabilities implemented. The graph reflects the sampled frontend and documented OAuth handoff; backend internals and the database are not shown, so their behavior is left unspecified.

Main entry points: [`web/src/App.tsx`](https://github.com/robrosk/oura-coach/blob/main/web/src/App.tsx) (Route dispatcher), [`web/src/components/Layout.tsx`](https://github.com/robrosk/oura-coach/blob/main/web/src/components/Layout.tsx) (Shared page layout), [`web/src/components/TermsGate.tsx`](https://github.com/robrosk/oura-coach/blob/main/web/src/components/TermsGate.tsx) (Terms access gate), [`web/src/pages/Accept.tsx`](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Accept.tsx) (Consent acceptance)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_routing["Web routing and shell"]
  node_router["Route dispatcher<br/>[App.tsx]"]
  node_layout["Shared page layout<br/>[Layout.tsx]"]
  node_header["Site navigation<br/>[Header.tsx]"]
  node_footer["Site footer<br/>[Footer.tsx]"]
end

subgraph group_consent["Consent and legal content"]
  node_terms_gate["Terms access gate<br/>[TermsGate.tsx]"]
  node_accept["Consent acceptance<br/>[Accept.tsx]"]
  node_scrollable_terms["Scrollable terms"]
  node_terms_state["Consent version check<br/>[terms.ts]"]
  node_local_storage[("Browser consent storage<br/>[storage.ts]")]
  node_markdown_page["Legal document renderer<br/>[MarkdownPage.tsx]"]
  node_privacy["Privacy page<br/>[Privacy.tsx]"]
  node_terms["Terms page<br/>[Terms.tsx]"]
end

subgraph group_app["Wellness app and Oura connection"]
  node_home["Public landing<br/>[Home.tsx]"]
  node_app_home["App home<br/>[AppHome.tsx]"]
  node_connect["Oura connection screen<br/>[Connect.tsx]"]
  node_welcome["Authorization welcome<br/>[Welcome.tsx]"]
  node_api_client["OAuth API client<br/>[api.ts]"]
end

node_visitor(("User"))
node_backend{{"Oura Coach backend"}}
node_oura{{"Oura authorization"}}

node_visitor -->|"opens routes"| node_router
node_router -->|"wraps pages"| node_layout
node_layout -->|"renders"| node_header
node_layout -->|"renders"| node_footer
node_router -->|"routes to"| node_home
node_router -->|"protects app routes"| node_terms_gate
node_terms_gate -->|"renders when allowed"| node_app_home
node_terms_gate -->|"checks acceptance"| node_terms_state
node_terms_state -->|"reads acceptance"| node_local_storage
node_router -->|"routes to"| node_accept
node_accept -->|"renders terms"| node_scrollable_terms
node_accept -->|"records acceptance"| node_local_storage
node_router -->|"routes to"| node_privacy
node_router -->|"routes to"| node_terms
node_privacy -->|"renders document"| node_markdown_page
node_terms -->|"renders document"| node_markdown_page
node_router -->|"routes to"| node_connect
node_router -->|"routes to"| node_welcome
node_connect -->|"starts authorization"| node_api_client
node_api_client -->|"requests auth URL"| node_backend
node_connect -->|"redirects for authorization"| node_oura

click node_router "https://github.com/robrosk/oura-coach/blob/main/web/src/App.tsx"
click node_layout "https://github.com/robrosk/oura-coach/blob/main/web/src/components/Layout.tsx"
click node_header "https://github.com/robrosk/oura-coach/blob/main/web/src/components/Header.tsx"
click node_footer "https://github.com/robrosk/oura-coach/blob/main/web/src/components/Footer.tsx"
click node_home "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Home.tsx"
click node_terms_gate "https://github.com/robrosk/oura-coach/blob/main/web/src/components/TermsGate.tsx"
click node_accept "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Accept.tsx"
click node_scrollable_terms "https://github.com/robrosk/oura-coach/blob/main/web/src/components/ScrollableTerms.tsx"
click node_terms_state "https://github.com/robrosk/oura-coach/blob/main/web/src/lib/terms.ts"
click node_local_storage "https://github.com/robrosk/oura-coach/blob/main/web/src/lib/storage.ts"
click node_markdown_page "https://github.com/robrosk/oura-coach/blob/main/web/src/components/MarkdownPage.tsx"
click node_privacy "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Privacy.tsx"
click node_terms "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Terms.tsx"
click node_app_home "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/app/AppHome.tsx"
click node_connect "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/app/Connect.tsx"
click node_welcome "https://github.com/robrosk/oura-coach/blob/main/web/src/pages/app/Welcome.tsx"
click node_api_client "https://github.com/robrosk/oura-coach/blob/main/web/src/lib/api.ts"

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_router,node_layout,node_header,node_footer,node_visitor toneBlue
class node_terms_gate,node_accept,node_scrollable_terms,node_terms_state,node_local_storage,node_markdown_page,node_privacy,node_terms toneAmber
class node_home,node_app_home,node_connect,node_welcome,node_api_client toneMint
class node_backend,node_oura toneIndigo
```

## Components

### Web routing and shell

- [Route dispatcher](https://github.com/robrosk/oura-coach/blob/main/web/src/App.tsx): `web/src/App.tsx`
- [Shared page layout](https://github.com/robrosk/oura-coach/blob/main/web/src/components/Layout.tsx): `web/src/components/Layout.tsx`
- [Site navigation](https://github.com/robrosk/oura-coach/blob/main/web/src/components/Header.tsx): `web/src/components/Header.tsx`
- [Site footer](https://github.com/robrosk/oura-coach/blob/main/web/src/components/Footer.tsx): `web/src/components/Footer.tsx`

### Consent and legal content

- [Terms access gate](https://github.com/robrosk/oura-coach/blob/main/web/src/components/TermsGate.tsx): `web/src/components/TermsGate.tsx`
- [Consent acceptance](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Accept.tsx): `web/src/pages/Accept.tsx`
- [Scrollable terms](https://github.com/robrosk/oura-coach/blob/main/web/src/components/ScrollableTerms.tsx): `web/src/components/ScrollableTerms.tsx`
- [Consent version check](https://github.com/robrosk/oura-coach/blob/main/web/src/lib/terms.ts): `web/src/lib/terms.ts`
- [Browser consent storage](https://github.com/robrosk/oura-coach/blob/main/web/src/lib/storage.ts): `web/src/lib/storage.ts`
- [Legal document renderer](https://github.com/robrosk/oura-coach/blob/main/web/src/components/MarkdownPage.tsx): `web/src/components/MarkdownPage.tsx`
- [Privacy page](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Privacy.tsx): `web/src/pages/Privacy.tsx`
- [Terms page](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Terms.tsx): `web/src/pages/Terms.tsx`

### Wellness app and Oura connection

- [Public landing](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/Home.tsx): `web/src/pages/Home.tsx`
- [App home](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/app/AppHome.tsx): `web/src/pages/app/AppHome.tsx`
- [Oura connection screen](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/app/Connect.tsx): `web/src/pages/app/Connect.tsx`
- [Authorization welcome](https://github.com/robrosk/oura-coach/blob/main/web/src/pages/app/Welcome.tsx): `web/src/pages/app/Welcome.tsx`
- [OAuth API client](https://github.com/robrosk/oura-coach/blob/main/web/src/lib/api.ts): `web/src/lib/api.ts`

### Other components

- **User**
- **Oura Coach backend**
- **Oura authorization**

## Connections

- User → Route dispatcher: opens routes
- Route dispatcher → Shared page layout: wraps pages (evidence: `web/src/App.tsx`)
- Shared page layout → Site navigation: renders (evidence: `web/src/components/Layout.tsx`)
- Shared page layout → Site footer: renders (evidence: `web/src/components/Layout.tsx`)
- Route dispatcher → Public landing: routes to (evidence: `web/src/App.tsx`)
- Route dispatcher → Terms access gate: protects app routes (evidence: `web/src/App.tsx`)
- Terms access gate → App home: renders when allowed (evidence: `web/src/App.tsx`)
- Terms access gate → Consent version check: checks acceptance (evidence: `web/src/components/TermsGate.tsx`)
- Consent version check → Browser consent storage: reads acceptance (evidence: `web/src/lib/terms.ts`)
- Route dispatcher → Consent acceptance: routes to (evidence: `web/src/App.tsx`)
- Consent acceptance → Scrollable terms: renders terms (evidence: `web/src/pages/Accept.tsx`)
- Consent acceptance → Browser consent storage: records acceptance (evidence: `web/src/pages/Accept.tsx`)
- Route dispatcher → Privacy page: routes to (evidence: `web/src/App.tsx`)
- Route dispatcher → Terms page: routes to (evidence: `web/src/App.tsx`)
- Privacy page → Legal document renderer: renders document (evidence: `web/src/pages/Privacy.tsx`)
- Terms page → Legal document renderer: renders document (evidence: `web/src/pages/Terms.tsx`)
- Route dispatcher → Oura connection screen: routes to (evidence: `web/src/App.tsx`)
- Route dispatcher → Authorization welcome: routes to (evidence: `web/src/App.tsx`)
- Oura connection screen → OAuth API client: starts authorization (evidence: `web/src/pages/app/Connect.tsx`)
- OAuth API client → Oura Coach backend: requests auth URL (evidence: `web/src/lib/api.ts`)
- Oura connection screen → Oura authorization: redirects for authorization (evidence: `web/src/pages/app/Connect.tsx`)
