Monorepo Structure
The project uses a pnpm workspace managed by Turborepo for efficient builds and caching:Build System
Monkeytype uses Turborepo to orchestrate builds across the monorepo:turbo.json
- Dependency-aware builds: Packages build in correct order (
^builddependency) - Incremental builds: Only rebuilds changed packages
- Parallel execution: Independent tasks run concurrently
- Smart caching: Turborepo caches build outputs
Package Scripts
The rootpackage.json provides commands for the entire monorepo:
Technology Stack
Frontend Stack
| Technology | Purpose |
|---|---|
| SolidJS | Reactive UI framework (fine-grained reactivity) |
| Vite | Build tool and dev server |
| TailwindCSS | Utility-first styling |
| TanStack Query | Server state management |
| Firebase | Authentication (client SDK) |
| TypeScript | Type safety (v6.0 beta) |
/frontend/src/ts/
Backend Stack
| Technology | Purpose |
|---|---|
| Express.js | HTTP server framework |
| ts-rest | Type-safe API contracts |
| MongoDB | Primary database (user data, results) |
| Redis | Caching and leaderboards |
| Firebase Admin | Authentication verification |
| BullMQ | Background job queue |
| TypeScript | Type safety (v6.0 beta) |
/backend/src/
Shared Packages
@monkeytype/contracts- Type-safe API contracts using
@ts-rest/core - Shared between frontend and backend
- Ensures API type safety at compile time
- Zod schemas for runtime validation
- TypeScript types derived from schemas
- Used for users, results, configs, etc.
- Shared utility functions
- Date/time helpers, string manipulation
- Test mode and funbox definitions
- Shared game logic
System Architecture Diagram
Request Flow
A typical request flows through the system as follows:- Frontend: User action triggers API call via
@ts-rest/coreclient - Type Safety: Request matches contract definition from
@monkeytype/contracts - Backend: Express receives request at ts-rest endpoint
- Middleware Pipeline:
- Context middleware attaches request metadata
- Authentication verifies Firebase token or ApeKey
- Rate limiter checks request limits
- Validation ensures request schema matches contract
- Controller: Business logic processes the request
- DAL: Data access layer queries MongoDB or Redis
- Response: Type-safe response returned via contract
Authentication Flow
Key Design Principles
Type Safety
- End-to-end types: Types flow from schemas → contracts → frontend
- Runtime validation: Zod schemas validate at runtime
- Compile-time checks: TypeScript catches errors before deployment
Performance
- Redis caching: Frequent queries cached (leaderboards, configs)
- Lazy loading: Frontend code-splits by route
- Optimistic updates: UI updates before server confirmation
- PWA support: Service worker for offline capability
Scalability
- Horizontal scaling: Stateless backend servers
- Database indexing: MongoDB indices on common queries
- Queue system: BullMQ handles async jobs (emails, reports)
- CDN delivery: Static assets served from CDN
Development Workflow
Local Development
Build Pipeline
Next Steps
- Frontend Architecture - Deep dive into SolidJS structure
- Backend Architecture - API design and middleware
- Database Architecture - MongoDB and Redis usage