Skip to content

Boilerplate Repository Guide

Overview

The boilerplate repository serves as the initial project structure for all new gyms. It provides a fully configured Next.js 16 application with authentication, database management, Docker-based environments, and a consistent developer workflow — ready to clone and build on.

Single starting point

Every new gym should begin by cloning this repository. It ensures consistent architecture, tooling, and conventions across all OTS gyms.


Tech Stack

Layer Technology
Framework Next.js 16 (App Router)
Language TypeScript 5
Styling Tailwind CSS 4
Database PostgreSQL 18
ORM Prisma 7
State Management Zustand 5
Forms React Hook Form 7 + Zod resolvers
Auth Client-side Zustand (localStorage)
Containerization Docker
Deployment Vercel

What you get

  • Modern web stack: Next.js 16 (App Router) + TypeScript 5 + Tailwind CSS 4
  • Database: Prisma 7 + PostgreSQL 18
  • Fast onboarding: one-command bootstrap via npm run initialize
  • Data workflows: seed with npm run db:seed, or sync environments via npm run db -- sync ...
  • Deploy-ready: npm run vercel-build runs Prisma generate + migrations + build
  • Demo auth: client-side Zustand persisted to localStorage (useful for gyms; not production-grade auth)

Getting Started

Prerequisites

  • Node.js 22+
  • Docker (Docker Desktop or Docker Engine)
  • A GITHUB_TOKEN environment variable exported in your shell (a GitHub Personal Access Token with read:packages scope). The .npmrc uses it to install private packages from the @turing-rlgym GitHub Packages registry. Without it, npm install (and Docker builds) will fail.
  • A .env file at the project root (template below; see also Environment Variables)

Example:

export GITHUB_TOKEN="..."

.env required

The application reads configuration from .env. Use the template below for local development. If you need remote database credentials (for syncing or APP_ENV != local), request them from your team lead.

1) Create .env

Create a .env file at the project root:

APP_ENV=local
GYM_SLUG=boiler-plate

# Required for remote DB access (syncing or APP_ENV != local)
REMOTE_DB_USER=your_remote_db_user
REMOTE_DB_PASS=your_remote_db_password

Notes:

  • Local development uses APP_ENV=local and expects Postgres on localhost:5432.
  • Remote credentials (REMOTE_DB_USER, REMOTE_DB_PASS) are only required if you plan to sync from/to a remote environment, or connect directly to a remote DB (APP_ENV != local). For remote environments, the database name is derived from GYM_SLUG (e.g. ${GYM_SLUG}_prod).
  • If you change GYM_SLUG, make sure your local DB build/run workflow matches it (see the boilerplate repo’s docker/README.md).

2) Bootstrap everything (local Docker database)

One command to rule them all

Run the single initialization command below — it installs dependencies, generates the Prisma client, builds + starts a local Postgres container, runs the initial migration, and launches the dev server. This path is for APP_ENV=local. If you'd rather connect to a remote database instead, skip ahead to Connect to a Remote Database.

npm run initialize

This command runs six steps in sequence:

  1. npm install — installs all Node.js dependencies.
  2. npx prisma generate — generates the type-safe Prisma Client from the schema.
  3. npm run docker:build:db — builds a local PostgreSQL image (Dockerfile target: db).
  4. npm run docker:run:db — starts the local PostgreSQL container on port 5432.
  5. npx prisma migrate dev --name init — creates and applies the initial database migration.
  6. npm run dev — starts the Next.js development server at http://localhost:3000.

3) Put data in your database

After initialization, populate your local database. Choose the path that matches your situation:

If this is a brand-new project with no existing data, seed the database with sample flights:

npm run db:seed

If the project is already under active development and a remote database has data, pull it into your local container:

Configure .env first

Make sure your .env file has GYM_SLUG, REMOTE_DB_USER, and REMOTE_DB_PASS configured before syncing. Missing variables will cause authentication errors.

npm run db -- sync --from <env>   # e.g. dev, stg, prod

For the full DB sync guide (promotion chain, verification, data-only vs full), see scripts/README.md.

Connect to a Remote Database (without Docker)

If the project already has a remote database set up, you don't need Docker or npm run initialize at all. Simply change APP_ENV in your .env file to the desired remote environment and start the dev server:

