Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

09 — User Behaviour (Audit Module)

Expected behaviour (derived from server semantics + shared interaction rules), common mistakes users make with these screens, and the UX countermeasures.


1. Expected behaviour (server-contract-driven)

  • Everything they see is append-only: no edit/delete/undo affordances anywhere; footer on detail states it (audit-log.repository.ts:6, PLAN 19.3 PLAN.md:191).
  • Timestamps are authoritative: display occurredAt in local time; hover/tooltip shows UTC ISO (audit-log.schema.ts:42-43); there is no server timezone field — the client owns tz display.
  • The list is server-paginated: page 1 loads 50 (audit.controller.ts:20); scrolling loads more; pull-to-refresh resets to page 1.
  • New activity appears live: while the list is open, WS appends arrive without manual refresh (ws-bridge.service.ts:16-22).
  • Filters are exact-match on raw strings (action/entityType/actorIdaudit.controller.ts:22-24), not fuzzy search; the client explains that.
  • Masking is already applied server-side: sensitive payload keys show *** — the user will see masked values in before/after (audit.service.ts:20); UI must not hint that secrets are retrievable.

2. Common mistakes & countermeasures

MistakeRelatedUX countermeasure
Expecting a search box that finds any textno q param (08 §1 row 7)search control hidden/disabled with "search (planned)" tooltip; interim client-side page filter
Expecting date-range filtering ("what happened last Tuesday?")no from/to (AUDITING.md:86 vs code)date controls (planned); until then: paginate back, sort is fixed desc (audit-log.repository.ts:23)
Filtering by entity type and getting nothingemitters rarely set entityType (OQ-1)inline helper note on the dropdown: "Entity type appears only on entries that carried it"
Thinking the diff is a full recordbefore mostly absent; after = payload (audit.handler.ts:42-43)"Snapshot after action" label; empty-diff empty state
Trying to "correct" a wrong entry (impossible)append-onlyno edit paths exist; detail footer explains immutability; support workflow = new action
Misreading timestamps across timezonesUTC storage, local displayUTC in tooltip; column header note on desktop
Clicking rows expecting a server refetchno :id endpoint (OQ-4)instant in-memory detail (fast); deep-link fallback message

3. Power & new users

  • Power user (compliance officer, desktop): keyboard-first table — / filter, arrow navigation, Enter open, Ctrl+C copy JSON on detail; "Load more" until the window is covered; export (planned).
  • New user: list + filter bar are self-explanatory; empty state teaches ("Actions that happen in StudyLyon will appear here.").

4. Mobile & a11y users

  • One-thumb phone: compact AuditEntryRow cards; filter bar collapses to a AppBottomSheet ("Filter" button) to keep the list scannable.
  • TalkBack/VoiceOver: table headers announced; diff rows labeled "field X changed"; realtime banner announced via live region.
  • Dynamic type 200%: table degrades to stacked rows (06 §2); no clipping.
  • Reduced motion: appends/rows fade only (Mo-m-instant); no stagger.

5. Interrupted sessions & retries

  • Suspend/resume: list re-fetches on resume if stale > 5 min (volatile list TTL, 00-shared/06 §3.3); WS resubscribes on reconnect.
  • Mid-load interruption: skeleton stays; error state offers retry.
  • Retry after 429: countdown; no auto-retry (00-shared/07 §4).
  • Server 5xx: generic error + requestId; retry keeps current filters.

6. Abandonment

  • Where people quit: filter sheet dismissal (keeps filters), deep-link entry not found (back to list), export sheet (planned) disabled (acknowledged note).
  • Filters + scroll persist per session in the cubit (StatefulShellBranch keeps tab state, 00-shared/05 §3); not persisted across app restarts (no requirement).

7. Frustration points → UX treatments (summary table)

FrustrationTreatment
"Where is last week's entry?"date-range filter (planned); until then "load more" + fixed desc sort
"Why is this filter empty?"helper notes on entityType/actor dropdowns
"What changed exactly?"AuditDiffView changed/added/removed; JSON tree for payloads
"Who is actor u_8f2a…?"name resolution (proposed) via users module; always show id anyway (mono, copyable)
"Can I get a CSV?"export (planned) — disabled control with honest note

8. Adoption path (holistic)

P0: list + filters + detail (in-memory) + realtime append. P1: actor-name resolution, keyboard-first table refinements. P2 (planned): date-range + search (backend), export, entry timeline, RBAC preset wiring into access-audit.