Skip to main content

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​

FilePurpose
cascade.tsCalculate time shifts
server/apply-changes.tsTransactional DB updates
server/validate-changes.tsZod 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 = 1000 prevents 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:

  1. Accepts batch of changes
  2. Validates with Zod schemas
  3. Checks version for conflicts
  4. Applies in single transaction
  5. 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