09 — User Behaviour (Audit Module)
- 1. Expected behaviour (server-contract-driven)
- 2. Common mistakes & countermeasures
- 3. Power & new users
- 4. Mobile & a11y users
- 5. Interrupted sessions & retries
- 6. Abandonment
- 7. Frustration points → UX treatments (summary table)
- 8. Adoption path (holistic)
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.3PLAN.md:191). - Timestamps are authoritative: display
occurredAtin 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/actorId—audit.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 inbefore/after(audit.service.ts:20); UI must not hint that secrets are retrievable.
2. Common mistakes & countermeasures
| Mistake | Related | UX countermeasure |
|---|---|---|
| Expecting a search box that finds any text | no 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 nothing | emitters 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 record | before 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-only | no edit paths exist; detail footer explains immutability; support workflow = new action |
| Misreading timestamps across timezones | UTC storage, local display | UTC in tooltip; column header note on desktop |
| Clicking rows expecting a server refetch | no :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,Enteropen,Ctrl+Ccopy 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
AuditEntryRowcards; filter bar collapses to aAppBottomSheet("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)
| Frustration | Treatment |
|---|---|
| "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.