How EquiPassr Works
A deep dive into the core data flows, expiration rules engine, offline architecture, and security model powering EquiPassr's real-time horse show verification system.
Core User Flows
QR Verification Flow
Owner's Phone
QR code displayed
Secretary Scans
Camera reads token
Server Query
Live DB lookup
Document Check
Rules engine evaluates
Result Shown
Green/Red on secretary
Why server-side verification?
The QR code on the owner's phone contains only a signed token. No document data is ever on-device. Secretaries cannot be shown fake screenshots — the server always queries live data.
Anti-fraud design
Results appear only on the secretary's device. Owners never see pass/fail, preventing screenshot fraud. Tokens are cryptographically signed with rotation on each login.
Expiry Rules Engine
All rules are stored in the database and managed via admin panel — no code deployment required
Coggins Test
HealthEquine Infectious Anemia
Health Certificate
HealthIssued by licensed vet
Rabies Vaccination
VaccinationAnnual requirement
Flu/Rhino Vaccination
VaccinationBi-annual
USEF Membership
MembershipCalendar year
Brand Inspection
RegistrationState-specific
Rules Engine Logic
function verifyDocuments(horse, event) {
const results = [];
for (const requirement of event.requirements) {
if (!requirement.required) continue;
const doc = horse.documents.find(
d => d.documentTypeId === requirement.documentTypeId
);
if (!doc) {
results.push({ pass: false, reason: `Missing: ${requirement.name}` });
continue;
}
const daysOld = differenceInDays(new Date(), doc.expirationDate);
if (daysOld < 0) {
results.push({ pass: false, reason: `${doc.name} expired ${Math.abs(daysOld)}d ago` });
} else {
results.push({ pass: true });
}
}
return {
pass: results.every(r => r.pass),
reasons: results.filter(r => !r.pass).map(r => r.reason)
};
}Offline-First Architecture
Offline Mode
- Owners view horse profiles + documents
- QR passes displayed offline
- Secretaries scan and cache results
- Check-ins queued for sync
Background Sync
- Detects connectivity restored
- Flushes queued check-ins to server
- Pulls latest doc updates
- Conflict resolution with server wins
Data Flow Diagram
Service Worker (Workbox)
Caches assets, intercepts requests
IndexedDB (Dexie.js)
Local horse, doc, event data
Sync Queue
Pending mutations waiting to sync
Background Sync API
Triggered on reconnect
REST API Server
Authoritative source of truth
Technology Stack
Frontend
Next.js 14 + TypeScript
App Router, SSR
State
Zustand + localStorage
Offline-first persistence
Auth
JWT + Role-based
Owner / Secretary / Admin
Offline
Workbox + Dexie.js
IndexedDB local storage
Sync
Background Sync API
Auto-sync when online
QR
Signed tokens (server)
Anti-screenshot fraud
Storage
AWS S3 / Cloudflare R2
Document file storage
Database
PostgreSQL + Prisma
Relational, type-safe