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

06 — Screen Specifications (Dashboard Module)

Production-grade specs for each dashboard screen: chrome, states, components, micro-interactions, a11y, responsive, dark/light, motion. Tokens: Sp = 00-shared/02 §3, Ty = typography §2, El = elevation §5, R = radius §4, Mo = motion §6. All components reference 00-shared/03. Data shapes cite dashboard.service.ts; payload contract in 12_API_Mapping.md E1.


1. Dashboard Home /dashboard

Chrome: standard AppBar (title "Dashboard", elevation El-1), optional subtitle line "Last updated Xs ago" when serving from cache; body scrolls (CustomScrollView), SafeArea respected; horizontal padding 16 (phone), 24 (tablet+). No FAB except on (planned) customize entry (IconButton in AppBar, shown only with dashboard.widget.managepermissions.constants.ts:38).

1.1 Layout (phone portrait)

AppBar "Dashboard"                    [.. customize (planned, perm-gated)]
RefreshIndicator wraps content ↓
─────────────────────────────────────
Section: KPI row (horizontal scroll)
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│Students│ │Teachers│ │ Staff  │ │Attend. │ │ Dues   │
│  812   │ │  34    │ │  21    │ │ 93%    │ │ ₹4.2L  │
│ ▲ +2   │ │  —     │ │  —     │ │  ▓ 91% │ │ ▲ +8k  │
└────────┘ └────────┘ └────────┘ └────────┘ └────────┘
   KpiCard×5: value headlineMedium; label bodySmall;
   TrendIndicator (planned) bodySmall success/error/neutral
─────────────────────────────────────
Section: Attendance summary (planned chart)
ChartCard "Attendance — today"
  bar/line per status breakdown (summary:status→count,
  dashboard.service.ts:40-43) or rate line (:57-64)
  PeriodSelector (planned): Today | 7d | 30d  (segmented)
─────────────────────────────────────
Section: Finance card (planned trend)
ChartCard "Finance" — dues number + pendingInvoices
  chip "3 overdue" (status issued/partial/overdue,
  dashboard.service.ts:36-37)
─────────────────────────────────────
Section: widget grid (planned, perm-gated)

1.2 KPI cards — content contract

Each KPI card binds to one leaf of the payload (dashboard.service.ts:50-70):

CardValueSource lineFormat
Studentsstudents.total:31 (count active)integer, NumberFormat
Teachersteachers.total:32integer
Staffstaff.total:33integer
Attendanceattendance.rate:57-64% (server pre-rounds)
Duesfinance.totalDueAmount:45-48,:68currency, locale INR
Pending invoicesfinance.pendingInvoices:36-37,:67integer badge on Dues card

Trend (Δ vs previous period) has no server field → render only when a (planned) trend field ships; until then show neutral and never fake a delta. Trend style: success up, error down, neutral flat (00-shared/02).

1.3 States

  • loading (first load): AppSkeleton — KPI row as 5 square cards (value line 28 dp, label line 12 dp, shimmer Mo.m-fast); charts as AppSkeleton(chart) blocks. No partial numbers.
  • success: cards fade/slide in Mo-m-base staggered (30 ms apart); charts animate draw Mo-m-base.
  • empty (fresh tenant): counts render as real 0 (the API returns zeros — dashboard.service.ts:31-33,64), each zero card shows a muted hint: "Invite your first student"; attendance card shows "No attendance today" (rate 0 path :64); finance card "No pending invoices". A single AppEmptyState hero ("Your dashboard is ready — add your first data") for the all-zero case; never hide a 0 behind an error.
  • error (offline): AppOfflineBanner top + last-good payload rendered with StaleBanner ("Showing data from X min ago"); retry button.
  • error (5xx): first-load → AppErrorState.code (INTERNAL) + Retry; with previous data → inline AppSnackbar + keep old numbers, no flash.
  • stale: payload served from client cache older than the 60 s TTL (Dashboard.md:41) but newer than 10 min → StaleBanner (info) with "Refresh" action; older → treat as offline.
  • permission: no dashboard.read → route inaccessible (module hidden), never an error screen (00-shared/06 §5).

1.4 Refresh / polling / WS

