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