Skip to content

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 install

Each 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 dev

Shortcut 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:studio

There 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:e2e

The client and admin apps have no test suites.

Linting

Each app has its own ESLint config. Run all at once via Turborepo:

bash
pnpm lint

Or 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 lint

ESLint configs

Server (apps/server/eslint.config.mjs): typescript-eslint recommended + type-checked + eslint-plugin-prettier/recommended. Notable rule overrides:

RuleSetting
@typescript-eslint/no-explicit-anyoff
@typescript-eslint/no-floating-promiseswarn
@typescript-eslint/no-unsafe-argumentwarn

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 --noEmit

Key TypeScript settings across the project:

SettingValueNotes
stricttrue (root)Base strictness on
strictNullCheckstrue (server)Null safety enforced on server
noImplicitAnyfalseImplicit any permitted
emitDecoratorMetadatatrueRequired for NestJS DI
experimentalDecoratorstrueRequired 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 build

There 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-any is off but avoid any where 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 identify event only