09 — User Behaviour (Rooms Module)
Observed/expected user behaviours around the room catalog, and the
(proposed)analytics events that measure them. Where a behaviour hits a backend gap, the gap is named (OQ-x, see 01 §10).
1. Behaviours & patterns
1.1 Browsing & filtering (S1)
- Users scan for capacity + type first ("which lab fits 40?"), building second.
- Without server filter/sort (OQ-3), users page through
_id-ordered data — behaviour: client-side chips + search(proposed); long-term server params(planned). - Pull-to-refresh is the trust gesture after admin edits elsewhere.
1.2 Code hygiene (S3)
- Users type lowercase/mixed codes ("Lab 2", "lab-2"); client uppercases + trims
(proposed). - Duplicate attempts are common at term start (copy-paste of previous room). Create-time
409 (authoritative,
rooms.service.ts:19-21) + inline hint resolve it. - Edit-path duplicate (OQ-1) is a real trap: rename onto an existing code → 500 today;
users retry, get same 500 → ticket. Mitigation
(proposed): client warning + server pre-check(planned).
1.3 Capacity behaviour (OQ-7)
- Server accepts negative/zero capacity (
@IsNumberonly —create-room.dto.ts:20-23); users have entered0for "unknown". Client blocks< 1(proposed)and shows "Capacity unknown" state for absent capacity — never a fake0.
1.4 Deletion (S4)
- Users delete rather than archive; they expect the room to disappear from lists
(it does — soft delete,
rooms.service.ts:48-51) and to be able to "undo" (they can't — restore is DB-level; snackbar copy says "deleted"). - In-use rooms get deleted (OQ-4) — timetable planner later sees a missing venue.
Copy warning
(proposed); server in-use guard(planned). - Typed-name confirm reduces accidental deletes; analytics track cancel-vs-confirm.
1.5 Permission-denied
- Without server RBAC (OQ-2), a read-only user with a crafted request can mutate rooms;
client gates UI, but the server guard is the real fix
(planned). Client treats future 403 as route-hide + 403 screen.
1.6 Offline
- Reads: last-good cache + banner; stale list is acceptable (catalog changes rarely).
- Writes: blocked — no offline queue for this module (reference data; low urgency).
2. Analytics events (proposed)
| Event | Trigger | Screen |
|---|---|---|
rooms.list.open | screen shown | S1 |
rooms.list.search (term) | search debounce fires | S1 |
rooms.list.filter.type (type) | chip toggle | S1 |
rooms.list.filter.building | chip toggle | S1 |
rooms.list.filter.clear | "Clear filters" | S1 |
rooms.list.load_more (page) | infinite scroll fetch | S1 |
rooms.list.refresh | pull-to-refresh | S1 |
rooms.list.row_tap (id) | row → detail | S1 |
rooms.detail.open (id) | screen shown | S2 |
rooms.detail.edit | Edit pressed | S2 |
rooms.detail.delete.start | Delete menu pressed | S2 |
rooms.detail.copy_code | menu copy | S2 |
rooms.editor.create.open / .edit.open | form shown | S3 |
rooms.editor.create.submit / .edit.submit | Save pressed | S3 |
rooms.editor.create.success / .edit.success | 201/200 | S3 |
rooms.editor.create.duplicate | 409 | S3 |
rooms.editor.discard | discard confirm | S3 |
rooms.delete.confirm / rooms.delete.cancel | dialog action | S4 |
rooms.checkin.scan | QR scan at venue | (forward-looking) |
rooms.booking.{book,cancel} | booking actions | (planned) |
rooms.analytics.utilization | utilization report view | (proposed) |
3. Behavioural rules
| Rule | Rationale |
|---|---|
| No optimistic writes on S3/S4 — always wait for server result | conflict/duplicate semantics must stay authoritative; remove() returns void so local removal happens only after 200 |
| Local row removal on delete success (no refetch) | DELETE has no payload (rooms.service.ts:48) |
| Filter state survives list-scroll within session, resets on route pop | predictable resets (00-shared/05) |
| Search debounce 300 ms; code-dup check debounce 300 ms | input budget (00-shared/10 §1) |
| Empty filter result keeps filter visible with "clear" CTA | recoverability over dead-ends |
| 429/rate-limit → backoff countdown on submit, no auto-retry | shared error handling (00-shared/06 §5) |