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

05 — Screen Inventory (Attendance Module)

Eight screens. Purpose, entry, primary tasks, components, API, and states for each. API refs are exact (see 12_API_Mapping.md); flags: (planned) = backend gap.


S1 — Today's Roster (class picker)

PurposePick a class (my classes this academic year) + date (default today) → enter marking. Surfaces completion: "23/40 marked".
Entry/attendance (teacher landing, 00-shared/05 §2); timetable class card ("Mark attendance", END_TO_END_USER_FLOWS.md:27); dashboard KPI tap
Primary taskspick class, switch date (yesterday corrections), start marking, view unmarked count
Dataclasses via GET /api/v1/classes (academics module); existing marks need class+date → S2 loads them
ComponentsAppListTile (class cards + completion ring), AppDatePicker, AppSectionHeader ("Marked today"), AppBadge (unmarked count), AppFAB
Statesskeleton → class list (grouped by grade/section) → empty (no classes assigned)
NotesTeacher's classes = classes where classTeacherId = me (class.schema.ts:28) or timetable assignment — resolve via timetable module (planned); fallback: all classes the user can read

S2 — Marking Grid (hero screen, fully speced in 06)

PurposeMark/overlay one status per student for a class+date; the fastest daily capture surface.
EntryS1 pick → push; deep-link /attendance/class/:id/date/:date
Primary taskstap-cycle status, sweep-all-absent, batch apply, mark-late w/ check-in, remark existing day (overwrite semantics), undo
DataGET /attendance/class/:classId?date= (existing docs); roster = students with classId (student.schema.ts:38-39); writes POST /attendance or POST /attendance/bulk
ComponentsAttendanceGrid, StatusChip, MarkedCountBar, StatusFilterChips, BatchEditSheet, UndoBar (see 07)
Statesloading skeleton → grid (rows default-present, existing marks overlaid) → offline (cached roster + queued marks)
Rulesone doc per student/day enforced by unique index attendance.schema.ts:59-62; re-mark = overwrite (attendance.repository.ts:23-29)

S3 — Batch Edit Sheet

PurposeApply one status to many selected rows in a single POST /attendance/bulk.
EntryS2: long-press row (multi-select) → sheet; or "Sweep all to absent" quick action
Primary tasksmulti-select rows, choose target status, confirm, see per-record result
DataBulkMarkAttendanceDto {records[]} (mark-attendance.dto.ts:51-54) → sequential marks, one AttendanceMarked per record (attendance.service.ts:48-54)
ComponentsBatchEditSheet (half-height), status chips grid, selection counter, AppButton "Apply to N"
NotesPartial failure handling per OQ-2 (server returns docs array; failures would throw — client shows snackbar with count; retry-safe because upsert)

S4 — History / Calendar View

PurposeMonthly heatmap per class (or per student from S7): status colors per day, tap day → day summary.
Entry/attendance/class/:id/history; S2 app-bar calendar icon; S6 drill-down
Primary tasksmonth navigation, status-filter heatmap, day detail, jump to S2 read-only for a date
DataGET /attendance/class/:classId?date= per day (N requests, OQ-4 unpaginated) or GET /attendance/student/:studentId?startDate&endDate for S7
ComponentsCalendarHeatmap, StatusLegend, DaySummaryCard, AppDatePicker
NotesClass-level month = up to ~30 daily fetches — cache aggressively (see 13_State_Management.md); consider server aggregation (planned) when OQ-4 resolves

S5 — Monthly Report (summary)

PurposeClass attendance stats for a range: totals + per-status counts; trigger async report.
Entry/attendance/class/:id/report/:month (admin) — teacher lacks report.* (role.schema.ts:31, OQ)
Primary taskspick class + range, view summary, request generated report, open detail
DataGET /attendance/summary?classId&startDate&endDate (attendance.service.ts:103-113{total, summary:{status:count}}); POST /reports/generate {type:'attendance_summary'}GET /reports/:jobId (reports.controller.ts:14-24)
ComponentsSummaryDonut (or AppCharts bar), AppStatTile per status, CalendarHeatmap (rate by week), ReportJobCard (queued/processing/completed/failed — report-job.schema.ts:13-18)
NotesBoth summary paths aggregate in memory (attendance.service.ts:103-113, reports.service.ts:110-137) — UI must handle slow responses at scale (OQ-8)

S6 — Report Detail

PurposeFull generated attendance_summary result: totals, period, per-status breakdown; drill into students/days.
EntryS5 report card tap; /attendance/reports/:jobId
Primary tasksread result, filter status, drill to S4/S7, re-run for new range
DataGET /reports/:jobId{status, result:{total, summary, classId, period}} (reports.service.ts:131-136)
ComponentsAppInfoRow (period, class), AppCharts bar/donut, StatusLegend, AppEmptyState (no data)
Statesqueued → processing (progress) → completed / failed (error from report-job.schema.ts:38-39)

S7 — Student Attendance Profile (tab)

PurposeOne student's history: month heatmap, % present, per-status counts, day detail. Used by self (student), child (parent), and class teacher (context).
Entry/students/:id → "Attendance" tab; parent alert deep link studylyon://attendance/:date
Primary tasksmonth nav, % present, day drill-down, mark/remark (teacher only)
DataGET /attendance/student/:studentId?startDate&endDate (attendance.service.ts:63-73)
ComponentsCalendarHeatmap, AppStatTile (% present, absent, late), StatusLegend, AbsenceAlertCard
NotesRole-gating open (OQ-7): parent/student roles have student.read only (role.schema.ts:55,63); END_TO_END_USER_FLOWS.md:324-325,378-379 assume read access

S8 — Biometric Device Status

PurposeDevice health + ingest visibility: status (active/inactive/offline, biometric-device.schema.ts:7-11), last punch, ingest count, pipeline state.
Entry/attendance/devices (admin/operator)
Primary taskslist devices, check last-punch freshness, view today's ingest count, understand derivation status
Datadevices via biometric module repository (no list endpoint today — (planned), OQ-3); logs GET-able via biometric.log.read (permissions.constants.ts:42)
ComponentsBiometricDeviceTile, AppBadge (status), IngestTrendChart (proposed), AppBanner ("punches captured — not yet applied", OQ-3)
NotesIngest exists (POST /biometric/ingest, biometric.controller.ts:14-18); biometric-sync cron registered (scheduler.service.ts:71-76) but no worker → nothing becomes attendance (OQ-3)