MechanismBehaviour
Pull-to-refreshAppRefreshIndicator → cubit refresh()bypasses client cache (force network, 00-shared/06 §3.3)
Focus returnrefetch when app resumes or route returns to dashboard (staleness check first)
Pollingbackground poll every 60 s while dashboard is the active tab and app is online; cancelled on dispose (13_State_Management.md §4)
WS invalidationon AttendanceMarked / ResultPublished / PaymentRecorded / InvoiceGenerated (Dashboard.md:34) delivered to tenant:{id} (ws.gateway.ts:50) → debounced (2 s) refetch; charts animate in place Mo-m-base
Double-load guardsingle in-flight request; queued trigger coalesces (13_State_Management.md §3)

1.5 Charts ((planned) blocks; today only numbers ship)

  • Type: attendance trend line/bar; finance collection line. Render via shared AppCharts (00-shared/03); no chart library decision is module-owned.
  • A11y chart summaries: every chart has semanticsLabel describing the data ("Attendance 93% today, 812 of 874 present") + a bodySmall caption text row (screen-reader-safe alternative, 00-shared/09).
  • Empty chart: dashed-line placeholder + "No data for this period".
  • PeriodSelector (planned): SegmentedButton Today/7d/30d; selection is cubit state, triggers refetch with ?period= only when server supports it (planned) — until then client-side slicing of the overview is not possible (single today-only payload); selector stays disabled with tooltip.

1.6 A11y

  • KPI cards: semantics button (drill) + label, value in one node; order value-first for screen readers ("93 percent, Attendance").
  • Live region on value changes after WS refresh (announce only deltas > 1%).
  • Trend (planned): arrow glyphs have hidden semantics text ("up 2%").
  • Touch targets ≥ 48 dp; dynamic type to 200% reflows KPI row to vertical.
  • Color is never the only signal (trends also carry ▲/▼ glyphs).

1.7 Dark/light & responsive

  • Token-only theming; KPI cards surfaceContainerLow (dark: same token), charts use primary/secondary/tertiary (00-shared/02).
  • Tablet ≥840 dp: 3-col grid (KPI row 1×5→wrap 3+2, charts side-by-side).
  • Desktop: max content width 1200; hover raises card El-e2 + reveals drill affordance.
  • Landscape phone: charts keep 16:9, KPI row stays horizontal scroll.

1.8 Motion

  • Route enter: Mo-m-base slide+fade; skeleton shimmer Mo-m-fast; WS-updated values: AnimatedSwitcher 200 ms; stale banner slide-in.

2. Attendance Detail /dashboard/attendance (planned)

ConcernSpecification
ChromeAppBar "Attendance", back; body as §1
HeaderheadlineMedium today's rate + summary chips (present/absent/… counts — dashboard.service.ts:40-43)
ChartChartCard period trend from GET /dashboard/attendance (Dashboard.md:24); PeriodSelector enabled (server param (planned))
Statesas §1; empty → "No attendance recorded yet" (rate-0 path :64)
A11ychart caption + semantics as §1.5
Teacher scope(planned) (IMPLEMENTATION_PLAN.md:232) — "my classes" filter; no server support today

3. Finance Detail /dashboard/finance (planned)

ConcernSpecification
ChromeAppBar "Finance", back
Headerdues headlineMedium + pendingInvoices count + overdue chip (:36-37)
Chartcollection trend from GET /dashboard/finance (Dashboard.md:25)
Drill"View invoices" → /fees/invoices (filters mirror status in issued/partial/overduedashboard.service.ts:36-37)
Statesas §1; empty → "No pending invoices — all settled"
A11yas §1.5

4. Widget Customization /dashboard/customize (planned)

ConcernSpecification
EntryAppBar IconButton on Home, rendered only with dashboard.widget.manage (permissions.constants.ts:38)
Palettelist of widget cards with ReorderableListView handles + Switch visibility + role chips (planned)
SaveAppButtonPATCH /dashboard/widgets/:id per change (planned) (Dashboard.md:27); per-item saving state; conflict (another admin edited) → AppSnackbar + reload list
Persistenceserver dashboard_widgets (Dashboard.md:7) (planned); no local-only layout — always server-authoritative
Statesloading skeleton list; empty → "All widgets shown"; error → AppErrorState + retry
A11yreorder handles have Move semantics; switches labeled with widget name

Shared micro-interaction & motion notes (all screens)

  • Mo-m-base route transitions; AppBar elevation El-1; cards El-e1 (00-shared/02 §5-6).
  • Snackbar durations: success < 3 s, error ≥ 4 s (00-shared/03 A).
  • No FAB on dashboard screens (customize is an AppBar action).
  • Polling timer paused when app backgrounded (WidgetsBindingObserver).
  • Safe areas: bottom nav height respected in authed context.