docs(wiki): activity-log explainability, dates/i18n, KP-300H barcode fix

Record this session's work across the affected pages + three log entries.

- ticket-encoding: id 13→11 digits (guess-resistance rationale, legacy-safe
  validation) + a barcode-geometry rule (symbol dots must fit the narrowest
  deployed printer's line — the KP-300H 72mm overflow).
- rongta-printer: KP-300H raster-garbage root cause (line overflow, not
  corruption), sendRaw graceful-close fix, Albanian human dates (formatStampSq).
- i18n: localized ledger reason codes, relative/human dates + the
  "browser ICU lacks Albanian" gotcha, toggle stale-router-context fix.
- shift: Albanian Z-report, shift-history UI + permission scoping.
- booth-console: explainable activity log (inline reasons/badges, event-detail
  modal with snapshots + audit disclosure, subscriber names, failed-snapshot
  tiles).
- index/log updated; all added wikilinks resolve.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-06-19 11:41:27 +02:00
parent bbf61c48df
commit 0074e82a2a
7 changed files with 154 additions and 20 deletions
+24 -1
View File
@@ -2,7 +2,7 @@
type: concept
tags: [parking, frontend, booth, realtime, ui]
sources: []
updated: 2026-06-18
updated: 2026-06-19
status: open
---
@@ -68,6 +68,29 @@ a right column with the **live event ticker**. Submitting/clicking a ticket open
modal** (entry/duration/total, tender, voucher checkbox, entry/exit snapshots). All live-refreshed via
the WS.
### Explainable activity log (2026-06-19)
The ticker used to flag an **anomaly** with no explanation — a red row with just an id, "nobody knows
what happened." Now every event is **self-describing and clickable**:
- **Inline reason + badges.** Each row surfaces the localized reason (from the signed `reasonCode` —
see [[i18n]]) and computed classification badges (entry/exit-refused, lot-full, barrier-failed,
manual-open…). Anomalies always show a reason line (or "no reason recorded") so a red flag is never
silent.
- **Clickable → event-detail modal.** A read-only modal with humanized labelled fields (not raw JSON),
the session's **entry/exit snapshots**, and the **signed-chain provenance** (signature / keyId /
prevHash) collapsed behind an "audit data" disclosure — operator sees the story, an auditor expands
for the crypto. *Why show signatures at all:* makes the [[append-only-event-chain|tamper-evidence]]
visible against the [[threat-model|booth-operator]] threat, and survives a signer swap (`keyId`).
- **Subscriber names, not opaque keys.** A [[subscription]] occurrence's `SUBSESS-…` id now renders as
the holder's name ("Aqif Kopertoni", fallback "Abonent"/"Subscriber"). Resolved **read-time
server-side** (events API + WS push attach a non-signed `subscriberLabel` from `permitId →
holder_name`; cached, invalidated on subscription edit/delete) so it needs no extra client
permission and the signed event stays minimal.
- **Failed-snapshot visibility.** A camera that was *attempted but unreachable* now shows a "⚠ camera
unreachable" tile (from snapshot [[device-events|telemetry]]) instead of a silent gap — so the
operator can tell "no camera" from "camera failed". (Surfaced a real incident: a subscriber's entry
snapshot failed `EHOSTUNREACH` while the exit one succeeded — by design a snapshot is *evidence, not
a gate*, so the open proceeded and only the image was missing.)
## The shift control (header) + the booth gate
The header carries a single **shift button** that expresses the [[shift|site-wide single-open