Comprehensive QR Code System
Overview
This document describes the comprehensive QR code system implemented for Hashpass. The system provides dynamic QR code generation, double-spend prevention, admin controls, and is designed to be agnostic for future wallet crypto transfers.
Features
✅ Core Features
-
Dynamic QR Generation
- Each pass generates unique, time-limited QR codes
- QR codes expire after a configurable time (default: 30 minutes)
- Automatic refresh mechanism prevents stale QR codes
-
Double-Spend Prevention
- Each QR code can only be used once (configurable)
- Database-level validation prevents reuse
- Usage tracking and audit logs
-
Admin Controls
- Admins can revoke QR codes at any time
- Suspend QR codes temporarily
- Reactivate revoked/suspended QR codes
- View all QR codes and scan logs
-
Wallet-Agnostic Design
- Supports multiple QR types:
pass,wallet_transfer,access_code,ticket - Extensible for future crypto wallet integrations
- Flexible JSON payload system
- Supports multiple QR types:
-
Integrated Scanner
- QR scanner integrated in navbar
- Real-time validation feedback
- Error handling and user feedback
Architecture
Database Schema
qr_codes Table
- Stores all QR code records
- Fields:
token: Unique dynamic tokenqr_type: Type of QR (pass, wallet_transfer, etc.)pass_id: Associated pass (nullable)user_id: Owner of the QRstatus: active, used, expired, revoked, suspendedexpires_at: Expiration timestampusage_count: Number of times scannedmax_uses: Maximum allowed uses (default: 1)- Admin fields:
revoked_by,revoked_at,revoked_reason
qr_scan_logs Table
- Audit trail for all QR scans
- Tracks scanner information, scan results, and timestamps
Database Functions
generate_qr_token(): Generates unique QR tokensgenerate_pass_qr(): Creates a dynamic QR for a passvalidate_and_use_qr(): Validates and marks QR as used (prevents double spending)revoke_qr_code(): Admin function to revoke QR codessuspend_qr_code(): Admin function to suspend QR codesreactivate_qr_code(): Admin function to reactivate QR codes
Service Layer (lib/qr-system.ts)
The QRSystemService class provides:
generatePassQR(): Generate QR for a passvalidateAndUseQR(): Validate and use QR (prevents double spending)checkQRValidity(): Check validity without usingrevokeQR(): Admin revokesuspendQR(): Admin suspendreactivateQR(): Admin reactivategetQRScanLogs(): Get scan historygenerateWalletTransferQR(): Generate wallet transfer QR (future)
Components
-
QRScanner(components/QRScanner.tsx)- Full-screen QR scanner modal
- Camera permission handling
- Real-time validation
- Success/error feedback
-
DynamicQRDisplay(components/DynamicQRDisplay.tsx)- Displays dynamic QR codes for passes
- Auto-refresh functionality
- Expiry countdown timer
- Status indicators
API Endpoints
All endpoints require admin authentication:
GET /api/qr/admin- List all QR codes (with filters)POST /api/qr/admin- Revoke a QR codePOST /api/qr/admin/suspend- Suspend a QR codePOST /api/qr/admin/reactivate- Reactivate a QR codeGET /api/qr/admin/logs- Get QR scan logs
Usage
For Users
-
View Pass QR Code
- Navigate to dashboard
- Click "QR Code" button on pass card
- QR code displays with auto-refresh
-
Scan QR Code
- Click QR scanner icon in navbar
- Point camera at QR code
- Validation happens automatically
For Admins
-
Manage QR Codes
// Revoke a QR codeawait qrSystemService.revokeQR(token, adminUserId, reason);// Suspend a QR codeawait qrSystemService.suspendQR(token, adminUserId);// Reactivate a QR codeawait qrSystemService.reactivateQR(token, adminUserId); -
View QR Codes
// Get all QR codesconst qrCodes = await qrSystemService.getUserQRCodes(userId);// Get scan logsconst logs = await qrSystemService.getQRScanLogs(qrCodeId);
Integration Points
Navbar Scanner
- Located in
app/(shared)/dashboard/_layout.tsx - QR scanner button opens full-screen scanner
- Integrated with
QRScannercomponent
Pass Display
- Located in
components/PassesDisplay.tsx - "QR Code" button opens modal with
DynamicQRDisplay - Each pass has its own dynamic QR
Security Features
-
Double-Spend Prevention
- Database-level checks prevent QR reuse
- Atomic operations ensure data consistency
- Usage count tracking
-
Expiration
- QR codes expire after 30 minutes (configurable)
- Automatic status updates
- Expired QRs cannot be used
-
Admin Controls
- Only admins can revoke/suspend QRs
- Full audit trail in scan logs
- Revocation reasons tracked
-
Rate Limiting
- API endpoints have rate limiting
- Prevents abuse and DDoS
Future Enhancements
Wallet Integration
The system is designed to support wallet QR codes for crypto transfers:
// Generate wallet transfer QR
const walletQR = await qrSystemService.generateWalletTransferQR(
userId,
walletAddress,
amount,
currency
);
Additional Features
- QR code analytics dashboard
- Bulk QR operations
- Custom QR expiration rules per pass type
- QR code templates and branding
Migration
To set up the QR system:
-
Run Database Migration
# The migration file is at:# supabase/migrations/20250120000000_create_qr_system.sql -
Verify Installation
- Check that tables are created
- Verify functions are available
- Test QR generation
-
Configure Admin Roles
- Set up
user_rolestable if not exists - Assign admin role to users who need QR management
- Set up
Troubleshooting
QR Codes Not Generating
- Check user authentication
- Verify pass exists and is active
- Check database connection
- Review error logs
Scanner Not Working
- Verify camera permissions
- Check
expo-barcode-scannerinstallation - Test on physical device (simulators may not support camera)
Admin API Access Denied
- Verify admin role in
user_rolestable - Check authentication token
- Verify API endpoint authorization logic
API Examples
Generate QR Code
const result = await qrSystemService.generatePassQR(passId, {
expiresInMinutes: 30,
maxUses: 1
});
Validate QR Code
const result = await qrSystemService.validateAndUseQR(token, scannerUserId);
if (result.valid) {
// QR is valid and has been marked as used
console.log(result.qr_data);
} else {
// QR is invalid, expired, or already used
console.error(result.message);
}
Admin: List QR Codes
curl -X GET "https://api.example.com/api/qr/admin?status=active&page=1" \
-H "<AUTH_HEADER>"
Admin: Revoke QR Code
curl -X POST "https://api.example.com/api/qr/admin" \
-H "<AUTH_HEADER>" \
-H "Content-Type: application/json" \
-d '{"token": "QR-1234-5678", "reason": "Lost device"}'
Best Practices
- QR Expiration: Keep expiration times reasonable (15-60 minutes)
- Auto-Refresh: Enable auto-refresh for better UX
- Error Handling: Always handle validation errors gracefully
- Admin Actions: Log all admin actions for audit purposes
- Rate Limiting: Implement rate limiting on QR generation
Support
For issues or questions:
- Check database logs for errors
- Review scan logs for validation issues
- Verify RLS policies are correctly configured
- Test with different user roles