# antonbsa/twitch-radar architecture

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

- Interactive diagram: https://gitdiagram.com/antonbsa/twitch-radar
- Repository: https://github.com/antonbsa/twitch-radar

## Overview

Twitch Radar is a mobile-first PWA for receiving alerts when followed Twitch broadcasters switch into selected categories. A viewer signs in, chooses followed channels and category preferences, and registers a push endpoint; the API synchronizes Twitch data and EventSub subscriptions, then processes verified stream events and delivers matching alerts. The graph also captures account/language settings and snoozes. Source excerpts establish the webhook queue handoff and browser push behavior; some service-to-service wiring is represented only where the repository structure or README supports it.

Main entry points: [`apps/api/src/db/schema.ts`](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/db/schema.ts) (D1 database), [`apps/api/src/index.ts`](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/index.ts) (API worker), [`apps/web/src/lib/api.ts`](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/lib/api.ts) (API client), [`apps/web/public/service-worker.js`](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/public/service-worker.js) (Push worker)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["Viewer PWA"]
  node_app["PWA routes<br/>[App.tsx]"]
  node_webapi["API client<br/>[api.ts]"]
  node_channelsui["Channel settings<br/>[channels.tsx]"]
  node_alertsui["Alert settings<br/>[alerts.tsx]"]
  node_accountui["Account settings<br/>[account.tsx]"]
  node_sw["Push worker<br/>[service-worker.js]"]
end

subgraph group_api["API and identity"]
  node_apiworker["API worker<br/>[index.ts]"]
  node_authroutes["OAuth routes<br/>[auth.ts]"]
  node_session["Session service<br/>[session.ts]"]
  node_channelroutes["Channel routes<br/>[channels.ts]"]
  node_prefroutes["Preference routes<br/>[preferences.ts]"]
  node_pushroutes["Push routes"]
end

subgraph group_tracking["Stream tracking"]
  node_sync["Twitch sync<br/>[sync.ts]"]
  node_eventroutes["EventSub manager<br/>[reconcile.ts]"]
  node_webhooks["EventSub webhook<br/>[webhooks.ts]"]
  node_processor["Event processor<br/>[process.ts]"]
end

subgraph group_notify["Alert delivery"]
  node_matcher["Preference matcher<br/>[match.ts]"]
  node_delivery["Push delivery<br/>[deliver.ts]"]
  node_snooze["Snooze handling<br/>[snooze-sweep.ts]"]
end

subgraph group_state["Persistent state"]
  node_queue["Event queue"]
  node_d1[("D1 database<br/>[schema.ts]")]
  node_kv[("Cloudflare KV<br/>[session.ts]")]
end

node_viewer(("Viewer"))
node_twitch{{"Twitch"}}
node_pushservice{{"Web Push service"}}
node_browser(("Browser push"))

node_viewer -->|"uses"| node_app
node_app -->|"requests"| node_webapi
node_channelsui -->|"loads and saves"| node_webapi
node_alertsui -->|"loads and saves"| node_webapi
node_accountui -->|"manages account"| node_webapi
node_webapi -->|"HTTP requests"| node_apiworker
node_apiworker -->|"dispatches"| node_authroutes
node_apiworker -->|"dispatches"| node_channelroutes
node_apiworker -->|"dispatches"| node_prefroutes
node_apiworker -->|"dispatches"| node_pushroutes
node_authroutes -->|"OAuth requests"| node_twitch
node_authroutes -->|"creates sessions"| node_session
node_session -->|"reads and writes"| node_kv
node_channelroutes -->|"syncs follows"| node_sync
node_sync -->|"fetches Twitch data"| node_twitch
node_channelroutes -->|"reads and writes"| node_d1
node_prefroutes -->|"reads and writes"| node_d1
node_pushroutes -->|"stores subscriptions"| node_d1
node_pushroutes -->|"provides push setup"| node_sw
node_sync -->|"reconciles subscriptions"| node_eventroutes
node_eventroutes -->|"manages subscriptions"| node_twitch
node_twitch -->|"sends events"| node_webhooks
node_webhooks -->|"enqueues events"| node_queue
node_webhooks -->|"updates subscription state"| node_d1
node_queue -->|"dispatches events"| node_processor
node_processor -->|"checks and records events"| node_d1
node_processor -->|"matches changes"| node_matcher
node_matcher -->|"reads preferences"| node_d1
node_processor -->|"requests delivery"| node_delivery
node_delivery -->|"records deliveries"| node_d1
node_delivery -->|"sends notification"| node_pushservice
node_pushservice -->|"delivers push"| node_browser
node_browser -->|"dispatches push"| node_sw
node_sw -->|"shows alert"| node_viewer
node_viewer -->|"requests snooze"| node_sw
node_sw -->|"posts snooze"| node_webapi
node_apiworker -->|"dispatches snooze work"| node_snooze
node_snooze -->|"reads and writes"| node_d1

