Architecture
Two SQLite connections, both read-only. Process map, data boundaries and the two deliberate source-backed routes.
One scanner writes the cache. One server reads it. The source database is never in a writable state anywhere in the process tree.
Canonical source ↗Processes
| Process | Entry | Role |
|---|---|---|
| Scanner | bun src/scan.ts | Reads source RO; writes and reconciles the cache |
| API | bun run serve | Serves JSON from the cache, plus two source-backed routes |
| UI | bun run web | Dashboard; proxies /api in development |
Data boundaries
| Store | Env | Writer | Reader |
|---|---|---|---|
| OpenCode sessions | OPENCODE_DB | OpenCode only | scan + transcript/live |
| Derived metrics | OPENCODEVIEW_CACHE | scan.ts only | API (read-only) |
Why two routes still touch the source
Most endpoints read the cache and nothing else. Two are deliberate exceptions, because materializing them would mean duplicating raw message text into a second file — a worse privacy trade than reading it live.
GET /api/session/:id/transcriptMessage and part text is intentionally not fully materialized into the cache.
GET /api/liveIn-progress session state only exists in the source at request time.
✓ Both remain read-only and redacted.
Code map
| Path | Responsibility |
|---|---|
| src/scan.ts | Project and session rollups, flags, tool metrics, cache schema |
| src/server.ts | Hono routes, bind and auth guards, query_only connections |
| src/server-config.ts | Host, port and token fail-closed rules |
| src/redaction.ts | Secret and path scrubbing for outbound payloads |
| src/stats.ts | Shared numeric helpers — EWMA, changepoint detection |
| web/src/App.tsx | Shell, locale, lazy view boundaries |
| web/src/lib/api/ | Typed clients for every /api/* route |
| web/src/i18n/ | EN-US and PT-BR message catalogs |