# michelebellitti/loop architecture

> Architecture diagram of the GitHub repository michelebellitti/loop, 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/michelebellitti/loop
- Repository: https://github.com/michelebellitti/loop
- Video tour (about a minute): https://gitdiagram.com/michelebellitti/loop/video

## Overview

Loop is an email-first job application tracker: it reads mailbox signals, classifies and resolves them into applications, derives pipeline state, and asks the user to review uncertain cases. The user signs in, connects a mailbox or manually adds an application, then views the derived pipeline and can correct or review it. The README documents chat, statistics, nudges, push, and calendar signals as additional product capabilities. Some service wiring is documented only at a high level, so uncertain call relationships are omitted.

Main entry points: [`backend/loop/db/pool.py`](https://github.com/michelebellitti/loop/blob/main/backend/loop/db/pool.py) (Application database), [`backend/loop/api/app.py`](https://github.com/michelebellitti/loop/blob/main/backend/loop/api/app.py) (HTTP API), [`backend/loop/api/routes/applications.py`](https://github.com/michelebellitti/loop/blob/main/backend/loop/api/routes/applications.py) (Application routes), [`frontend/src/api.ts`](https://github.com/michelebellitti/loop/blob/main/frontend/src/api.ts) (API client)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["PWA"]
  node_app["App shell<br/>[App.tsx]"]
  node_pipeline_view["Pipeline view<br/>[Pipeline.tsx]"]
  node_review_view["Review queue<br/>[ReviewQueue.tsx]"]
  node_api_client["API client<br/>[api.ts]"]
end

subgraph group_gateway["API"]
  node_api_app["HTTP API<br/>[app.py]"]
  node_auth["Sessions and auth<br/>[auth.py]"]
  node_application_routes["Application routes<br/>[applications.py]"]
  node_review_routes["Review routes<br/>[review.py]"]
  node_chat["Assistant chat<br/>[agent.py]"]
end

subgraph group_ingest["Mailbox ingestion"]
  node_google["Google mailbox client<br/>[client.py]"]
  node_mailbox_service["Mailbox connector service<br/>[connector.py]"]
  node_normalise["Message normalisation<br/>[normalise.py]"]
  node_calendar["Calendar signals<br/>[mailbox.py]"]
end

subgraph group_interpret["Signal processing"]
  node_extract["Signal extraction<br/>[extractor.py]"]
  node_classifier["Ladder classifier<br/>[classifier.py]"]
  node_resolver["Application resolution<br/>[resolver.py]"]
  node_domain["Stages and activity<br/>[stages.py]"]
end

subgraph group_state["Application state"]
  node_pipeline["Event pipeline<br/>[pipeline.py]"]
  node_queue["Work queue<br/>[queue.py]"]
  node_db[("Application database<br/>[pool.py]")]
  node_nudge["Nudges and notifications<br/>[nudge.py]"]
  node_push["Web push<br/>[push.py]"]
end

node_user(("User"))
node_mail_service["Mail provider"]
node_browser(("Browser user"))

node_user -->|"uses"| node_app
node_app -->|"requests"| node_api_client
node_api_client -->|"HTTP calls"| node_api_app
node_api_app -->|"gates requests"| node_auth
node_api_app -->|"dispatches"| node_application_routes
node_api_app -->|"dispatches"| node_review_routes
node_application_routes -->|"reads and writes"| node_db
node_review_routes -->|"reads and writes"| node_db
node_pipeline_view -->|"fetches board"| node_api_client
node_review_view -->|"fetches and answers"| node_api_client
node_mailbox_service -->|"reads mailbox"| node_google
node_google -->|"OAuth and Gmail API"| node_mail_service
node_mailbox_service -->|"normalises messages"| node_normalise
node_calendar -->|"reads calendar parts"| node_google
node_extract -->|"classifies signals"| node_classifier
node_resolver -->|"uses classification"| node_classifier
node_pipeline -->|"consumes events"| node_queue
node_pipeline -->|"appends and projects"| node_db
node_application_routes -->|"publishes manual events"| node_queue
node_review_routes -->|"publishes corrections"| node_queue
node_application_routes -->|"derives display state"| node_domain
node_chat -.->|"uses application context"| node_db
node_nudge -->|"reads application state"| node_db
node_nudge -.->|"dispatches notifications"| node_push
node_push -.->|"pushes alert"| node_browser

click node_app "https://github.com/michelebellitti/loop/blob/main/frontend/src/App.tsx"
click node_pipeline_view "https://github.com/michelebellitti/loop/blob/main/frontend/src/mobile/Pipeline.tsx"
click node_review_view "https://github.com/michelebellitti/loop/blob/main/frontend/src/sheets/ReviewQueue.tsx"
click node_api_client "https://github.com/michelebellitti/loop/blob/main/frontend/src/api.ts"
click node_api_app "https://github.com/michelebellitti/loop/blob/main/backend/loop/api/app.py"
click node_auth "https://github.com/michelebellitti/loop/blob/main/backend/loop/api/auth.py"
click node_application_routes "https://github.com/michelebellitti/loop/blob/main/backend/loop/api/routes/applications.py"
click node_review_routes "https://github.com/michelebellitti/loop/blob/main/backend/loop/api/routes/review.py"
click node_google "https://github.com/michelebellitti/loop/blob/main/backend/loop/google/client.py"
click node_mailbox_service "https://github.com/michelebellitti/loop/blob/main/backend/loop/services/connector.py"
click node_normalise "https://github.com/michelebellitti/loop/blob/main/backend/loop/connector/normalise.py"
click node_extract "https://github.com/michelebellitti/loop/blob/main/backend/loop/services/extractor.py"
click node_classifier "https://github.com/michelebellitti/loop/blob/main/backend/loop/ladder/classifier.py"
click node_resolver "https://github.com/michelebellitti/loop/blob/main/backend/loop/services/resolver.py"
click node_domain "https://github.com/michelebellitti/loop/blob/main/backend/loop/domain/stages.py"
click node_pipeline "https://github.com/michelebellitti/loop/blob/main/backend/loop/services/pipeline.py"
click node_queue "https://github.com/michelebellitti/loop/blob/main/backend/loop/db/queue.py"
click node_db "https://github.com/michelebellitti/loop/blob/main/backend/loop/db/pool.py"
click node_chat "https://github.com/michelebellitti/loop/blob/main/backend/loop/chat/agent.py"
click node_nudge "https://github.com/michelebellitti/loop/blob/main/backend/loop/services/nudge.py"
click node_push "https://github.com/michelebellitti/loop/blob/main/backend/loop/services/push.py"
click node_calendar "https://github.com/michelebellitti/loop/blob/main/backend/loop/google/mailbox.py"

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_pipeline_view,node_review_view,node_api_client,node_user,node_browser toneBlue
class node_api_app,node_auth,node_application_routes,node_review_routes,node_chat toneAmber
class node_google,node_mailbox_service,node_normalise,node_calendar toneMint
class node_extract,node_classifier,node_resolver,node_domain toneRose
class node_pipeline,node_queue,node_db,node_nudge,node_push,node_mail_service toneIndigo
```

## Components

### PWA

- [App shell](https://github.com/michelebellitti/loop/blob/main/frontend/src/App.tsx): `frontend/src/App.tsx`
- [Pipeline view](https://github.com/michelebellitti/loop/blob/main/frontend/src/mobile/Pipeline.tsx): `frontend/src/mobile/Pipeline.tsx`
- [Review queue](https://github.com/michelebellitti/loop/blob/main/frontend/src/sheets/ReviewQueue.tsx): `frontend/src/sheets/ReviewQueue.tsx`
- [API client](https://github.com/michelebellitti/loop/blob/main/frontend/src/api.ts): `frontend/src/api.ts`

### API

- [HTTP API](https://github.com/michelebellitti/loop/blob/main/backend/loop/api/app.py): `backend/loop/api/app.py`
- [Sessions and auth](https://github.com/michelebellitti/loop/blob/main/backend/loop/api/auth.py): `backend/loop/api/auth.py`
- [Application routes](https://github.com/michelebellitti/loop/blob/main/backend/loop/api/routes/applications.py): `backend/loop/api/routes/applications.py`
- [Review routes](https://github.com/michelebellitti/loop/blob/main/backend/loop/api/routes/review.py): `backend/loop/api/routes/review.py`
- [Assistant chat](https://github.com/michelebellitti/loop/blob/main/backend/loop/chat/agent.py): `backend/loop/chat/agent.py`

### Mailbox ingestion

- [Google mailbox client](https://github.com/michelebellitti/loop/blob/main/backend/loop/google/client.py): `backend/loop/google/client.py`
- [Mailbox connector service](https://github.com/michelebellitti/loop/blob/main/backend/loop/services/connector.py): `backend/loop/services/connector.py`
- [Message normalisation](https://github.com/michelebellitti/loop/blob/main/backend/loop/connector/normalise.py): `backend/loop/connector/normalise.py`
- [Calendar signals](https://github.com/michelebellitti/loop/blob/main/backend/loop/google/mailbox.py): `backend/loop/google/mailbox.py`

### Signal processing

- [Signal extraction](https://github.com/michelebellitti/loop/blob/main/backend/loop/services/extractor.py): `backend/loop/services/extractor.py`
- [Ladder classifier](https://github.com/michelebellitti/loop/blob/main/backend/loop/ladder/classifier.py): `backend/loop/ladder/classifier.py`
- [Application resolution](https://github.com/michelebellitti/loop/blob/main/backend/loop/services/resolver.py): `backend/loop/services/resolver.py`
- [Stages and activity](https://github.com/michelebellitti/loop/blob/main/backend/loop/domain/stages.py): `backend/loop/domain/stages.py`

### Application state

- [Event pipeline](https://github.com/michelebellitti/loop/blob/main/backend/loop/services/pipeline.py): `backend/loop/services/pipeline.py`
- [Work queue](https://github.com/michelebellitti/loop/blob/main/backend/loop/db/queue.py): `backend/loop/db/queue.py`
- [Application database](https://github.com/michelebellitti/loop/blob/main/backend/loop/db/pool.py): `backend/loop/db/pool.py`
- [Nudges and notifications](https://github.com/michelebellitti/loop/blob/main/backend/loop/services/nudge.py): `backend/loop/services/nudge.py`
- [Web push](https://github.com/michelebellitti/loop/blob/main/backend/loop/services/push.py): `backend/loop/services/push.py`

### Other components

- **User**
- **Mail provider**
- **Browser user**

## Connections

- User → App shell: uses
- App shell → API client: requests
- API client → HTTP API: HTTP calls
- HTTP API → Sessions and auth: gates requests
- HTTP API → Application routes: dispatches
- HTTP API → Review routes: dispatches
- Application routes → Application database: reads and writes
- Review routes → Application database: reads and writes
- Pipeline view → API client: fetches board
- Review queue → API client: fetches and answers
- Mailbox connector service → Google mailbox client: reads mailbox
- Google mailbox client → Mail provider: OAuth and Gmail API
- Mailbox connector service → Message normalisation: normalises messages
- Calendar signals → Google mailbox client: reads calendar parts
- Signal extraction → Ladder classifier: classifies signals
- Application resolution → Ladder classifier: uses classification
- Event pipeline → Work queue: consumes events
- Event pipeline → Application database: appends and projects
- Application routes → Work queue: publishes manual events
- Review routes → Work queue: publishes corrections
- Application routes → Stages and activity: derives display state
- Assistant chat → Application database: uses application context
- Nudges and notifications → Application database: reads application state
- Nudges and notifications → Web push: dispatches notifications
- Web push → Browser user: pushes alert
