This document outlines the fix for a critical bug where users received "session not found" errors when trying to check attendance using QR codes or 6-digit numeric codes, even though they were properly enrolled in the seminar.
- Users got "Session not found" error when scanning QR codes
- Users got "Session not found" error when entering 6-digit numeric codes
- Error occurred even for enrolled users with approved status
- Attendance check completely failed for all users
"Session not found"
The main problem was a mismatch between QR code generation and verification:
QR Code Generation (POST method): ✅ Correctly stored codes in qr_codes table
await supabase.from('qr_codes').insert({
session_id: sessionId,
seminar_id: seminarId,
qr_code: qrCode,
numeric_code: numericCode,
// ...
});QR Code Verification (PUT method): ❌ Still trying to verify against session.materials_url
// OLD BROKEN CODE
sessionQrData = JSON.parse(session.materials_url); // Wrong!
if (sessionQrData.qr_code !== qrCode) {
return NextResponse.json({ error: 'Invalid QR code' });
}Users lacked the necessary Row Level Security policies to:
- INSERT their own attendance records
- UPDATE their own attendance records
The existing policies only allowed:
- Users to SELECT their own attendance
- Seminar owners/admins to manage all attendance
But no policy allowed users to create attendance via QR code check-in.
File: src/app/api/seminars/[id]/attendance/qr/route.ts
Before (Broken):
// Tried to parse materials_url as QR data
sessionQrData = JSON.parse(session.materials_url);
if (sessionQrData.qr_code !== qrCode) {
return error;
}After (Fixed):
// For numeric codes: already verified in qr_codes table lookup
// For QR codes: verify against qr_codes table
if (!numericCode) {
const { data: storedQrCode } = await supabase
.from('qr_codes')
.select('id, expires_at')
.eq('qr_code', qrCode)
.eq('session_id', sessionId)
.eq('seminar_id', seminarId)
.single();
if (!storedQrCode) {
return NextResponse.json({ error: 'Invalid or expired QR code' });
}
}Improvements:
- Added proper error logging for debugging
- Enhanced session lookup with seminar information
- Better error messages for users
- Improved enrollment status checking
// Enhanced session lookup with seminar info
const { data: session, error: sessionError } = await supabase
.from('sessions')
.select(`
id,
seminar_id,
materials_url,
seminars!inner (
id,
title,
owner_id
)
`)
.eq('id', sessionId)
.eq('seminar_id', seminarId)
.single();File: scripts/fix-attendance-rls-for-users.sql
Added two critical policies:
Policy 1: Allow users to create attendance
CREATE POLICY "Users can create their own attendance via QR code" ON public.attendances
FOR INSERT
WITH CHECK (
auth.uid() = user_id AND
EXISTS (
SELECT 1 FROM public.enrollments e
JOIN public.sessions s ON s.seminar_id = e.seminar_id
WHERE e.user_id = auth.uid()
AND e.status = 'approved'
AND s.id = attendances.session_id
)
);Policy 2: Allow users to update attendance
CREATE POLICY "Users can update their own attendance via QR code" ON public.attendances
FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (
auth.uid() = user_id AND
EXISTS (
SELECT 1 FROM public.enrollments e
JOIN public.sessions s ON s.seminar_id = e.seminar_id
WHERE e.user_id = auth.uid()
AND e.status = 'approved'
AND s.id = attendances.session_id
)
);Improvements:
- Added specific error logging for debugging
- Better error messages for users
- Enhanced enrollment status checking
- Support for updating existing attendance records
// Enhanced enrollment check with logging
if (enrollmentError || !enrollment) {
console.error('Enrollment check error:', enrollmentError);
console.log('User enrollment check - User ID:', user.id, 'Seminar ID:', seminarId);
return NextResponse.json({
error: 'You are not enrolled in this seminar or your enrollment is not approved'
}, { status: 403 });
}File: src/app/api/debug/attendance-check/route.ts
Created a comprehensive debugging endpoint that checks:
- Session existence and validity
- User enrollment status
- QR code/numeric code verification
- Current attendance status
- User permissions
- Provides specific recommendations for fixing issues
Usage:
POST /api/debug/attendance-check
{
"seminarId": "uuid",
"sessionId": "uuid",
"qrCode": "optional",
"numericCode": "optional"
}Run the SQL script to add missing attendance policies:
# In Supabase SQL Editor
-- Run: scripts/fix-attendance-rls-for-users.sqlEnsure the qr_codes table exists with proper structure:
# If not already applied
-- Run: scripts/add-qr-codes-table.sql- Teacher generates QR code for session
- Student scans QR code
- ✅ Attendance should be recorded successfully
- Student can scan again to update attendance
- Teacher generates 6-digit code for session
- Student enters numeric code
- ✅ Attendance should be recorded successfully
- Student can enter code again to update attendance
- Expired codes: Should get "expired" error
- Invalid codes: Should get "invalid" error
- Non-enrolled users: Should get "not enrolled" error
- Non-existent sessions: Should get "session not found" error
Use the debug endpoint to verify all components:
// Test debugging
fetch('/api/debug/attendance-check', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
seminarId: 'your-seminar-id',
sessionId: 'your-session-id',
qrCode: 'your-qr-code', // or
numericCode: 'your-numeric-code'
})
});- Reduced number of database queries by combining lookups
- Eliminated unnecessary
materials_urlparsing - More efficient session and enrollment verification
- Earlier validation to prevent unnecessary processing
- Better error categorization for user experience
- Comprehensive logging for debugging
The new policies are secure because they:
- Only allow users to create/update their own attendance
- Require valid enrollment with approved status
- Verify session belongs to enrolled seminar
- Use proper authentication context (
auth.uid())
- QR codes expire after 10 minutes
- Codes are tied to specific sessions and seminars
- Automatic cleanup of expired codes
- Verification against stored database records (not just client data)
- Attendance Success Rate: % of successful QR/numeric code scans
- Error Rates: Track specific error types
- Session Not Found Errors: Should be near zero after fix
- Enrollment Issues: Monitor enrollment status problems
- QR Code Cleanup: Automatic cleanup of expired codes
- Policy Review: Periodic review of RLS policies
- Error Log Review: Monitor error patterns
- Performance Monitoring: Track attendance API response times
- Caching: Cache enrollment status for faster lookups
- Batch Processing: Support multiple attendance records at once
- Offline Support: Allow offline QR scanning with sync
- Analytics: Track attendance patterns and insights
If issues arise, the rollback process:
- Remove new RLS policies:
DROP POLICY "Users can create their own attendance via QR code" ON attendances;
DROP POLICY "Users can update their own attendance via QR code" ON attendances;- Revert API changes: Git revert to previous version
- Monitor: Watch for any remaining issues
- Alternative approach: Manual attendance management until fix
The fix is backward compatible and should not require rollback.