Monorepo Structure
The project uses npm workspaces to manage three interconnected packages:package.json:
Technology Stack
Frontend (Website)
- Framework: Next.js 16 with React 19
- Rendering: App Router with standalone output
- Styling: Tailwind CSS 4.1
- State Management:
- Zustand for global state
- TanStack Query for server state
- Dexie (IndexedDB) for client-side persistence
- UI Components: Radix UI primitives
- Charts: Chart.js with react-chartjs-2
- Real-time: WebSocket integration via
react-use-websocket
Backend (API Server)
- Runtime: Bun
- Framework: Elysia 1.4
- Database: MongoDB with Mongoose + Typegoose
- Caching: Redis (ioredis)
- API Documentation: OpenAPI/Swagger
- Task Scheduling: Elysia Cron
- Real-time: WebSocket connections to ScoreSaber and BeatLeader
- Monitoring: Prometheus metrics
- Discord Integration: Discord.js bot for notifications
Common Library
- Language: TypeScript
- Validation: Zod schemas
- API Client: Axios
- Time Utils: Day.js
- Serialization: devalue for efficient data transfer
- Shared Models: Typegoose models for MongoDB
System Architecture
Data Flow
1. User Request Flow
- Client Request: User navigates to a page (e.g.,
/player/76561198449793387) - Next.js SSR: Server renders initial HTML with metadata
- TanStack Query: Client fetches player data from backend API
- Backend Controller: Routes request to appropriate service
- Service Layer: Checks Redis cache first
- Cache Miss: Fetches from MongoDB or external APIs
- Response: Data flows back through the stack
- Client Render: React components display the data
2. Real-time Score Updates
3. Caching Strategy
Multi-layer caching for optimal performance:- Client-side (Dexie): User settings, player profiles (6 hours TTL)
- Server-side (Redis): API responses with varying TTL:
- BeatSaver maps: 7 days
- Player data: 30 minutes
- Leaderboards: 2 hours
- ScoreSaber API: 2 minutes
Key Features
Shared Type Safety
The@ssr/common package ensures type safety across frontend and backend:
API Documentation
Elysia automatically generates OpenAPI/Swagger docs:http://localhost:8080/swagger
Performance Optimizations
Frontend
- React Compiler: Automatic memoization
- Optimized Imports: Package-level tree shaking
- Image Optimization: Unoptimized for faster builds
- Standalone Output: Minimal Docker images
Backend
- Bun Runtime: Fast JavaScript runtime
- Redis Caching: Reduces database load
- Connection Pooling: MongoDB connection reuse
- Prometheus Metrics: Performance monitoring