# 1. In .env, set APP_ENV to one of: data, development, staging, production
# 2. Then run:
npm install
npx prisma generate
npm run dev

The app will connect directly to the corresponding remote database — no local container required. Use this when you want to develop against an existing remote dataset without any Docker setup.

APP_ENV=local is the only value that requires a local Docker DB

Setting APP_ENV=local connects to the local Docker database (what npm run initialize sets up). All other values (data, development, staging, production) connect to remote databases using the credentials in .env.


Scripts Reference

All scripts are defined in package.json and grouped by purpose below.

These commands build Docker images from the project's multi-stage Dockerfile. The build uses a GITHUB_TOKEN secret so npm ci can install private packages listed in .npmrc.

Image names are derived from GYM_SLUG

Docker image tags are derived from .env GYM_SLUG (for example: ${GYM_SLUG}-app:dev, ${GYM_SLUG}-db). You do not need to manually rename scripts when cloning the boilerplate.

Command What it builds Dockerfile target
npm run docker:build Development image with hot-reload support and full source code mounted (${GYM_SLUG}-app:dev) dev
npm run docker:build:prod Production-optimized image with a standalone Next.js build (${GYM_SLUG}-app:runner) runner
npm run docker:build:db Local PostgreSQL 18 image (${GYM_SLUG}-db) db
npm run docker:build:dist Self-contained distribution image (${GYM_SLUG}-app:dist) + a build-time DB snapshot dist

The dev target copies the full source and runs npm run dev. The runner target builds the app, then creates a minimal container with only the standalone output — no node_modules, no source code.

These commands start containers from previously built images.

Command Image Notes
npm run docker:run ${GYM_SLUG}-app:dev Dev app container (mounts your repo). Sets APP_ENV=local inside the container.
npm run docker:run:prod ${GYM_SLUG}-app:runner Production runner container. Uses APP_ENV from your .env to choose the database connection.
npm run docker:run:db ${GYM_SLUG}-db Local PostgreSQL container on localhost:5432. Container name is ${GYM_SLUG}-db.
npm run docker:run:dist ${GYM_SLUG}-app:dist Dist image with embedded Postgres initialized from a build-time snapshot (no credentials at runtime).
npm run docker:export:dist ${GYM_SLUG}-app:dist Exports the dist image to ${GYM_SLUG}-app-dist.tar.gz.

Volume mounts in dev mode

The docker:run (dev) command mounts three volumes:

  • $(pwd):/app — your local project directory is synced into the container.
  • /app/node_modules — an anonymous volume prevents the container's node_modules from being overwritten by your host.
  • /app/.next — an anonymous volume keeps the Next.js cache inside the container.

This means you can edit files locally and see changes reflected immediately without rebuilding.

These commands manage the Prisma schema and the PostgreSQL database. For deep-dive DB sync behavior, see scripts/README.md.

Command Purpose When to use
npx prisma generate Regenerates the Prisma Client (prisma/generated/). After any change to .prisma files.
npx prisma db push Pushes schema changes directly to the DB (no migration file). Local development only. Fast iteration — may drop data.
npx prisma migrate deploy Applies pending migrations from prisma/migrations/. Staging / production deployments (also runs during npm run vercel-build).
npx prisma studio Opens Prisma Studio at http://localhost:5555. Inspecting/editing data without writing queries.
npm run db:seed Populates the database with sample flight data. After a fresh DB setup or reset.
npm run db -- sync --from <env> Sync a source environment into a target (default target: local). Pulling remote data locally; promoting data through envs.

db:push may drop data

The npx prisma db push command applies schema changes directly without generating a migration file. This is convenient for local iteration but can cause data loss. Never use it against staging or production databases — use npx prisma migrate deploy instead.


Environment Variables

The application uses APP_ENV to determine which database to connect to at runtime. The connection URL is built dynamically by lib/build-database-url.ts using the variables in .env.

Never commit .env files

The .env file contains database credentials and secrets. It must remain in .gitignore and should never be committed to the repository.

Variable Purpose
APP_ENV Controls the active environment: local, data, development, staging, production.
GYM_SLUG Gym slug used to derive DB names (e.g. ${GYM_SLUG}_dev, ${GYM_SLUG}_prod) and local DB (${GYM_SLUG}-db).
REMOTE_DB_USER Shared database username for remote environments.
REMOTE_DB_PASS Shared database password for remote environments.

