Development Setup¶
Prerequisites¶
| Tool | Minimum Version | Check Command |
|---|---|---|
| Node.js | 20.0.0 | node --version |
| pnpm | 9.0.0 | pnpm --version |
| Docker | 24.0.0 | docker --version |
| Docker Compose | 2.20.0 | docker compose version |
First-Time Setup¶
# Clone the repo
git clone <repo-url>
cd meterplex
# Install dependencies
pnpm install
# Copy environment template
cp .env.example .env
# Start infrastructure
pnpm docker:up
# Wait for containers to be healthy (~15 seconds)
docker compose ps
# Run database migrations
pnpm prisma:migrate:dev
# Seed development data
pnpm prisma:seed
# Start the app
pnpm start:dev
Verify Everything Works¶
# Health check (should return status: ok)
curl http://localhost:3000/health | jq
# Swagger docs (open in browser)
open http://localhost:3000/api/docs
# Check database has seed data
docker compose exec postgres psql -U meterplex -d meterplex -c "SELECT name, slug FROM tenants"
Daily Workflow¶
# Start your day
pnpm docker:up # Start containers (if stopped)
pnpm start:dev # Start app with hot reload
# After changing schema.prisma
pnpm prisma:migrate:dev --name describe-your-change
pnpm prisma:generate # Regenerate typed client
# Nuclear reset (drops all data, re-runs everything)
pnpm docker:down # Removes containers AND volumes
pnpm docker:up
pnpm prisma:migrate:dev
pnpm prisma:seed
Common Issues¶
Port 5432 already in use¶
You have a local Postgres installation competing with Docker. Stop it:
Prisma "exports is not defined in ES module scope"¶
The Prisma client was generated without moduleFormat = "cjs". Fix:
Prisma "role does not exist"¶
Docker volume has stale data from a previous run with different credentials:
Environment Variables¶
All environment variables are documented in .env.example. The app validates every variable on startup — if any required variable is missing, the app crashes immediately with a clear error listing exactly what's missing.
See src/config/env.validation.ts for the validation schema.
Conventions¶
File Naming¶
- Files:
kebab-case.ts(e.g.,correlation-id.middleware.ts) - Classes:
PascalCase(e.g.,CorrelationIdMiddleware) - Barrel exports:
index.tsin each module folder
Import Aliases¶
| Alias | Resolves To |
|---|---|
@common/* |
src/common/* |
@config/* |
src/config/* |
@modules/* |
src/modules/* |
Database Conventions¶
- Table names:
snake_caseplural (e.g.,tenants) - Column names:
snake_case(e.g.,created_at) - Primary keys: UUID v4 (Postgres native
uuidtype) - Prisma models:
PascalCasesingular with@@map()for table name - Prisma fields:
camelCasewith@map()for column name