The Attendance module provides a comprehensive, production-ready system for tracking student attendance. It supports multiple tracking methods, parent engagement features, early warning systems for chronic absenteeism, and flexible reporting capabilities.
┌─────────────────────────────────────────────────────────────────────────┐
│ ENTRY POINTS │
├─────────────────────────────────────────────────────────────────────────┤
│ Platform: /s/[subdomain]/attendance → Overview Dashboard │
│ Parent: /parent/attendance → Parent Portal View │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ TAKING ATTENDANCE │
├──────────────┬──────────────┬──────────────┬────────────────────────────┤
│ Manual │ QR Code │ Barcode │ Bulk Upload │
│ /manual │ /qr-code │ /barcode │ /bulk-upload │
└──────┬───────┴──────┬───────┴──────┬───────┴────────────┬───────────────┘
│ │ │ │
└──────────────┴──────────────┴────────────────────┘
│
▼
┌───────────────────────────────┐
│ Period Selector (optional) │
│ Auto-detects current period │
│ from timetable integration │
└───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ actions.ts: markAttendance() / markPeriodAttendance() │
└─────────────────────────────────────────────────────────────────────────┘
│
┌─────────┴─────────┐
│ Status = ABSENT? │
└─────────┬─────────┘
│ YES
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ triggerAbsenceNotification() │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────────────┐ │
│ │ Email │ │ SMS │ │ In-app Notification │ │
│ │ (Resend) │ │ (Twilio) │ │ (Parent Portal) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ PARENT EXCUSE WORKFLOW │
├─────────────────────────────────────────────────────────────────────────┤
│ 1. Parent receives notification │
│ 2. Views absence in parent portal → excuse-form.tsx │
│ 3. Submits excuse with reason + attachments → submitExcuse() │
│ 4. Teacher/Admin reviews → excuse-review.tsx → reviewExcuse() │
│ 5. Status: APPROVED → Attendance updated to EXCUSED │
│ REJECTED → Remains unexcused │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ EARLY WARNING SYSTEM │
├─────────────────────────────────────────────────────────────────────────┤
│ getStudentsAtRisk() → Groups by US DoE Risk Levels: │
│ ┌────────────────┬────────────────┬────────────────┬────────────────┐ │
│ │ Satisfactory │ At-Risk │ Moderately │ Severely │ │
│ │ ≥95% │ 90-94.9% │ Chronic 80-89%│ Chronic <80% │ │
│ └────────────────┴────────────────┴────────────────┴────────────────┘ │
│ │ │
│ ▼ │
│ intervention-tracker.tsx → Create/Track/Escalate │
│ 14 intervention types • 5 statuses • Priority 1-4 │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ REPORTING & ANALYTICS │
├─────────────────────────────────────────────────────────────────────────┤
│ /analytics → charts.tsx (trends, breakdowns, period analysis) │
│ /reports → content.tsx (filterable table with export) │
│ │ │
│ export-button.tsx │
│ ┌─────────┬─────────────┬─────────────┐ │
│ │ CSV │ Excel │ PDF │ │
│ │ │ (5 sheets) │ (branded) │ │
│ └─────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
src/
├── app/[lang]/s/[subdomain]/(platform)/attendance/
│ ├── page.tsx # Overview dashboard
│ ├── manual/page.tsx # Manual attendance marking
│ ├── qr-code/page.tsx # QR code sessions
│ ├── barcode/page.tsx # Barcode scanning
│ ├── bulk-upload/page.tsx # CSV bulk import
│ ├── analytics/page.tsx # Charts and trends
│ └── reports/page.tsx # Filterable reports + export
│
├── components/platform/attendance/
│ ├── content.tsx # Overview dashboard content
│ ├── actions.ts # Server actions (~4000 lines, 30+ functions)
│ ├── validation.ts # Zod schemas for all forms
│ ├── types.ts # TypeScript type definitions
│ ├── tracking.tsx # Manual attendance marking UI
│ │
│ ├── qr-code/
│ │ ├── content.tsx # QR code session management
│ │ ├── qr-generator.tsx # QR code generation
│ │ ├── qr-scanner.tsx # Student QR scanning
│ │ └── actions.ts # QR-specific server actions
│ │
│ ├── barcode/
│ │ ├── content.tsx # Barcode scanning UI
│ │ └── barcode-scanner.tsx
│ │
│ ├── bulk-upload/
│ │ ├── content.tsx # CSV import UI
│ │ └── upload-form.tsx
│ │
│ ├── period/
│ │ ├── period-selector.tsx # Period dropdown with timetable
│ │ └── current-period.tsx # Current period indicator
│ │
│ ├── early-warning/
│ │ ├── content.tsx # Early warning dashboard
│ │ ├── at-risk-list.tsx # Students by risk level
│ │ └── intervention-tracker.tsx
│ │
│ ├── excuses/
│ │ ├── excuse-form.tsx # Parent excuse submission
│ │ ├── excuse-review.tsx # Teacher/admin review
│ │ └── actions.ts
│ │
│ ├── analytics/
│ │ ├── content.tsx # Analytics dashboard
│ │ └── charts.tsx # Recharts visualizations
│ │
│ └── reports/
│ ├── content.tsx # Reports page
│ ├── export-button.tsx # CSV/Excel/PDF dropdown
│ ├── pdf-generator.tsx # @react-pdf/renderer
│ └── excel-generator.ts # xlsx library
│
└── components/platform/parent-portal/attendance/
├── view.tsx # Parent attendance view
└── excuse-form.tsx # Parent excuse submission
Navigate to Attendance in the platform sidebar to access the module.
The overview page displays:
Mark attendance manually for a class:
01. Go to Manual page
Click "Take Attendance" from the overview or navigate to Attendance → Manual
02. Select a class
Choose the class from the dropdown
03. Select the date
Pick the date for attendance (defaults to today)
04. Select period (optional)
For period-based schools, select the specific period. The system auto-detects the current period based on timetable.
05. Mark status for each student
Use the toggle buttons to mark each student as:
06. Submit
Click "Save Attendance" to record all entries. Absent students' guardians are automatically notified.
For secondary schools with timetable-based attendance:
Current Period Indicator
Shows the current period based on school timetable with quick action to mark attendance.
Period Selector
Period Analytics
Generate QR codes for students to scan and mark their attendance:
01. Go to QR Code page
Click "QR Code Session" from overview or navigate to Attendance → QR Code
02. Select a class
Choose the class for the session
03. Configure options
Set validity period (default: 30 minutes)
04. Generate QR Code
Click "Generate" to create a unique QR code
05. Display the QR code
Students scan with their devices to check in. The system validates student enrollment and prevents duplicate scans.
Use student ID barcodes for quick attendance:
01. Go to Barcode Scanner page
Navigate to Attendance → Barcode
02. Select a class
Choose the class for attendance
03. Scan student IDs
Use a barcode scanner or device camera to scan student ID barcodes. The system looks up the student identifier and marks attendance.
Import attendance records from a CSV file:
01. Go to Bulk Upload page
Navigate to Attendance → Bulk Upload
02. Download template
Get the CSV template with required columns
03. Fill in data
Add attendance records following the format:
studentId,date,status,checkInTime,checkOutTime,notes
student_123,2024-01-15,PRESENT,08:00,15:00,
student_456,2024-01-15,ABSENT,,,Medical leave04. Upload file
Select your CSV file and click "Upload"
05. Review results
Check the import summary for successful and failed records
When a student is marked absent, the system automatically notifies guardians:
Notification Channels:
Notification Content:
Multi-language Support:
Parents can submit excuses for their children's absences:
01. View Absence
Parents see unexcused absences in their portal
02. Click "Submit Excuse"
Opens the excuse submission form
03. Select Reason
Choose from:
04. Provide Details
Add description and upload supporting documents (medical notes, etc.)
05. Submit
Excuse goes to teacher/admin for review
Excuse Status:
Parents see comprehensive attendance information:
The system automatically monitors student attendance and identifies at-risk students:
Risk Levels (US DoE Guidelines):
Dashboard Features:
Track and manage interventions for at-risk students:
Intervention Types:
Intervention Workflow:
01. Create Intervention
Select intervention type, set priority, assign staff member
02. Schedule
Set scheduled date and any follow-up dates
03. Track Progress
Update status: Scheduled → In Progress → Completed/Escalated
04. Document Outcome
Record results and next steps
Escalation: Interventions can be escalated to higher levels (e.g., parent call → parent meeting → administrator meeting)
Generate and export attendance reports:
Configure attendance module behavior:
The attendance module uses server actions for data operations:
// Mark daily attendance
markAttendance(input: {
classId: string
date: string
records: Array<{
studentId: string
status: 'present' | 'absent' | 'late'
}>
})
// Mark period-specific attendance
markPeriodAttendance(input: {
classId: string
date: string
periodId: string
records: Array<{
studentId: string
status: 'PRESENT' | 'ABSENT' | 'LATE'
notes?: string
}>
})
// Get periods for a class on a specific day
getPeriodsForClass(input: {
classId: string
date: string
})
// Get current period based on time
getCurrentPeriod(classId?: string)
// Get at-risk students
getStudentsAtRisk(input?: {
classId?: string
riskLevel?: 'AT_RISK' | 'MODERATELY_CHRONIC' | 'SEVERELY_CHRONIC'
limit?: number
})
// Create intervention
createIntervention(input: {
studentId: string
type: InterventionType
title: string
description: string
priority?: number
scheduledDate?: string
assignedTo?: string
})
// Update intervention
updateIntervention(input: {
interventionId: string
status?: InterventionStatus
outcome?: string
completedDate?: string
})
// Submit excuse (parent)
submitExcuse(input: {
attendanceId: string
reason: ExcuseReason
description?: string
attachments?: string[]
})
// Review excuse (teacher/admin)
reviewExcuse(input: {
excuseId: string
status: 'APPROVED' | 'REJECTED'
reviewNotes?: string
})type AttendanceStatus =
| "PRESENT"
| "ABSENT"
| "LATE"
| "EXCUSED"
| "SICK"
| "HOLIDAY"
type AttendanceMethod =
| "MANUAL"
| "QR_CODE"
| "BARCODE"
| "BULK_UPLOAD"
| "GEOFENCE"
| "RFID"
| "FINGERPRINT"
| "FACE_RECOGNITION"
| "NFC"
| "BLUETOOTH"
type InterventionType =
| "PARENT_PHONE_CALL"
| "PARENT_EMAIL"
| "PARENT_MEETING"
| "HOME_VISIT"
| "COUNSELOR_REFERRAL"
| "SOCIAL_WORKER_REFERRAL"
| "ADMINISTRATOR_MEETING"
| "ATTENDANCE_CONTRACT"
| "TRUANCY_REFERRAL"
| "COMMUNITY_RESOURCE"
| "ACADEMIC_SUPPORT"
| "MENTORSHIP_ASSIGNMENT"
| "INCENTIVE_PROGRAM"
| "OTHER"
type InterventionStatus =
| "SCHEDULED"
| "IN_PROGRESS"
| "COMPLETED"
| "CANCELLED"
| "ESCALATED"
type ExcuseReason =
| "MEDICAL"
| "FAMILY_EMERGENCY"
| "RELIGIOUS"
| "SCHOOL_ACTIVITY"
| "TRANSPORTATION"
| "WEATHER"
| "OTHER"
type ExcuseStatus = "PENDING" | "APPROVED" | "REJECTED"The attendance module uses these Prisma models:
model Attendance {
id String @id @default(cuid())
schoolId String
studentId String
classId String
date DateTime @db.Date
status AttendanceStatus
method AttendanceMethod @default(MANUAL)
checkInTime DateTime?
checkOutTime DateTime?
notes String?
markedBy String?
markedAt DateTime @default(now())
// Period tracking
periodId String?
timetableId String?
periodName String?
@@unique([schoolId, studentId, classId, date, periodId])
@@index([schoolId, date, periodId])
}
model AttendanceExcuse {
id String @id @default(cuid())
schoolId String
attendanceId String @unique
reason ExcuseReason
description String?
attachments String[]
status ExcuseStatus @default(PENDING)
submittedBy String
reviewedBy String?
reviewNotes String?
}
model AttendanceIntervention {
id String @id @default(cuid())
schoolId String
studentId String
type InterventionType
title String
description String
outcome String?
status InterventionStatus @default(SCHEDULED)
priority Int @default(1)
scheduledDate DateTime?
completedDate DateTime?
followUpDate DateTime?
initiatedBy String
assignedTo String?
escalatedFrom String?
}
model QRCodeSession {
id String @id @default(cuid())
schoolId String
classId String
code String @unique
expiresAt DateTime
isActive Boolean @default(true)
scanCount Int @default(0)
scannedBy Json @default("[]")
}
model StudentIdentifier {
id String @id @default(cuid())
schoolId String
studentId String
type IdentifierType // BARCODE, QR_CODE, RFID_CARD, etc.
value String
isActive Boolean @default(true)
isPrimary Boolean @default(false)
}The attendance seed creates realistic test data:
Run seed:
pnpm db:seed