How APP_ENV routes the connection

When APP_ENV=local, the app connects to the local Docker database at postgresql://postgres:postgres@localhost:5432/${GYM_SLUG}-db. For all other environments, it builds a remote connection from REMOTE_DB_USER, REMOTE_DB_PASS, and a DB name derived from GYM_SLUG + an environment suffix (e.g. ${GYM_SLUG}_stg).


Project Structure

├── app/                      Next.js App Router (pages, layouts, API routes)
│   ├── api/flights/          Flight data API (GET with filters, pagination, sorting)
│   ├── api/admin/            Admin endpoints (health check, data management)
│   └── auth/                 Auth pages (login, register, forgot-password)
├── components/
│   ├── auth/                 Auth forms (LoginForm, RegisterForm, ForgotPasswordForm, LogoutButton)
│   ├── flights/              Flight UI (FlightsSection, FlightsTable, FlightsFilters, FlightsPagination)
│   ├── landing/              Landing page components (Header, Footer, NavigationBar, Content)
│   └── ui/                   Reusable primitives (Button, Card, Modal, TextInput)
├── data/initializers/        Default state values and seed data
├── lib/                      Shared utilities (auth, database, helpers)
├── prisma/
│   ├── schema/models/        Prisma model definitions (.prisma files)
│   ├── generated/            Auto-generated Prisma Client (do NOT edit)
│   ├── migrations/           SQL migration files
│   └── seed.ts               Database seeding script (flights)
├── scripts/                  Shell scripts for database sync workflows
├── store/                    Zustand stores (modal, users, auth)
├── types/                    Shared TypeScript type definitions
├── docker/                   Docker helper scripts (snapshot + dist entrypoint)
├── Dockerfile                Multi-stage build (dev, builder, runner, db, snapshot, dist)
├── prisma.config.ts          Prisma configuration (schema path, datasource URL)
└── package.json              Dependencies and all npm scripts

For deeper documentation on specific areas, see the README in each directory of the boilerplate repository:


Common Workflows

I just cloned the repo and the project is new

npm run initialize
npm run db:seed

I just cloned the repo and the project is already under development

Configure .env first

Make sure .env is configured (at minimum GYM_SLUG, REMOTE_DB_USER, REMOTE_DB_PASS) before syncing. See Environment Variables.

npm run initialize
npm run db -- sync --from dev       # or data, dev, stg, prod — whichever has the data you need

I'm starting my day and need to run the project

npm run docker:run:db       # start the local PostgreSQL container
npm run dev                 # start the Next.js dev server at http://localhost:3000

I want to test the production Docker image locally

npm run docker:build:prod
# Set APP_ENV in .env (data, development, staging, or production), then:
npm run docker:run:prod

I need production data locally

Configure .env first

Make sure .env is configured (at minimum GYM_SLUG, REMOTE_DB_USER, REMOTE_DB_PASS) before syncing. See Environment Variables.

npm run db -- sync --from prod

I want to inspect the database visually

npx prisma studio

I want to work against a remote database without Docker

# In .env, set APP_ENV to the desired environment (data, development, staging, or production)
npm install
npx prisma generate
npm run dev

I changed a Prisma model

npx prisma generate
npx prisma db push

I need to apply migrations to a remote database

Admin only

Applying migrations to remote databases should only be done by authorized team members.

APP_ENV=staging npx prisma migrate deploy
APP_ENV=production npx prisma migrate deploy

Troubleshooting

  • npm install fails (401/403): confirm GITHUB_TOKEN is exported and has read:packages access (required for private @turing-rlgym/* packages from GitHub Packages).
  • Docker errors: make sure Docker Desktop (or the Docker daemon) is running, then retry npm run initialize.
  • Port 5432 already in use: stop any local Postgres using that port, or adjust the port mapping in your DB run command (see docker/README.md).
  • Remote DB auth/hostname errors: verify GYM_SLUG, REMOTE_DB_USER, REMOTE_DB_PASS, and your network access to the remote database host.
  • App running in Docker + APP_ENV=local: localhost:5432 inside the app container is not the DB container. Recommended: run the app on your host (npm run dev) and keep Postgres in Docker, or connect to a remote DB (APP_ENV != local) / configure container networking.