Four sources, one shape
| Source | Origin | Default |
|---|---|---|
qt-events |
QuantumTouch's own event log and its archives | On |
controller-api |
The BNG controller's audit log | On |
systemd-journal |
journalctl across the BNG service units |
On |
portal-access |
Captive portal HTTP access lines | Off — opt in |
Every entry from every source is normalised to the same eight fields:
{
"ts": 1753000000.5,
"source": "qt-events",
"actor": "jdoe (session:9f8b2c14…)",
"action": "event:qt_config_change",
"summary": "Plan 'Silver-20M' updated",
"detail": "rev_id=4412, kind=config_write, severity=info",
"related_event_id": null,
"raw": { "…the untouched original source record…" },
"entry_id": "a1b2c3d4e5f6a7b8"
}
raw is what makes lossy normalisation safe. The original record is preserved
verbatim on every entry, so no information is destroyed by the projection and a
client can always fall back to source-native fields.
Actions are namespaced by source — event:<action>, controller:<METHOD> <path>,
service:{lifecycle|health|access|log}, portal:access — so a consumer can filter
by origin without inspecting the source field.
entry_id is a content-derived hash of the timestamp, source, and summary. It is
not persisted; it is recomputable from any feed of the same data, which is
what makes it usable as a cursor without server-side state.