docs(decisions): ADR 0006 — router serves shell, Cell provides APIs

This commit is contained in:
2026-05-09 12:25:44 +00:00
parent 4c10c0f7f2
commit 41e272949f
+49
View File
@@ -0,0 +1,49 @@
# ADR-0006 · Router serves console shell, Cell provides APIs
**Status**: accepted
**Date**: 2026-05
## Context
The operator console is a SPA that needs:
- A stable, well-known URL (`http://blocao-router.local/`).
- Access to APIs from both the router (network config) and the Cell (Frigate, forensic engine).
- TLS termination.
- Auth.
Options:
1. SPA hosted on the Cell, router redirects.
2. SPA hosted on the router, Cell exposes APIs cross-origin.
3. SPA hosted on the router, router reverse-proxies to Cell APIs.
## Decision
**Option 3**. The router always serves the SPA shell at `http://blocao-router.local/` (or HTTPS once cert is set up). The Cell provides APIs only — never a UI directly.
The router reverse-proxies API calls based on path:
- `/api/router/*` → local `ubus` over `/ubus`
- `/api/cell/*` → discovered Cell IP/port
- `/api/cell/<cell-id>/*` → specific Cell when multi-Cell
The browser only ever talks to the router. CORS never appears.
## Consequences
**Good**:
- Single origin, no CORS complications.
- Cell can be unreachable temporarily without breaking the router-side parts of the UI.
- Router is the natural single point of auth.
- Cell discovery is a router responsibility, transparent to the UI.
**Bad / trade-offs**:
- Router has to do reverse-proxy work; small CPU cost on a low-power device.
- If the router is down, no UI access at all. Mitigated by Tailscale fallback to direct Cell SSH (ops only).
- The mental model "router = thin, Cell = fat" is partially violated — router does carry the SPA bytes.
## Alternatives considered
- **Cell hosts the SPA**: requires Cell to be discoverable from operator's machine, makes URLs unstable when Cell IPs change.
- **Hub hosts the SPA, both router and Cell expose APIs**: requires WAN connectivity for the operator UI, breaks air-gapped deployments.