feat(vision): surface the recognized plate in the booth UI

The ANPR plate was saved (device_events kind:"read") but had no UI. Extend
GET /api/snapshots/by-identity/:identity to also return plates[] (plate, confidence,
region, direction, snapshotId, at) for that session, and render each as a cyan
"Plate: AA558EE 100%" chip in the SnapshotStrip — so it shows in both the booth
event-detail modal and the pay modal, beside the evidence photo, no separate screen.
Deduped by plate+direction; session:read gated; i18n sq+en.

Verified: by-identity returns plates[] for a seeded read (200, AA558EE 0.999 Albania
entry). Build + lint green.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-06-19 17:23:32 +02:00
parent ecaaefd899
commit 9ec644811a
7 changed files with 100 additions and 5 deletions
+13 -2
View File
@@ -789,11 +789,22 @@ export interface SnapshotFailure {
occurredAt: string;
}
/** A licence plate recognized for this session by the ANPR-on-snapshot path (advisory
* record — see opencv-anpr-service.md). `snapshotId` links to the image it was read from. */
export interface PlateRead {
plate: string;
confidence: number | null;
region: string | null;
direction: "entry" | "exit" | null;
snapshotId: string | null;
at: 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>. */
* attempts PLUS any recognized plates. Image bytes are at `/api/snapshots/:id`. */
export function fetchSnapshots(
identity: string,
): Promise<{ snapshots: SnapshotMeta[]; failures?: SnapshotFailure[] }> {
): Promise<{ snapshots: SnapshotMeta[]; failures?: SnapshotFailure[]; plates?: PlateRead[] }> {
return apiFetch(`/api/snapshots/by-identity/${encodeURIComponent(identity)}`);
}