10 — Interaction Specification (Dashboard Module)
- 1. Load sequence (first open)
- 2. Pull-to-refresh
- 3. Background polling
- 4. WebSocket-triggered refresh
- 5. KPI card tap → drill
- 6. Stale-data surfaces
- 7. Customize screen
(planned) - 8. Empty-state interactions
- 9. Keyboard / focus
- 10. Motion budget
Micro-interaction rules for the dashboard. Motion tokens
Mo.*per 00-shared/02 §6; shared interaction patterns per 00-shared/08. State flow per 13_State_Management.md; component contracts per 07_Component_Library.md.
1. Load sequence (first open)
- Route push
Mo-m-baseslide+fade;AppBarimmediately visible. - KPI row area renders 5
AppSkeletoncards (value 28 dp line + label 12 dp, shimmerMo-m-fast), charts renderAppSkeleton(chart). - Payload arrives → skeletons swap for values with staggered fade-in
(30 ms apart, row order = service order
dashboard.service.ts:31-33,34,35-37); chart blocks animate drawMo-m-base((planned)blocks). - Failure on first load →
AppErrorState.code+Retry; retry re-runs the sequence from 2. No partial numbers.
2. Pull-to-refresh
AppRefreshIndicatorwraps the scroll view; trigger calls cubitrefresh()withforce: true— bypasses client cache (00-shared/06 §3.3), network fetch, cache-write on success.- During refresh: cards stay painted (no skeleton flash); only the indicator
spins. Success → silent replace
AnimatedSwitcher200 ms. Failure with existing data →AppSnackbar(error)≥ 4 s, numbers unchanged. - Double pull while in-flight → ignored (single-flight guard, 13_State_Management.md §3).
3. Background polling
- Timer: 60 s (matches cache TTL
Dashboard.md:41), active only while the dashboard route is current and app is foregrounded. - Tick →
refresh()non-forced: if client cache age < 60 s, skip (no request). Else fetch. - App backgrounded (
WidgetsBindingObserver) → timer paused; on resume, staleness check runs immediately.
4. WebSocket-triggered refresh
- Client subscribed to
tenant:{tenantId}room (auto-join on connect —ws.gateway.ts:50); listens forAttendanceMarked,ResultPublished,PaymentRecorded,InvoiceGenerated(Dashboard.md:34). - Event arrives → debounce 2 s (coalesce bulk event bursts) →
refresh(force: true). - If the overview key was invalidated server-side
(planned), the fetch naturally re-reads Redis; today the service live-scans (dashboard.service.ts:24-38) so the refetch simply gets fresh numbers. - Value deltas ≥ 1% animate (
AnimatedSwitcher200 ms) + live-region announcement (a11y). Sub-1% deltas update silently. - Connection lost → rely on poll timer; banner
AppOfflineBannerafter 2 missed polls.
5. KPI card tap → drill
- Whole card is the target (≥ 48 dp). Tap →
Mo-m-basepress ripple → route push to owning module: students list / teachers list / staff list / attendance day view / fees invoices filteredissued|partial|overdue(dashboard.service.ts:36-37). - Back → dashboard refetches on return (staleness check), preserving scroll position.
- No permission for target module → card tap shows
AppSnackbar"You don't have access to this section" (rare; hidden-by-permission prefers to omit the card entirely(planned)).
6. Stale-data surfaces
StaleBanner(info) slides in when rendering client-cached payload older than 60 s (Dashboard.md:41); shows age ("2 min ago") +Refresh.- ≥ 10 min → treated as offline:
AppOfflineBanner+ data kept. - On any successful refetch the banner animates out
Mo-m-fast.
7. Customize screen (planned)
- Entry IconButton (perm-gated
dashboard.widget.manage—permissions.constants.ts:38); route push. - Reorder: drag handle press
Mo-m-fast; drop commits to list state;Saveissues per-widgetPATCH(Dashboard.md:27); per-item spinner; conflict → snackbar + reload. No auto-save on drag.
8. Empty-state interactions
- Zero KPI cards: muted hint line; tap still drills (empty target screens
show their own
AppEmptyState). - All-zero dashboard: hero
AppEmptyState"Your dashboard is ready — add your first data" with primary action → Students module.
9. Keyboard / focus
- Dashboard has no text fields (except
(planned)customize search);Taborder: KPI cards → charts (focusable with caption) → AppBar actions. - Enter activates focused card. Escape returns from detail routes.
10. Motion budget
| Interaction | Token |
|---|---|
| Route enter/exit | Mo-m-base |
| Skeleton shimmer | Mo-m-fast |
| Value update (WS/poll) | 200 ms AnimatedSwitcher |
| Stale/offline banner | slide-in Mo-m-fast |
Chart draw (planned) | Mo-m-base |
| Press ripple | Mo-m-fast |