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

08 — Form Specifications (Dashboard Module)

The dashboard is a read-first surface: no forms exist today (the single endpoint is GET /dashboard/overviewdashboard.controller.ts:13-17; no DTO directory exists under src/modules/dashboard/). This file specifies the two form-like surfaces that arrive with (planned) server work, plus the non-form "inputs" the screens already take. Validation rules follow the shared form baseline (00-shared/08).


1. Widget Customization form (planned)

Reached from /dashboard/customize (perm-gated by dashboard.widget.managepermissions.constants.ts:38). Server API (planned) (Dashboard.md:26-27); persistence dashboard_widgets (Dashboard.md:7).

FieldControlRules
Widget listReorderableListView (drag handles)1:1 with server widget ids; reorder is local until save
VisibilitySwitch per widgetoptimistic toggle + rollback on failure
Role chipsAppChips multi-select (planned)"who may see this widget" — free-text chip input; server role-list param (planned)
SubmitAppButton "Save"one PATCH /dashboard/widgets/:id per changed widget (planned); per-item saving state; conflict (409, concurrent edit) → AppSnackbar + reload

States: idle (pristine, Save disabled) / dirty (Save enabled) / saving (per-item spinner) / saved (success snackbar < 3 s) / error (banner ≥ 4 s, keep local edits) / conflict (reload).

A11y: drag handles Move semantics; every switch has widget-name label; focus moves to first invalid — none expected (no free-text validation).

2. Period selector (planned) — segmented, not a form

FieldControlRules
PeriodSegmentedButton Today/7d/30dsingle-select, non-empty default "Today"; disabled + tooltip until server accepts ?period= on /dashboard/attendance / /dashboard/finance (planned) (Dashboard.md:24-25)

State lives in the cubit (13_State_Management.md §3); changing period refetches; no optimistic rendering of unloaded periods (charts show skeleton).

3. Existing "inputs" (non-form)

InputKindBehaviour
Pull-to-refreshgesturebypasses client cache, force network (06_Screen_Specifications.md §1.4)
KPI tap → drilltap target ≥ 48navigation only, no payload mutation
WS invalidationpassive listenernever user-visible as input

4. Global form rules (applied when forms land)

  • No form autofill needed (no personal data).
  • Submit-once: double-tap guard (00-shared/08).
  • Offline: forms disabled with AppOfflineBanner (no offline queue for dashboard writes; 00-shared/06 §3.6).
  • Error copy maps 400 VALIDATION_ERROR field-level, 409 conflict inline (00-shared/07 §3).