click node_app "https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/App.tsx"
click node_webapi "https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/lib/api.ts"
click node_channelsui "https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/routes/channels.tsx"
click node_alertsui "https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/routes/alerts.tsx"
click node_accountui "https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/routes/account.tsx"
click node_sw "https://github.com/antonbsa/twitch-radar/blob/main/apps/web/public/service-worker.js"
click node_apiworker "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/index.ts"
click node_authroutes "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/auth.ts"
click node_session "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/session.ts"
click node_channelroutes "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/channels.ts"
click node_prefroutes "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/preferences.ts"
click node_pushroutes "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/push-subscriptions.ts"
click node_sync "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/twitch/sync.ts"
click node_eventroutes "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/eventsub/reconcile.ts"
click node_webhooks "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/webhooks.ts"
click node_processor "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/eventsub/process.ts"
click node_matcher "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/notifications/match.ts"
click node_delivery "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/notifications/deliver.ts"
click node_snooze "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/notifications/snooze-sweep.ts"
click node_d1 "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/db/schema.ts"
click node_kv "https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/session.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_app,node_webapi,node_channelsui,node_alertsui,node_accountui,node_sw,node_viewer,node_browser toneBlue
class node_apiworker,node_authroutes,node_session,node_channelroutes,node_prefroutes,node_pushroutes toneAmber
class node_sync,node_eventroutes,node_webhooks,node_processor toneMint
class node_matcher,node_delivery,node_snooze toneRose
class node_queue,node_d1,node_kv,node_twitch,node_pushservice toneIndigo
```

## Components

### Viewer PWA

- [PWA routes](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/App.tsx): `apps/web/src/App.tsx`
- [API client](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/lib/api.ts): `apps/web/src/lib/api.ts`
- [Channel settings](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/routes/channels.tsx): `apps/web/src/routes/channels.tsx`
- [Alert settings](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/routes/alerts.tsx): `apps/web/src/routes/alerts.tsx`
- [Account settings](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/src/routes/account.tsx): `apps/web/src/routes/account.tsx`
- [Push worker](https://github.com/antonbsa/twitch-radar/blob/main/apps/web/public/service-worker.js): `apps/web/public/service-worker.js`

### API and identity

- [API worker](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/index.ts): `apps/api/src/index.ts`
- [OAuth routes](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/auth.ts): `apps/api/src/http/routes/auth.ts`
- [Session service](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/session.ts): `apps/api/src/services/session.ts`
- [Channel routes](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/channels.ts): `apps/api/src/http/routes/channels.ts`
- [Preference routes](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/preferences.ts): `apps/api/src/http/routes/preferences.ts`
- [Push routes](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/push-subscriptions.ts): `apps/api/src/http/routes/push-subscriptions.ts`

### Stream tracking

- [Twitch sync](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/twitch/sync.ts): `apps/api/src/services/twitch/sync.ts`
- [EventSub manager](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/eventsub/reconcile.ts): `apps/api/src/services/eventsub/reconcile.ts`
- [EventSub webhook](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/http/routes/webhooks.ts): `apps/api/src/http/routes/webhooks.ts`
- [Event processor](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/eventsub/process.ts): `apps/api/src/services/eventsub/process.ts`

### Alert delivery

- [Preference matcher](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/notifications/match.ts): `apps/api/src/services/notifications/match.ts`
- [Push delivery](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/notifications/deliver.ts): `apps/api/src/services/notifications/deliver.ts`
- [Snooze handling](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/notifications/snooze-sweep.ts): `apps/api/src/services/notifications/snooze-sweep.ts`

### Persistent state

- **Event queue**
- [D1 database](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/db/schema.ts): `apps/api/src/db/schema.ts`
- [Cloudflare KV](https://github.com/antonbsa/twitch-radar/blob/main/apps/api/src/services/session.ts): `apps/api/src/services/session.ts`

### Other components

- **Viewer**
- **Twitch**
- **Web Push service**
- **Browser push**

## Connections

- Viewer → PWA routes: uses
- PWA routes → API client: requests
- Channel settings → API client: loads and saves
- Alert settings → API client: loads and saves
- Account settings → API client: manages account
- API client → API worker: HTTP requests
- API worker → OAuth routes: dispatches
- API worker → Channel routes: dispatches
- API worker → Preference routes: dispatches
- API worker → Push routes: dispatches
- OAuth routes → Twitch: OAuth requests
- OAuth routes → Session service: creates sessions
- Session service → Cloudflare KV: reads and writes
- Channel routes → Twitch sync: syncs follows
- Twitch sync → Twitch: fetches Twitch data
- Channel routes → D1 database: reads and writes
- Preference routes → D1 database: reads and writes
- Push routes → D1 database: stores subscriptions
- Push routes → Push worker: provides push setup
- Twitch sync → EventSub manager: reconciles subscriptions
- EventSub manager → Twitch: manages subscriptions
- Twitch → EventSub webhook: sends events
- EventSub webhook → Event queue: enqueues events
- EventSub webhook → D1 database: updates subscription state
- Event queue → Event processor: dispatches events
- Event processor → D1 database: checks and records events
- Event processor → Preference matcher: matches changes
- Preference matcher → D1 database: reads preferences
- Event processor → Push delivery: requests delivery
- Push delivery → D1 database: records deliveries
- Push delivery → Web Push service: sends notification
- Web Push service → Browser push: delivers push
- Browser push → Push worker: dispatches push
- Push worker → Viewer: shows alert
- Viewer → Push worker: requests snooze
- Push worker → API client: posts snooze
- API worker → Snooze handling: dispatches snooze work
- Snooze handling → D1 database: reads and writes
