Architecture
CheerKeeper is a two-sided platform with a web admin dashboard and mobile app sharing a common backend.
System Overview
┌─────────────────────────────────────────────────────────────┐
│ Clients │
├────────────────────────────┬────────────────────────────────┤
│ Admin Dashboard │ Mobile App │
│ (Next.js 16) │ (Expo/React Native) │
│ admin.cheerkeeper.com │ iOS + Android │
└────────────────────────────┴────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ API Layer │
│ Next.js API Routes (app/api/*) │
│ • RESTful endpoints │
│ • JWT + NextAuth authentication │
│ • Rate limiting │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Business Logic │
├────────────────────────────┬────────────────────────────────┤
│ Schedule Engine │ Auth System │
│ lib/schedule-engine/ │ lib/auth/ │
├────────────────────────────┼────────────────────────────────┤
│ Terminology Config │ PDF/AI Extraction │
│ lib/terminology/ │ lib/extraction/ │
└────────────────────────────┴────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Data Layer │
│ Prisma ORM → PostgreSQL (Neon) │
└─────────────────────────────────────────────────────────────┘
Admin Dashboard
Tech Stack
- Next.js 16 with App Router
- TypeScript throughout
- Tailwind CSS + shadcn/ui components
- TanStack Query for server state
- Vercel hosting
Key Directories
cheerkeeper-admin/
├── app/
│ ├── (auth)/ # Login, register pages
│ ├── (dashboard)/ # Main app pages
│ │ ├── events/ # Event management
│ │ └── settings/ # User/company settings
│ └── api/ # API routes (102 endpoints)
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives
│ ├── event-builder/ # Event creation wizard
│ └── schedule/ # Schedule editor
├── lib/
│ ├── auth/ # Authentication logic
│ ├── schedule-engine/ # Cascade, sync, validation
│ └── terminology/ # Competition type configs
└── prisma/ # Database schema
Mobile App
Tech Stack
- Expo SDK 54 with Expo Router
- TypeScript throughout
- React Native StyleSheet (custom theme)
- expo-sqlite for offline data
- AsyncStorage for preferences
Key Directories
cheerkeeper-app/
├── app/
│ ├── (tabs)/ # Main tab navigation
│ ├── (auth)/ # Login screens
│ └── event/ # Event detail screens
├── src/
│ ├── components/ # React Native components
│ ├── services/ # API client, storage
│ ├── stores/ # State management
│ └── utils/ # Theme, constants
└── assets/ # Images, fonts
Authentication
Dual authentication system:
Custom JWT
- Email/password login
- Access token (1 hour) + Refresh token (7 days)
- Stored in httpOnly cookies
NextAuth.js
- Google OAuth integration
- Session management
- Account linking
Unified Session
The getUnifiedSession() helper checks both systems:
// lib/auth/unified-session.ts
export async function getUnifiedSession() {
// Check JWT first
const jwtSession = await getJWTSession();
if (jwtSession) return jwtSession;
// Fall back to NextAuth
const nextAuthSession = await auth();
if (nextAuthSession) return nextAuthSession;
return null;
}
Schedule Engine
The core scheduling system in lib/schedule-engine/:
Components
| File | Purpose |
|---|---|
cascade.ts | Calculate time shifts |
server/apply-changes.ts | Transactional DB updates |
server/validate-changes.ts | Zod schema validation |
Cascade Algorithm
// O(n) linear pass
function calculateCascade(performances, changedPerf, delta) {
return performances
.filter(p => p.time > changedPerf.time)
.filter(p => p.sessionId === changedPerf.sessionId)
.map(p => ({ ...p, time: p.time + delta }));
}
Safety Features
MAX_CASCADE_DEPTH = 1000prevents infinite loops- Session boundaries stop cascade
- Optimistic locking via
scheduleVersion
API Design
RESTful Endpoints
/api/auth/* # Authentication
/api/events/* # Event CRUD
/api/events/:id/schedule/* # Schedule management
/api/company/* # Company/user management
/api/teams-orgs/* # Organizations and teams
Version 2 Sync
The /api/events/:id/schedule/v2/sync endpoint:
- Accepts batch of changes
- Validates with Zod schemas
- Checks version for conflicts
- Applies in single transaction
- Returns new version number
Data Flow
Creating a Performance
User Input
↓
React Form → API Call → Route Handler
↓
Zod Validation → Schedule Engine
↓
Prisma Transaction → PostgreSQL
↓
Response → React Query Cache
↓
UI Update
Mobile App Sync
App Opens
↓
Check cached data age
↓
Fetch /api/events/:id/schedule
↓
Store in expo-sqlite
↓
Display from local cache
↓
Background refresh on pull
Deployment
Admin Dashboard
- Platform: Vercel
- Database: Neon PostgreSQL
- CDN: Vercel Edge Network
- Environment: Production + Preview
Mobile App
- Build: EAS Build
- iOS: App Store via TestFlight
- Android: Google Play Store
- Updates: OTA updates via Expo
Monitoring
- Error Tracking: Sentry
- Analytics: Vercel Analytics
- Database: Neon dashboard
- Uptime: status.cheerkeeper.com
Related Docs
- Local Setup - Development environment
- Database Schema - Data models
- API Overview - API documentation