Precise interaction rules per screen and the long-running import
interaction. Motion tokens per 00-shared/08 ; components in 07 .
# Interaction Rule
1.1 File pick FileDropZone click/drop; .csv filter; immediately isolate-parse (15 §4 )
1.2 Parse fail inline AppAlert; file card shows error; Next disabled; live-region announce
1.3 Parse success file card confirms (name, rows, headers); Next enabled; m-fast check-in
1.4 Non-UTF-8 / BOM BOM stripped silently; non-UTF-8 → warning card with re-encode guidance (14 §2 )
1.5 Re-pick replaces previous file; wizard state (preview/confirm) reset to preview
# Interaction Rule
2.1 Header classification ColumnChip per header (required/optional/unknown)
2.2 Blocking warning ContractAlert blocking; Import N rows disabled; lists exact missing column names (08 §1 )
2.3 Sample rows first 10; row # = physical line (header=1)
2.4 Back returns to SS1 with file retained
2.5 Unknown columns warning only; never blocks (server ignores, bulk-import.service.ts:26-30)
# Interaction Rule
3.1 Start import fires POST /bulk/import/students (multipart field file, bulk.controller.ts:35-48); navigates immediately to SS4 in-flight; CTA disabled to block double-fire
3.2 Back allowed until fired; no server side effects before firing
# Interaction Rule
4.1 In-flight ImportProgressPanel indeterminate; no progress events exist (bulk-import.service.ts:22-65); panel explains and warns
4.2 Success summary card; View students; Download report
4.3 Partial grouped error table; pagination 50; row tap → expand detail
4.4 Row action copy error string; per-row "open file at line N" hint (rowNumber = line, :46)
4.5 Error CSV client-synthesized: original row + error column; no server endpoint
4.6 Fix errors → SS1 with failed row numbers queued; preview highlights them when the corrected file parses (03 J3)
4.7 Pre-row server rejection 400/404 rendered as failure card with exact copy (08 §2.1 )
4.8 429 countdown Retry in Ns, no auto-retry (00-shared/07 §4 )
4.9 Network drop partial-upload guidance; re-upload is duplicate-safe (06 §4.1a)
# Interaction Rule
5.1 Download GET /bulk/export/students (bulk.controller.ts:50-60); browser attachment students.csv; loading state on button
5.2 Empty header-only CSV still downloads; toast "No rows exported"
5.3 Export ≠ template disclaimer on card (04 §6)
The one request-holding interaction is import execution , and everything
about it must be honest about the synchronous backend:
Aspect Design
Duration reality ~1000 rows × (2 dup checks + 3-4 ref lookups + 2-3 writes) of sequential awaits inside one request (bulk-import.service.ts:45-63; students-import.adapter.ts:38-85)
Feedback indeterminate progress + copy: "validated and created server-side in one request; keep this tab open"
Duration guard client request timeout ≥ 120 s (configurable); on timeout → partial-upload guidance (4.9)
File cap 1000 rows / ~2 MB at pick time; warning above, block above hard cap (configurable (forward-looking))
Rate budget one import can be a large chunk of the 100/min api tier (00-shared/07 §4 ) — warn on very large files
Cancel no server cancel exists ; cancel only abandons the response — copy states rows may still be created
Future seam when async workers land ((planned), IMPLEMENTATION_PLAN.md:172), the panel switches to determinate + polling; cubit keeps progress + jobId fields ready (13 §4 )
Moment Motion (00-shared/08 )
file accepted m-fast (check icon pop)
parse error / block m-fast shake + live-region
wizard step advance m-base slide, stepper check pop
result counts m-base count-up on imported/failed
error row expand m-fast height collapse
SS1 entity select + browse: full keyboard path; drop zone reachable via Tab
SS2/SS4 tables: row # column is focusable; row actions Tab-able.
SS3: single CTA, Enter fires; Back via Escape.
No text inputs exist anywhere in the wizard except the (forward-looking)
entity search — keyboard-avoidance trivial.