Development Guide
Prerequisites
- Node.js 18+
- pnpm 8.15+ (
npm install -g pnpm) - PostgreSQL (or a Neon connection string)
- Clerk account (for auth keys)
- Spotify Developer account (for API credentials)
Setup
bash
# Clone and install all workspace dependencies
git clone <repo-url>
cd band-game
pnpm installEach app needs its own .env file. See Environment Variables for a complete per-app list.
Running the Apps
Use Turborepo to run all apps in parallel:
bash
# Run everything (server + client + admin + wiki)
pnpm dev
# Run a specific app
pnpm --filter @band-game/server dev
pnpm --filter @band-game/client dev
pnpm --filter @band-game/admin dev
pnpm --filter @band-game/wiki devShortcut scripts at the root:
bash
pnpm dev:server # server only
pnpm dev:client # client only
pnpm dev:admin # admin only
pnpm dev:all # all apps in parallel (same as pnpm dev)Default ports:
- Server:
3000 - Client (web):
8081(Expo) - Admin:
3001(Next.js) - Wiki:
5173(VitePress)
Database Migrations
Schema lives at apps/server/src/database/schema.ts. Migration SQL is generated into apps/server/drizzle/.
bash
# Generate SQL from schema changes
pnpm --filter @band-game/server db:generate
# Push schema to the database
pnpm --filter @band-game/server db:push
# Open Drizzle Studio (visual DB browser)
pnpm --filter @band-game/server db:studioThere is no seed script. There is no automatic migration step in the deploy pipeline — run db:push manually against the Neon connection string before or after deploying breaking schema changes.
Testing
Only the server has tests. Jest 29 + ts-jest, configured inline in apps/server/package.json.
bash
# Unit tests (*.spec.ts in src/)
pnpm --filter @band-game/server test
# Watch mode
pnpm --filter @band-game/server test:watch
# Coverage report
pnpm --filter @band-game/server test:cov
# E2E tests (apps/server/test/, separate jest config)
pnpm --filter @band-game/server test:e2eThe client and admin apps have no test suites.
Linting
Each app has its own ESLint config. Run all at once via Turborepo:
bash
pnpm lintOr per app:
bash
pnpm --filter @band-game/server lint # ESLint --fix (auto-fixes on run)
pnpm --filter @band-game/client lint # expo lint
pnpm --filter @band-game/admin lint # next lintESLint configs
Server (apps/server/eslint.config.mjs): typescript-eslint recommended + type-checked + eslint-plugin-prettier/recommended. Notable rule overrides:
| Rule | Setting |
|---|---|
@typescript-eslint/no-explicit-any | off |
@typescript-eslint/no-floating-promises | warn |
@typescript-eslint/no-unsafe-argument | warn |
The server lint command runs with --fix, so linting auto-repairs formatting issues.
Client (apps/client/eslint.config.js): eslint-config-expo/flat — Expo's default config.
Admin: Next.js built-in ESLint via next lint.
Prettier
Prettier is a dev dependency of the server and is enforced via eslint-plugin-prettier. There is no .prettierrc — Prettier defaults are used.
Pre-commit hooks
There are no pre-commit hooks. No Husky, no lint-staged.
TypeScript
bash
# Type-check the server
pnpm --filter @band-game/server tsc --noEmitKey TypeScript settings across the project:
| Setting | Value | Notes |
|---|---|---|
strict | true (root) | Base strictness on |
strictNullChecks | true (server) | Null safety enforced on server |
noImplicitAny | false | Implicit any permitted |
emitDecoratorMetadata | true | Required for NestJS DI |
experimentalDecorators | true | Required for NestJS decorators |
Building
bash
# Build all apps
pnpm build
# Build a specific app
pnpm --filter @band-game/server build # nest build → dist/
pnpm --filter @band-game/admin build # next build
pnpm --filter @band-game/wiki build # vitepress buildThere is no CI/CD pipeline. See Deployment for how Railway and EAS builds work.
Installing Packages
bash
# Add a dependency to a specific workspace
pnpm --filter @band-game/server add <package>
pnpm --filter @band-game/server add -D <package>Code Conventions
- TypeScript throughout —
no-explicit-anyis off but avoidanywhere possible - NestJS modules follow the standard module / service / gateway / controller pattern
- Drizzle ORM for all DB access — no raw SQL
- Clerk JWT validated on every authenticated REST endpoint; socket identity via
identifyevent only