Network¶
Connectivity, latency expectations, and protocol notes for the platform.
Latency budget (in-cluster)¶
| Hop | Target p95 | Notes |
|---|---|---|
| API → Postgres | ≤ 5 ms | Same VPC; PgBouncer optional. Slow queries handled with EF query plan analysis, not by extending the budget. |
| API → ClickHouse | ≤ 10 ms | HTTP 8123 within cluster. |
| API → OpenFGA | ≤ 20 ms | Use BatchCheck for list endpoints; per-row Check blows the budget. |
| API → Kafka produce | ≤ 30 ms | acks=all + idempotent producer. |
| Worker → Kafka consume | n/a | Throughput-bound, not latency. |
| Worker → ClickHouse insert | ≤ 100 ms / batch | Bulk inserts of 1k–5k rows. |
| Worker → Valhalla | ≤ 1 s | Map-matching can spike for long tracks. |
| Worker → Frame Attribute API | ≤ 200 ms | External; budget includes network egress. |
Latency budget (external)¶
| Hop | Target | Notes |
|---|---|---|
| Mobile → Ingress | ≤ 200 ms (good signal) | gRPC over HTTP/2; mobile networks can be much worse. App is offline-tolerant. |
| Mobile → S3 (presigned PUT) | ≤ 5 s per frame | Direct to provider; tested on 4G. |
| Browser → Ingress | ≤ 100 ms | UI interactions ≤ 300 ms p95 with one DB round-trip in the path. |
| Browser → S3 (PMTiles range read) | ≤ 200 ms | First range read includes index; subsequent are cached client-side. |
Throughput targets¶
| Topic / path | Steady | Peak |
|---|---|---|
axion.sense.track.metadata (frames + matching req/result) |
TBD msg/s | TBD msg/s |
recognition_requests (Sense → Vision Worker) |
matches frame rate | same |
vision_frames_lifecycle (Vision internal: quality, dispatch, results, location) |
≥ 2× frame rate (multi-hop per frame) | same |
clusterization_requests (Vision Clusterization → itself, H3 res-2 keyed) |
matches frame rate | same |
axion.sense.audit.events |
TBD | high during bulk admin actions |
axion.sense.citylens.* |
TBD | high during initial migration |
| Mobile → S3 (frame uploads, parallel) | several inspectors × frames/sec | hundreds (city-wide coverage day) |
The Worker is sized to absorb peak consumption with consumer lag returning to zero within 5 minutes.
Protocol details¶
Mobile → Sense API¶
- gRPC over HTTP/2. Streaming and unary; we use unary throughout currently.
- TLS 1.2 minimum (1.3 preferred).
- Bearer token (OIDC JWT) per request; refresh handled by mobile.
Browser → Sense API / Gen API¶
- REST over HTTP/1.1 (HTTP/2 if the ingress + browser negotiate).
- Bearer token in
Authorizationheader (Sense). HttpOnly session cookie (Gen, BFF pattern). - CORS allowed origins limited to web app hostnames.
Browser → S3¶
- Direct, presigned URL.
- CORS configured on the bucket —
GETandHEADfrom the web origin, withRangeheader allowed (for PMTiles).
Mobile → S3¶
- Direct, presigned URL.
- CORS allowed (mobile WebViews care; native HTTP clients don't, but configure for safety).
Service-to-service (in-cluster)¶
- HTTP/1.1 to Postgres (Npgsql), ClickHouse (HTTP 8123), Valhalla, Frame Attribute API.
- gRPC to OpenFGA.
- Kafka native protocol to Kafka.
Egress¶
The platform makes outbound calls to:
- OIDC IdP (token validation, JWKS fetch) — typically a few requests per service start, then cached.
- External ML system — only via Kafka; no direct HTTP egress.
- Citylens — Postgres connection (initial migration only); Kafka subscription (realtime).
- Frame Attribute API — HTTP per frame, when configured.
- 2GIS MapGL — direct from the browser.
- Langfuse — from Gen Web's Next.js BFF only (server-side).
In on-prem deployments, configure egress rules accordingly — most of these except Citylens and Frame Attribute API can be disabled.
Ingress requirements¶
- HTTP/2 support at the ingress for gRPC.
- Server-Sent Events (SSE) unbuffered for the AI agent stream (
/api/agent/stream). - Range request support for PMTiles (handled by S3 + presigned URLs; ingress isn't in that path).
- Body size: keep
client-max-body-sizemodest (1–8 MiB). Frame uploads bypass the ingress.
What's never on the wire¶
- Frame bytes through the API.
- Plaintext OIDC tokens through Gen Web (BFF cookies only).
- Plaintext data-source credentials (always AES-256-GCM encrypted at rest in the Gen DB).
- Raw user PII in span attributes or log lines (deliberate scrubbing).