# Architecture ## Stack - **Backend:** ASP.NET (.NET 10), Minimal API - **Frontend:** Vanilla HTML/CSS/JS (SPA, kein Framework) - **Datenbank:** SQLite via Dapper (read) + better-sqlite3 (import) - **Port:** 18684 ## Komponenten ### Backend (`Program.cs`) Minimal API mit Endpunkten für Kosten-Analyse: - `GET /api/cost-buckets` - Zeitraum in N Buckets aggregiert - `GET /api/cost-entries` - Einzelne Einträge mit Kosten - `GET /api/cost-chains` - Konversations-Ketten nach Kosten sortiert - `GET /api/cost-summary` - Gesamtkosten für Zeitraum - `GET /api/entry-chain/{id}` - Volle Kette eines Eintrags (parentId vor/zurück) - `GET /api/entry-chains` - Einträge mit chainId-Zuordnung - `POST /api/sync` - Triggert JSONL-Import via `export.mjs` DB-Zugriff über Dapper + `Microsoft.Data.Sqlite`. Connection per Request via Factory. ### JSONL Sync (`jsonl-sync/export.mjs`) Node.js Script das OpenClaw Session-JSONL-Files in SQLite importiert: 1. Liest alle `.jsonl` aus `/home/node/.openclaw/agents/main/sessions/` 2. Parsed Einträge, speichert in `entries` Tabelle 3. Berechnet `chainId` durch parentId-Walk bis zum nächsten User-Message 4. Inkrementell - merkt sich pro File die letzte verarbeitete Zeile ### Frontend (`wwwroot/`) SPA mit Zoom-Navigation durch Zeiträume: - **Bucket-View:** Balkendiagramm mit klickbarem Drill-Down (Monat → Woche → Tag → Stunden) - **Entry-View:** Einzelne API-Calls als Balken, farblich nach Konversations-Kette - **Chain-Blocks:** Teuerste Konversationen als klickbare Blöcke - **Modal:** Konversations-Kontext mit User/Assistant Messages - State wird im URL-Hash gespeichert ## Datenfluss ``` OpenClaw JSONL Files → export.mjs → SQLite (sessions.db) → .NET API → Frontend ``` ## Deployment ```bash ./deploy.sh ``` Baut Release, kopiert nach `publish/`, restartet den `token-analytics` systemd Service auf stein2.