10 — Interaction Specification (Reports Module)
- 1. The polling engine (core interaction)
- 2. Status transitions (UI)
- 3. Screen-level interactions
- 4. Error taxonomy (client)
- 5. Motion & haptics
- 6. Keyboard / adaptive (S2)
Interaction contracts: polling engine, transitions, error handling, motion. Motion tokens
m-fast/m-basefrom 00-shared/08; shared interaction baseline 00-shared/08.
1. The polling engine (core interaction)
Server contract: GET /reports/:jobId returns the full job doc
(reports.controller.ts:20-24, reports.service.ts:46-50); statuses
queued | processing | completed | failed (report-job.schema.ts:13-18).
Algorithm
start(jobId):
poll() every 2s while status in {queued, processing}
on completed → stop; render result (S5)
on failed → stop; render error + Retry
on 404 → stop; not-found state
on network/5xx → pause cycle; show banner + "Retry check";
manual retry resumes cycle
terminal status is sticky; a fresh screen open with terminal doc does not poll
Parameters
| Aspect | Value | Rationale |
|---|---|---|
| Interval | 2 s | fast enough for UX; harmless load (1 doc query, indexed {tenantId,status}, report-job.schema.ts:47) |
| Max consecutive failures | 2 | then pause; exponential backoff for manual retry (1 s → 2 s → 4 s) |
| Timeout per request | 10 s | global client HTTP timeout (00-shared/07) |
| Max overall wait | none | server has no job TTL; user can leave and return (B2) |
Jitter & life
- Poll times: 2 s ± 400 ms jitter (thundering-herd avoidance at term end when a school generates N cards).
- Poll cycle lifecycle: starts on S4
initState; cancelled on dispose; aTimer(not a loop) so cancellation is clean.
2. Status transitions (UI)
| From | To | Trigger | Transition |
|---|---|---|---|
| queued | processing | poll | badge swap (C2), progress row gains elapsed timer — m-fast crossfade |
| processing | completed | poll | success reveal; result card slides in m-base; haptic light (mobile) |
| processing | failed | poll | error card + error text; m-fast fade |
| any non-terminal | offline | network fail | banner slide-in; cycle pauses |
| offline | resumed | manual retry | banner clears; cycle resumes |
No transition animation for the badge itself beyond color change — keep perceptual noise low at 2 s cadence.
3. Screen-level interactions
S2 Generate form
- Submit → button
loading; on success: navigate pushReplacement to S4 (form is dead after submission; back returns to catalog). - Failure: inline errors, form intact.
report_cardwithout required ids: inline error BEFORE network (08 §3.1).
S3 Job list
- Pull-to-refresh: re-poll visible rows (only non-terminal ones).
- Row tap → S4. Failed row menu: Retry (re-POST
params→ new jobId,reports.service.ts:31-43). - Filter chips (All/Running/Completed/Failed) filter locally — no query API.
S4 Job detail
- Auto-poll (1). Elapsed timer ticks 1 s while processing.
- Retry (failed): confirm dialog → new POST → pushReplacement to new job detail.
- "New report from these params": prefill S2 from
params(:33).
S5 Result
- Scrollable content; export CTAs disabled w/ tooltip "coming soon"
(planned). - Share sheet
(forward-looking)once PDF exists.
4. Error taxonomy (client)
| Error | Detection | UX |
|---|---|---|
| 404 | poll GET | not-found state; back to list |
| 401 | interceptor | silent refresh, resume poll |
| 429 | interceptor | pause poll 30 s; countdown snackbar; no auto-retry (00-shared/10) |
| network | timeout/connection | banner + pause (1) |
| job failed | poll GET status | terminal UI (2) |
5. Motion & haptics
- Status badge changes:
m-fast(150 ms) color/opacity crossfade. - Result reveal:
m-base(250 ms) slide-up + fade. - Screen push: shared push transition (
00-shared/08). - Haptics:
HapticFeedback.mediumImpacton completed reveal; light on failed.
6. Keyboard / adaptive (S2)
resizeToAvoidBottomInset; next-chain; tablet: form left, live job preview right (05 §Keyboard).