The Express application serves the SPA, JSON data routes and POST /api/chat.
The complete route and response contract is in API Reference.
Developer instructions live in server/AGENTS.md.
| Source | Responsibility |
|---|---|
| index.js | Route registration, auth, probes, cache, warmer and shutdown |
| http.js | parseRange, parseIntervalHours, parseFilters and configuration validation |
| queries.js | SQL builders and endpoint queries |
| clickhouse.js | JSON queries, time conversion, ping and readonly-session probe |
| queryContext.js | Shared-load deadline and query cancellation ownership |
| pricing.js | Computed cost diagnostics and token-tier estimates |
| priceCatalog.js | Merged rate view (operator overrides, AWS Price List runtime/snapshot layers, code tables), background refresh and /api/config pricing.priceList |
| awsPriceList.js | pricing:GetProducts fetch and parser; npm run prices:snapshot writes awsPriceSnapshot.json |
| costEfficiency.js | Reported-cost efficiency ratios, retaining computed diagnostics |
| productivity.js | Activity heuristic added to leaderboard rows |
| chat.js | SSE assistant and SQL tool loop; see chat reference |
route() registers GET data handlers. It validates range and interval before cache lookup,
then passes parsed filters to the handler. Validation failures return 400; capacity
exhaustion returns 503 with Retry-After: 1; other failures return 500 with an opaque
error ID. A shared query-load deadline returns 504 with code: query_timeout,
an opaque error ID and Retry-After: 5. A warning logs only that ID, the registered
route and the timeout code; it excludes submitted filters and SQL.
Config, health and chat handlers bypass this wrapper.
ADR-020 records the shared
deadline and reader-profile decision, including repeated expensive-view timeouts.
The process-local cache deduplicates pending work until settlement and stores successful
results for 320 seconds from completion. Successful-result TTL and byte eviction do not
remove pending entries; producer deadlines below can reject pending work.
Keys contain the route path and sorted parameters. Ordinary routes use from, to,
group, user, model, project, team, intervalHours, email and includeUnknown.
Client overview and Codex insights instead use range bounds and validated client/backend/user/model/team
filters, including userExact/modelExact, and their applicable view, modelTime,
timeFormat or profile. Overview also keys the resolved bucket size, native query
source and effective range end. index.js's cacheKey()
owns this normalization. Failed promises are removed. The 2,000-entry
cap evicts settled entries by insertion order, not by last read. At most 64 distinct
cache loads execute concurrently. Up to 64 additional distinct keys wait FIFO without
starting their loaders or acquiring database slots. The cache queue's own wait limit
is 30 seconds. Existing-key requests share the same promise while waiting or executing.
A full queue returns the same coded 503; failed keys are removed.
Completion starts the successful-result TTL. Each new shared key also has a 25-second
cooperative deadline, starting before cache admission and covering its loader's DB
queue, sequential/parallel queries and result consumption together. It cancels queued
work and closes pending result bodies. Timeout results are removed, never cached as
empty/zero telemetry. An uncooperative loader remains accounted until it settles;
a timer does not free its slot while work is still active.
For data-route loads, the shared 25-second deadline expires before either queue's
30-second wait limit and returns 504. Cache/DB queues used without that deadline
retain their own 30-second expiration and coded 503 behavior.
The deadline belongs to the shared key, not one HTTP subscriber. Factor lookups retain separate ownership: an expired caller leaves, while another subscriber's request stays alive; the last cancellation aborts the lookup. Standalone DB helpers retain their independent limits below. This is not a transport, response-encoding/delivery or end-to-end fleet deadline. Synchronous work can delay cancellation; expiration checks reject late loader/serialization results but do not preempt JavaScript. Settled entries have a 16 MiB serialized-JSON byte quota and a 1 MiB per-entry quota. Oversized results are returned intact but not cached; byte eviction never removes pending work. Serialized size is an estimate for cache admission, not a heap/response-allocation bound.
capacity.js bounds admitted /api requests at 200,
database queries at 24 (including result consumption), and chat turns at two per process.
Database bursts wait FIFO in a bounded 128-query queue for at most 30 seconds; only a
full/expired queue rejects work. Normal query execution retains the client 30-second timeout
after admission, with a data-route shared deadline taking precedence if it expires first.
Readonly SQL's 30-second abort covers queue and execution together;
disconnect/deadline also cancels queued readonly work. These are cooperative limits.
Ordinary and readonly helpers explicitly close result bodies on abort after headers,
preserving the originating cancellation reason. dashboard.tf
declares CH_USER=otel_reader for the shared SDK; local Compose instead uses default.
The declared otel_reader profile enables
cancel_http_readonly_queries_on_client_close and retains its 60-second execution,
memory/result/read ceilings as backstops. Older installations may still disable that
setting; inspect getSetting(...) in the actual dashboard session using the
reader reconciliation procedure.
HTTP cancellation alone does not establish server-side
termination. Cancellation and execution checks are cooperative, so a client slot can be
released before server work stops; neither setting certifies fleet capacity or a hard deadline.
Overload JSON has code: capacity_exhausted and a localized retry message.
HTTP admission follows authentication and releases on response finish/close; work budgets
release on settlement. Probes and OIDC protocol routes remain outside HTTP admission;
ping has a separate four-call budget. Busy/failed ping keeps liveness HTTP 200 with
ok: false and makes readiness 503; it must not restart the process. The ClickHouse
connection pool remains 30.
These bounds do not reserve sockets, measure latency or establish a fleet SLO.
Large immutable data-route values share serialized bytes and one gzip operation among active responses. Representations are released after the last response finishes/closes and any compression settles; no settled encoding cache or copied source is retained. JSON policy/Express application changes do not share old bytes. Custom replacers/boxed spacing retain per-response evaluation. Content negotiation, JSON escaping, null/zero/tiny values, auth, status and private cache headers remain. This reduces duplicate response work, not the size of data received by each client or an absolute heap/socket bound.
Chat limits admit ten requests per IP/minute, storing at most 4,096 live keys and ten timestamps per key. Denied attempts do not extend the admitted-hit window. A full key map rejects new keys until expired entries can be removed; live limits are never evicted. Concurrent chat overload is checked before consuming an IP rate slot. Limits/cache are independent in each replica: they are neither a fleet-wide quota nor a billing bound. Shared proxy/NAT addresses can exhaust the IP limit. The existing chat limits and DB timeout/readonly gates still apply.
The warmer runs at startup and on 120-second boundaries, in batches of three with two-second
gaps. The warming plan prioritizes shared full and
cost/model-time profiles. Legacy views join only after recent authenticated, unfiltered
default-window demand. It requests DEFAULT_RANGE_DAYS with hourly resolution through
two days, otherwise daily. User drilldowns, snapshots and beta trace handlers do not warm.
Warming is per process and best effort; it does not guarantee a cache hit for every
range, filter or replica. See query performance.
JSON API responses use Cache-Control: no-store. The successful chat SSE handler overrides
this with no-cache. Keep frontend quantization in useApi.js
consistent with the server constants.
Filters are applied only where each query supplies a corresponding expression to
filterCond(). Model matching can be row-level, mixed metric matching, or a session
semi-join; these have different populations. Project matching covers four Usage endpoints
and requires the project-column gate. Team matching is a session semi-join from otel_logs
team evidence; routes that cannot apply it reject it with 400 unsupported filter.
See the filter contract.
incFlat and incBucketed handle shared counter aggregation. Queries needing additional
dimensions such as effort, agent, language, version or project use local raw-table
aggregations. Do not widen the shared grouping merely to simplify one endpoint:
ADR-001 explains the tradeoff.
See data for raw/rollup selection and remaining time-boundary approximations.
Keep API fields unchanged when choosing display spend. The frontend adapts reported_cost
through spend.js; server cost and summary computed_cost retain their diagnostic meaning.
Only the efficiency endpoint's cost_per_loc and cost_per_commit use reported cost.