Every screen of the Reports module: intent, route, composition, states,
permissions, behavior. Authoritative shared components in 00-shared/03 ;
this file enumerates which each screen uses with module specifics.
Format mirrors design-docs/auth/05_Screen_Inventory.md.
Analytics = {module}.{screen}.{action} (proposed).
Field Detail
Purpose Pick a report type to generate; see what exists
Entry nav "Reports"; dashboard quick action
Exit → /reports/new (select template)
Content Static list of 3 templates (report card / attendance summary / fee summary) with description + required-param hints; (planned) rows for coaching types (BATCH_PERFORMANCE, TEST_SERIES_ANALYSIS, DPP_COMPLETION — IMPLEMENTATION_PLAN.md:646)
Permission report.read (permissions.constants.ts:40) — hide module without it (forward-looking)
Widgets AppListTile per template, AppBadge "Scheduled" on summary types, FAB? none — list only
States idle; loading skeleton; empty (never: list is static)
Analytics reports.catalog.open, reports.catalog.select(type) (proposed)
Field Detail
Purpose Enter params for one template, POST generate
Entry catalog select
Exit submit → /reports/jobs/:jobId; back → catalog
Form type (fixed, from selection), conditional params per 08
Primary CTA Generate report (disabled while in flight)
States validation (client-side presence for report_card!), submitting (button spinner), error 400 inline, 429 countdown, offline banner
Permission report.generate (permissions.constants.ts:39) — submit blocked without it (forward-looking)
Analytics reports.generate.submit(type), reports.generate.success(jobId), reports.generate.failure(code) (proposed)
Field Detail
Purpose Recent report jobs for the tenant, newest first
Source No list endpoint today — client gap . Server has {tenantId, createdAt:-1} index (report-job.schema.ts:48) but no GET /reports route; client keeps a local history of submitted jobIds (limit ~50, persisted) (forward-looking): add GET /reports?status= server-side
Row type label, status chip (queued/processing/completed/failed — report-job.schema.ts:13-18), createdAt, source badge (User/Scheduled)
Actions tap → job detail; swipe/pull-to-refresh re-polls rows in view
Empty "No reports yet — create one" + CTA to catalog
Widgets AppListTile, AppBadge (status), AppSkeleton, RefreshIndicator, AppEmptyState
Field Detail
Purpose Live status + result of one job; the polling hub
Source GET /reports/:jobId (reports.controller.ts:20-24)
Content header (type, jobId short, createdAt), status area, param summary chips, result section
Status areas queued: "Waiting in queue…" icon; processing: progress indicator (indeterminate — no % from server); completed: result card; failed: error message + Retry
Poll auto-poll 2 s while queued/processing (see 10 ); stop on terminal
Permission report.read (forward-looking)
Errors 404 → "Report not found" state + back; network → banner, poll paused, manual retry
Analytics reports.job.status(jobId,status), reports.job.retry(jobId) (proposed)
Field Detail
Purpose Render completed result; export/share (planned)
Entry job detail when completed
Result renderers report card: subject table + grade badge; attendance: status count cards + totals; fee: 4 metric cards (reports.service.ts:154-158)
CTAs "Download CSV" / "Share PDF" (planned) — no export endpoint in code; "New report from these params" (re-POST)
Permission report.read
Empty completed with empty result → empty state (e.g. zero attendance records)
Analytics reports.result.open(jobId), reports.result.download(jobId) (proposed)
Server side exists: scheduler enqueues generate-attendance-report
(attendance-report.job.ts:15-23), actorId: 'scheduler'. Admin UI to
schedule/configure is (planned); today jobs just appear via job list
(no UI today — see screen 3 gap).
AppListTile, AppBadge, AppButton, AppSkeleton, AppEmptyState,
AppSnackbar, AppBottomSheet (filter), AppOfflineBanner, AppChips (params),
AppMetricCard (module: fee summary), AppProgressRow (module: job status).
reports.catalog.{open,select}, reports.generate.{submit,success,failure},
reports.job.{status,retry}, reports.result.{open,download}.
Forms: portrait-first, keyboard-avoid; tablet two-column (form | live job preview).
Job detail: tablet master-detail with result inline; desktop max-width card.