Attendance Engine & Inverted Persistence
Inverted attendance ledger, default-to-present failure modes, optimistic UI rollbacks, and foreign key cascade semantics.
Attendance Engine & Inverted Persistence
The Attendrix Attendance Engine tracks academic lecture attendance for thousands of students while maintaining sub-second client responsiveness and eliminating over 80% of database write overhead.
Absences are explicitly recorded in public.absences. Presence is derived dynamically when no absence record exists for an active class slot. Absences cannot be logged for canceled or holiday-flagged occurrences.
1. The Inverted Persistence Model
In standard university enterprise systems, an attendance record is created every time a student attends a lecture. Because Indian university regulations mandate 75–80% attendance, approximately 80–90% of all student-lecture pairs are positive.
Attendrix inverts this assumption:
State Definition:
- Row exists in public.absences for (user_id, class_id) --> Student is ABSENT
- No row exists in public.absences for (user_id, class_id) --> Student is PRESENTArchitectural Advantages
- 80%+ Write Reduction: The database writes records only when a student skips a class.
- Instant Course Initialization: Enrolling in a course requires zero row inserts in the attendance table; the student immediately starts with 100% attendance.
- Sparse Index Density: Indexes on
public.absences (user_id, class_id)remain exceptionally compact, fitting entirely in RAM buffer pools.
2. Concurrency Hazards: "Default to Present" Failure Modes
While the inverted model saves millions of database rows, it introduces an asymmetric failure hazard:
If a student marks themselves absent in the mobile app, but the network request drops or fails before reaching PostgreSQL, the database defaults to Present.
In an academic context where attendance fraud or unverified records carry disciplinary risks, an unhandled failure silently awards unearned presence.
Mitigation Architecture in Mobile Client
The Attendrix client implements a multi-layer mitigation strategy in mark_absent.dart and sync_app_data.dart:
sequenceDiagram
autonumber
participant UI as Flutter Student UI
participant AppState as FFAppState (Local Cache)
participant SecStore as FlutterSecureStorage (Pending Queue)
participant PostgREST as Supabase RPC (mark_absent)
participant DB as PostgreSQL public.absences
UI->>AppState: Student taps "Mark Absent"
AppState->>AppState: Optimistic UI update: is_absent = true
AppState->>SecStore: Enqueue pending absence mutation {class_id, timestamp}
AppState->>PostgREST: Dispatch mark_absent(p_class_id, p_source, p_reason)
alt RPC Succeeded
PostgREST->>DB: INSERT INTO public.absences (user_id, class_id)
DB-->>PostgREST: Returns updated attendance stats
PostgREST-->>AppState: Success Response
AppState->>SecStore: Dequeue pending mutation
AppState->>AppState: Confirm local attendance percentage
else RPC Network Timeout / Offline
AppState->>UI: Show Toast: "Absence saved offline. Will sync when online."
Note over AppState,SecStore: Pending queue persists across app restarts
else RPC Rejected (e.g. CLASS_CANCELLED)
PostgREST-->>AppState: Error: CLASS_CANCELLED
AppState->>SecStore: Dequeue invalid mutation
AppState->>AppState: Rollback is_absent = false
AppState->>UI: Show Alert: "Cannot mark absence: Class was cancelled."
end- Pending Mutation Queue: Mutations are immediately written to encrypted local flash storage (
FlutterSecureStorage) before the HTTP request is initiated. - Reconciliation Loop: Upon reconnecting to WiFi or cellular data,
syncAppDatareplays all pending mutations before fetching fresh server states. - Explicit Server Error Rollback: If the server rejects an absence (e.g., class cancelled by faculty, semester ended), the client automatically rolls back the optimistic UI state and notifies the student.
3. Class Reconciliation & Foreign Key Cascade Behavior
A critical architectural pitfall in university scheduling is handling class cancellations, room changes, and timetable regeneration.
Why Soft Deletes Are Mandatory
In the Attendrix database:
-- In public.classes:
is_cancelled boolean NOT NULL DEFAULT false,
cancelled_at timestamptz,
cancellation_reason textThe foreign key on public.absences.class_id references public.classes.class_id.
If timetable regeneration were implemented via physical SQL DELETE FROM classes WHERE ..., a cascade (ON DELETE CASCADE) would permanently wipe all historical student absences logged for those classes!
Even without cascade, a RESTRICT rule would cause the administrative schedule sync to crash.
The Soft-Delete Guarantee
To preserve historical attendance integrity:
- Never Physically Delete Occurrences: Classes are marked with
is_cancelled = true. - Exclusion from Calculation: The
calculate_user_attendance_v2RPC explicitly filters out cancelled classes:
SELECT count(*)
FROM classes c
WHERE c.semester_id = p_semester_id
AND c.is_cancelled = false
AND c.scheduled_start <= now();- Absence Ledger Invariance: Absences associated with cancelled classes are ignored during percentage calculation but preserved in the audit history.
4. Margin-of-Safety & Projection Mathematics
Students track attendance primarily to avoid falling below institutional mandatory thresholds (typically or ). The attendance projection algorithm computes live and projected compliance:
where and .
The custom action calculateProjectedAttendance calculates the bunk margin () and recovery deficit ():
Case 1: Attendance Above Threshold ()
The student can safely miss upcoming lectures before dropping below threshold :
Case 2: Attendance Below Threshold ()
The student must attend consecutive lectures without absence to recover to threshold :
Was this page helpful?
Your feedback directly guides the engineering documentation roadmap.