feat: explainable activity log — reasons, subscriber names, snapshot gaps
The live activity feed flagged anomalies with no explanation and showed opaque session keys. Make events self-describing and clickable. - Clickable feed rows → read-only event-detail modal: humanized fields, entry/exit snapshots, and signed-chain provenance collapsed behind an audit disclosure (operator sees the story, auditor expands for crypto). - Localized reason codes (backend i18n): the signed ledger now carries a stable REASON_CODE + params (+ English fallback) instead of free-text English. The UI translates via reason.<code> catalogs in sq/en, so an Albanian operator reads Albanian — from the same immutable event. Adding a language is a catalog change, no re-signing. (@parking/shared REASON_CODES, reasonPayload; entry/exit/subscription flows emit codes.) - Subscriber-name resolution: a SUBSESS-… occurrence now shows the subscription holder's name (fallback "Abonent"/"Subscriber"). Resolved read-time server-side (events API + WS push) as a non-signed subscriberLabel; cached with invalidation on subscription edit/delete. - Failed-snapshot visibility: a camera that was attempted but unreachable now shows a "⚠ camera unreachable" tile instead of a silent gap. The snapshots API returns failures[] from telemetry, filtered so a recovered capture shows no stale warning. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
+14
-3
@@ -747,9 +747,20 @@ export interface SnapshotMeta {
|
||||
capturedAt: string;
|
||||
}
|
||||
|
||||
/** Snapshot metadata for a session identity (newest first). Image bytes are at
|
||||
* `/api/snapshots/:id` — use that URL directly as an <img src>. */
|
||||
export function fetchSnapshots(identity: string): Promise<{ snapshots: SnapshotMeta[] }> {
|
||||
/** A capture that was ATTEMPTED but failed (camera offline, config) — surfaced so a
|
||||
* missing image isn't a silent gap. From snapshot telemetry, not the image store. */
|
||||
export interface SnapshotFailure {
|
||||
direction: "entry" | "exit" | null;
|
||||
deviceId: string;
|
||||
error: string;
|
||||
occurredAt: string;
|
||||
}
|
||||
|
||||
/** Snapshot metadata for a session identity (newest first) PLUS failed capture
|
||||
* attempts. Image bytes are at `/api/snapshots/:id` — use that as an <img src>. */
|
||||
export function fetchSnapshots(
|
||||
identity: string,
|
||||
): Promise<{ snapshots: SnapshotMeta[]; failures?: SnapshotFailure[] }> {
|
||||
return apiFetch(`/api/snapshots/by-identity/${encodeURIComponent(identity)}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user