Development Setup
Dev environment options, commands, environment variables, CI, git hooks, and the API key vault.
Collection of info about the codebase environment, setup and design choices. For the first-run walkthrough (dev container vs. local setup, seeding), see Getting Started - this page assumes you're already up and running and covers the commands, CI, and env vars you'll come back to as you keep working.
Commands
| Command | Description |
|---|---|
pnpm dev | Start the dev server with hot reload |
pnpm build | Production build |
pnpm start | Start the production server (requires a prior build) |
pnpm lint | Run ESLint |
pnpm format | Auto-format all files with Prettier |
pnpm format:check | Check formatting without writing (used in CI) |
pnpm db:generate | Generate migrations from schema changes |
pnpm db:migrate | Apply all pending migrations |
pnpm db:seed | Seed the 6 teams + a seed account (idempotent) |
pnpm db:reset | Drop and recreate the local database (blocked in production) |
pnpm db:studio | Open Drizzle Studio - visual database browser (dev only) |
pnpm test | Run the unit test suite once |
pnpm test:watch | Re-run tests on save (use while developing) |
pnpm test:ui | Open the Vitest browser UI |
pnpm test:coverage | Generate a coverage report |
CI & Git Hooks
Every push and PR runs ESLint, Prettier, a TypeScript check, and the Vitest suite in GitHub Actions, and every commit runs lint-staged + commitlint locally via Husky - see Code Quality Tooling for the full breakdown of what each workflow and hook does. Run pnpm check before pushing to catch what CI would catch without waiting on it.
Environment Variables
| Variable | Required | Description |
|---|---|---|
BETTER_AUTH_SECRET | Yes | Session signing secret - openssl rand -hex 32 |
VAULT_ENCRYPTION_KEY | Prod only | AES-256 key for vault secrets - openssl rand -hex 32 |
NEXT_PUBLIC_APP_URL | No | Public origin, e.g. http://localhost:3000 |
BETTER_AUTH_URL | No | Same as NEXT_PUBLIC_APP_URL |
BETTER_AUTH_TRUSTED_ORIGINS | No | Extra origins allowed to make auth requests (needed when accessing the dev server from a second machine on the LAN) |
DATABASE_PATH | No | Path to the SQLite file (default: ./db/dashboard.db) |
RESEND_API_KEY | No | Resend API key for transactional email |
EMAIL_FROM | No | Sender address, e.g. TrickFire Robotics <[email protected]> |
MINECRAFT_SERVER_HOST | No | Minecraft server hostname/IP (default: localhost) |
MINECRAFT_SERVER_PORT | No | Minecraft query port (default: 25565) |
MINECRAFT_SERVER_PATH | No | Absolute path to the Minecraft server directory |
MINECRAFT_WORLD_PATH | No | Absolute path to the world directory (for the playtime leaderboard) |
MINECRAFT_RCON_PORT | No | RCON port (default: 25575) |
MINECRAFT_RCON_PASSWORD | No | RCON password |
MINECRAFT_BOT_SKIN_URL | No | Skin URL applied to players detected as Carpet bots (real bot names come from the bots scoreboard team via RCON - see External Integrations) |
PL3XMAP_URL | No | Internal URL of the Pl3xMap web server, e.g. http://localhost:8080 |
TAILSCALE_API_KEY | No | Tailscale API key (admin console → Settings → Keys) |
TAILSCALE_TAILNET | No | Tailnet name, or - to auto-detect from the API key |
ONSHAPE_BASE_URL | No | OnShape API base URL |
ONSHAPE_ACCESS_KEY | No | OnShape access key |
ONSHAPE_SECRET_KEY | No | OnShape secret key |
ONSHAPE_COMPANY_ID | No | OnShape company ID (auto-detected from the access key if omitted) |
SIM_CACHE_DIR | No | Directory the simulation export proxy caches generated archives in (default: /var/cache/trickfire-sim) |
SIM_CACHE_MAX_ENTRIES | No | Max cached export archives before the oldest are evicted (default: 50) |
SIM_CACHE_TTL_DAYS | No | Days before a cached export archive expires (default: 7) |
SEED_ADMIN_EMAIL | No | Email for the seeded account |
SEED_ADMIN_PASSWORD | No | Password for the seeded account |
SEED_ADMIN_NAME | No | Display name for the seeded account |
GITHUB_ORG | No | GitHub organization name (e.g. trickfirerobotics) - enables the GitHub tab on the Members page |
GITHUB_TOKEN | No | Fine-grained PAT with Organization → Members: Read and write permission |
Danger
Never commit .env.local or .env.production. BETTER_AUTH_SECRET lets anyone forge session
tokens - if it leaks, rotate it immediately by changing the value and restarting the server (all
existing sessions are invalidated). Rotating or losing VAULT_ENCRYPTION_KEY makes every
existing vault entry permanently unrecoverable - back it up.
API Key Vault
The API Keys page is a shared credential vault to store third-party API keys and service logins. Any logged-in member can open the page and see what entries exist - reading a specific secret is the gated part, via a per-person grant set from that entry's Manage access action. There's no global "vault access" toggle and no bypass for any particular user.
Each entry is either a login (username + password, revealed in the browser on demand) or an api_key (never shown in the UI - retrieved only via the API endpoint below).
Fetching an API key - GET /api/vault/{id}/key
Authenticated by the caller's dashboard session cookie. Returns the key only if the user has been granted access to that entry.
| Status | Meaning |
|---|---|
200 | { "name": "Resend", "key": "re_live_..." } |
401 | Not logged in |
403 | Logged in but no access grant for this entry |
404 | Entry doesn't exist, or it is a login (use GET /api/vault/{id}/reveal instead) |
$ curl -s https://dashboard.trickfirerobotics.com/api/vault/12/key \
-H "Cookie: better-auth.session_token=<your-session-cookie>"Secrets are encrypted at rest with AES-256-GCM using VAULT_ENCRYPTION_KEY. In local dev, if that variable is unset, a key is auto-generated and saved to db/vault.key (gitignored).