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

10 — Interaction Specification (Academics Module)

Module-specific interactions for hierarchy browsing, master-detail, cascading pickers, and the assignment matrix, layered on shared 00-shared/08. Covers phone/tablet/desktop. Every interaction stays within server semantics (no optimistic writes on deletes/set-current).


1. Phone / touch

GestureBehaviourWhere
Tapnavigate rows, toggle tree nodes, open chips/sheets, submitall screens
Tap (row trailing)AppMenu (Edit / Delete / Replace / Remove / Set as current)lists, roster rows
Long-presssame as row menu (tree nodes, roster rows)explorer, matrix
Double-tapexpand/collapse tree node on the label (first tap = select, second = toggle) (proposed)explorer
Swipe leftno destructive swipe — deletes are destructive, keep confirm dialogsall lists
Pull downRefreshIndicator: re-fetch page 1 (lists) / refetch roster + cache (07 §10)lists, detail, explorer
Pinchnone (no media; tree depth ≤ 5 levels)
Hardware backpop to list; sheet → back closes sheet; root → exit shellall
Edge swipedrawer (phone shell)shell

2. Keyboard / desktop / mouse

InputBehaviour
Tablogical order Year → Grade → Section → Class → Subject (forms + explorer)
Entersubmits the visible form / confirms dialog primary action
Esccloses sheet/dialog, collapses popovers, cancels selection → focus returns to trigger
Nnew entity on list screens (year/grade/section/class/subject)
Ctrl+Entersubmit form; set-current confirm
Arrowsnavigate tree nodes (↑/↓ move, →/← expand/collapse), dropdown options
Spacetoggle selected chip / expand node
Right-clickcontext menu = row AppMenu (same actions)
Hoverrow/tree-node highlight surfaceVariant after 150 ms; tooltip on conflict icon (500 ms)
Focusvisible focus ring on every control (00-shared/09 §6)

3. Haptics (mobile)

EventHapticRef
Create success (year/grade/class/subject/assignment)lightImpact
409 duplicate surfacedmediumImpact
Delete confirm (destructive)heavyImpact
Tree node expand/collapseselectionClick
Chips / year switcher toggleselectionClick
Ruledisabled when system haptics off; none on desktop08 §3

4. Motion language (module extension of 08 §4)

TransitionDuration/curveUsed by
List → detail pushm-base slide; Hero on row leading avatar → header card (m-slow)year/grade/class/subject detail
Sheet (add assignment)m-base bottom slide, 2/3 heightmatrix add sheet
Tree expand/collapseAnimatedSize m-base; children stagger m-fastexplorer
Conflict banner in/outslide-down + fade m-baseclass detail, roster, explorer
Row removalAnimatedList exit m-fast + snackbarlists, roster
Status badge change (set-current)scale pop m-fast on new "Current" pillyear list/detail
Chips filter togglefill/outline swap m-fastlists, explorer
FAB morph (Overview → Subjects tab)AnimatedSwitcher m-fastclass detail

Reduced-motion: all of the above degrade to fades ≤ m-instant; no slide or scale.

5. Micro-interactions catalogue

InteractionDetail
Cascading picker parent changechildren reset + disabled with AnimatedSize shrink; new options fade in; selection emits {academicYearId, gradeId, sectionId} or null (07 §6)
"Add subject" in matrixsheet opens; subject dropdown searchable; already-assigned entries disabled with "Already assigned" caption
Duplicate warn on class nameas the user types the name, cache lookup on (year, grade, section, name) shows inline "Duplicate class?" confirm on submit, not on keystroke
Subject form markslive summary line updates per keystroke: "theory 80 + practical 20 = 100 ≤ max 100"; invalid combo disables submit
Set as currentserver-first: button loading → 200 → badges re-render (old current loses pill with m-fast fade) → snackbar
Remove assignmentconfirm dialog → server-first → row exit AnimatedList; 404 stale id → treat as removed + refresh
Year switcher changeall scoped lists reload (year param), skeleton only in list body, AppBar chip swaps m-fast
Pull-to-refresh cascadelist refreshes first, then cache (refreshAll), then downstream consumers re-fetch scoped data (13 §5)

6. Frustration controls (shared 08 §6 + module)

  • All presses respond < 100 ms with m-fast ripple.
  • Every network action shows pending state (button loading / skeleton / spinner).
  • Submit disabled while pending — no double-submit (anti-double-create: the worst failure here is a duplicate 409 that actually succeeded on the server).
  • 429 → countdown, never auto-retry.
  • Errors persist until corrected or dismissed; conflict banners stay until resolved (not auto-timeout) since they change the meaning of the roster.
  • studylyon://academics/classes/:id → class master screen directly.
  • studylyon://academics/explore?yearId= → explorer scoped to a year.
  • ObjectId paste: admin/dev build accepts pasted MongoId in search fields to jump to an entity (hidden behind kDebugMode flag).
  • Roster table (desktop): SelectableText on code/IDs, Ctrl+C works.

8. Validation of interaction to server semantics

Interaction claimServer check
"Set as current" confirms global un-flaggingsetCurrent loops all isCurrent:true docs (academic-year.service.ts:72-77) — confirmed
Delete of grade shows orphan warning, no cascaderemove = bare softDelete (grade.service.ts:58-61), no children checks — confirmed
Replace assignment = delete + createno update endpoint (subject-assignment.controller.ts:19-39) — confirmed
Client duplicate guard only, never claims server rejectionno unique index/check on assignments/classes (subject-assignment.schema.ts:22-25, class.service.ts:16-18) — confirmed
Year switcher re-scopes via academicYearId query paramby-year / by-class / by-teacher take academicYearId (class.controller.ts:30-35, subject-assignment.controller.ts:24-35) — confirmed
Status free-string treated conservativelyschema defaults only (grade.schema.ts:21-22) — confirmed