# artsen/site-ledger architecture

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

- Interactive diagram: https://gitdiagram.com/artsen/site-ledger
- Repository: https://github.com/artsen/site-ledger

## Overview

Site Ledger is a local-first website intelligence application that builds a durable, evidence-backed history of Sites and Pages. Users add Sites and discovery Sources, initiate bounded Scans, then inspect persistent Page observations and independently collected browser, performance, accessibility, and structured-content evidence. They can compare Scans, review deterministic Findings and Site Intelligence, and organize Page work. The graph follows documented capabilities and sampled app wiring; several feature-specific routes and service internals were not sampled, so their detailed call relationships are intentionally omitted.

Main entry points: [`backend/app/database.py`](https://github.com/artsen/site-ledger/blob/main/backend/app/database.py) (Application database), [`backend/app/services/job_handlers.py`](https://github.com/artsen/site-ledger/blob/main/backend/app/services/job_handlers.py) (Job handlers), [`backend/app/services/scan_execution.py`](https://github.com/artsen/site-ledger/blob/main/backend/app/services/scan_execution.py) (Scan execution), [`backend/app/main.py`](https://github.com/artsen/site-ledger/blob/main/backend/app/main.py) (FastAPI application)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interface["User interface"]
  node_frontend["Web application<br/>[main.tsx]"]
end

subgraph group_collection["Collection and jobs"]
  node_api["FastAPI application<br/>[main.py]"]
  node_routes["Core API routes<br/>[routes.py]"]
  node_render_routes["Render API<br/>[render_routes.py]"]
  node_scan["Scan execution<br/>[scan_execution.py]"]
  node_crawler["Static crawler<br/>[static_crawler.py]"]
  node_sources["URL Sources"]
  node_worker["Background worker<br/>[worker.py]"]
  node_handlers["Job handlers<br/>[job_handlers.py]"]
end

subgraph group_evidence["Evidence and analysis"]
  node_pages["Persistent Pages<br/>[site_pages.py]"]
  node_render["Browser evidence<br/>[render_runs.py]"]
  node_performance["Performance evidence"]
  node_accessibility["Accessibility audits<br/>[engine.py]"]
  node_structured["Structured content"]
  node_ai_docs["AI document evidence<br/>[ai_documents.py]"]
  node_comparisons["Scan comparisons"]
  node_findings["Deterministic Findings<br/>[findings.py]"]
  node_intelligence["Site Intelligence"]
end

subgraph group_state["Persistence"]
  node_db[("Application database<br/>[database.py]")]
  node_content_store[("HTML content store<br/>[content_store.py]")]
  node_artifact_store[("Render artifact store<br/>[artifact_store.py]")]
end

node_user(("Site operator"))
node_website(("Target website"))

node_user -->|"uses"| node_frontend
node_frontend -->|"requests data"| node_api
node_api -->|"mounts"| node_routes
node_api -->|"mounts"| node_render_routes
node_routes -->|"reads and writes"| node_db
node_routes -->|"manages Sources"| node_sources
node_render_routes -->|"reads and writes"| node_db
node_render_routes -->|"enqueues rerender"| node_worker
node_worker -->|"claims jobs"| node_db
node_worker -->|"dispatches jobs"| node_handlers
node_handlers -->|"executes scans"| node_scan
node_scan -->|"collects pages"| node_crawler
node_crawler -->|"fetches pages"| node_website
node_scan -->|"records observations"| node_pages
node_scan -->|"retains HTML"| node_content_store
node_handlers -->|"runs captures"| node_render
node_render -->|"stores artifacts"| node_artifact_store
node_handlers -.->|"collects measurements"| node_performance
node_handlers -.->|"runs audits"| node_accessibility
node_handlers -.->|"prepares content"| node_structured
node_sources -->|"persists provenance"| node_db
node_pages -->|"persists identities"| node_db
node_comparisons -->|"reads scan history"| node_db
node_findings -->|"reads evidence"| node_db
node_intelligence -->|"reads site activity"| node_db
node_ai_docs -->|"retains snapshots"| node_db

click node_frontend "https://github.com/artsen/site-ledger/blob/main/frontend/src/main.tsx"
click node_api "https://github.com/artsen/site-ledger/blob/main/backend/app/main.py"
click node_routes "https://github.com/artsen/site-ledger/blob/main/backend/app/api/routes.py"
click node_render_routes "https://github.com/artsen/site-ledger/blob/main/backend/app/api/render_routes.py"
click node_scan "https://github.com/artsen/site-ledger/blob/main/backend/app/services/scan_execution.py"
click node_crawler "https://github.com/artsen/site-ledger/blob/main/backend/app/crawler/static_crawler.py"
click node_sources "https://github.com/artsen/site-ledger/blob/main/backend/app/services/source_management.py"
click node_worker "https://github.com/artsen/site-ledger/blob/main/backend/app/worker.py"
click node_handlers "https://github.com/artsen/site-ledger/blob/main/backend/app/services/job_handlers.py"
click node_pages "https://github.com/artsen/site-ledger/blob/main/backend/app/services/site_pages.py"
click node_render "https://github.com/artsen/site-ledger/blob/main/backend/app/services/render_runs.py"
click node_performance "https://github.com/artsen/site-ledger/blob/main/backend/app/services/performance_collection.py"
click node_accessibility "https://github.com/artsen/site-ledger/blob/main/backend/app/accessibility/engine.py"
click node_structured "https://github.com/artsen/site-ledger/blob/main/backend/app/services/structured_content.py"
click node_ai_docs "https://github.com/artsen/site-ledger/blob/main/backend/app/parsers/ai_documents.py"
click node_comparisons "https://github.com/artsen/site-ledger/blob/main/backend/app/services/scan_comparisons.py"
click node_findings "https://github.com/artsen/site-ledger/blob/main/backend/app/services/findings.py"
click node_intelligence "https://github.com/artsen/site-ledger/blob/main/backend/app/services/site_intelligence.py"
click node_db "https://github.com/artsen/site-ledger/blob/main/backend/app/database.py"
click node_content_store "https://github.com/artsen/site-ledger/blob/main/backend/app/storage/content_store.py"
click node_artifact_store "https://github.com/artsen/site-ledger/blob/main/backend/app/storage/artifact_store.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_frontend toneBlue
class node_api,node_routes,node_render_routes,node_scan,node_crawler,node_sources,node_worker,node_handlers toneAmber
class node_pages,node_render,node_performance,node_accessibility,node_structured,node_ai_docs,node_comparisons,node_findings,node_intelligence toneMint
class node_db,node_content_store,node_artifact_store toneRose
class node_user,node_website toneIndigo
```

## Components

### User interface

- [Web application](https://github.com/artsen/site-ledger/blob/main/frontend/src/main.tsx): `frontend/src/main.tsx`

### Collection and jobs

- [FastAPI application](https://github.com/artsen/site-ledger/blob/main/backend/app/main.py): `backend/app/main.py`
- [Core API routes](https://github.com/artsen/site-ledger/blob/main/backend/app/api/routes.py): `backend/app/api/routes.py`
- [Render API](https://github.com/artsen/site-ledger/blob/main/backend/app/api/render_routes.py): `backend/app/api/render_routes.py`
- [Scan execution](https://github.com/artsen/site-ledger/blob/main/backend/app/services/scan_execution.py): `backend/app/services/scan_execution.py`
- [Static crawler](https://github.com/artsen/site-ledger/blob/main/backend/app/crawler/static_crawler.py): `backend/app/crawler/static_crawler.py`
- [URL Sources](https://github.com/artsen/site-ledger/blob/main/backend/app/services/source_management.py): `backend/app/services/source_management.py`
- [Background worker](https://github.com/artsen/site-ledger/blob/main/backend/app/worker.py): `backend/app/worker.py`
- [Job handlers](https://github.com/artsen/site-ledger/blob/main/backend/app/services/job_handlers.py): `backend/app/services/job_handlers.py`

### Evidence and analysis

- [Persistent Pages](https://github.com/artsen/site-ledger/blob/main/backend/app/services/site_pages.py): `backend/app/services/site_pages.py`
- [Browser evidence](https://github.com/artsen/site-ledger/blob/main/backend/app/services/render_runs.py): `backend/app/services/render_runs.py`
- [Performance evidence](https://github.com/artsen/site-ledger/blob/main/backend/app/services/performance_collection.py): `backend/app/services/performance_collection.py`
- [Accessibility audits](https://github.com/artsen/site-ledger/blob/main/backend/app/accessibility/engine.py): `backend/app/accessibility/engine.py`
- [Structured content](https://github.com/artsen/site-ledger/blob/main/backend/app/services/structured_content.py): `backend/app/services/structured_content.py`
- [AI document evidence](https://github.com/artsen/site-ledger/blob/main/backend/app/parsers/ai_documents.py): `backend/app/parsers/ai_documents.py`
- [Scan comparisons](https://github.com/artsen/site-ledger/blob/main/backend/app/services/scan_comparisons.py): `backend/app/services/scan_comparisons.py`
- [Deterministic Findings](https://github.com/artsen/site-ledger/blob/main/backend/app/services/findings.py): `backend/app/services/findings.py`
- [Site Intelligence](https://github.com/artsen/site-ledger/blob/main/backend/app/services/site_intelligence.py): `backend/app/services/site_intelligence.py`

### Persistence

- [Application database](https://github.com/artsen/site-ledger/blob/main/backend/app/database.py): `backend/app/database.py`
- [HTML content store](https://github.com/artsen/site-ledger/blob/main/backend/app/storage/content_store.py): `backend/app/storage/content_store.py`
- [Render artifact store](https://github.com/artsen/site-ledger/blob/main/backend/app/storage/artifact_store.py): `backend/app/storage/artifact_store.py`

### Other components

- **Site operator**
- **Target website**

## Connections

- Site operator → Web application: uses
- Web application → FastAPI application: requests data
- FastAPI application → Core API routes: mounts
- FastAPI application → Render API: mounts
- Core API routes → Application database: reads and writes
- Core API routes → URL Sources: manages Sources
- Render API → Application database: reads and writes
- Render API → Background worker: enqueues rerender
- Background worker → Application database: claims jobs
- Background worker → Job handlers: dispatches jobs
- Job handlers → Scan execution: executes scans
- Scan execution → Static crawler: collects pages
- Static crawler → Target website: fetches pages
- Scan execution → Persistent Pages: records observations
- Scan execution → HTML content store: retains HTML
- Job handlers → Browser evidence: runs captures
- Browser evidence → Render artifact store: stores artifacts
- Job handlers → Performance evidence: collects measurements
- Job handlers → Accessibility audits: runs audits
- Job handlers → Structured content: prepares content
- URL Sources → Application database: persists provenance
- Persistent Pages → Application database: persists identities
- Scan comparisons → Application database: reads scan history
- Deterministic Findings → Application database: reads evidence
- Site Intelligence → Application database: reads site activity
- AI document evidence → Application database: retains snapshots
