Development
Local setup, common commands, testing strategy, debugging tips.
1. Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Node.js | ≥ 20.x LTS | Runs the API |
| pnpm | ≥ 9 | Package management |
| Docker + Docker Compose | current | Runs Mongo + Mongo Express |
| A REST client | any | Talking to the API (Bruno, Insomnia, httpie, curl) |
No global Nest CLI is required — scripts in api/package.json invoke it via the local dependency.
2. First-time setup
From the repo root:
# 1. Copy env templates
cp .env.example .env
cp api/.env.example api/.env
# 2. Edit secrets (at minimum: MONGO_ROOT_PASSWORD, ME_PASSWORD,
# JWT_ACCESS_SECRET, JWT_REFRESH_SECRET once auth lands)
# 3. Start Mongo
docker compose up -d
# 4. Install API deps
cd api && pnpm install
# 5. Seed the database (once seed script exists)
pnpm seed
# 6. Run the API in watch mode
pnpm dev
The API listens on the port from PORT (default 4100). Mongo Express is at http://localhost:8083 using the credentials in the root .env.
3. Environment files
Two files, two purposes. Don't mix them.
| File | Consumed by | Contains |
|---|---|---|
/.env | docker-compose.yml | Mongo root creds, Mongo Express creds, DB_NAME, APP_SLUG (for container naming) |
/api/.env | The Nest process via ConfigModule | Everything the running API reads: PORT, MONGO_URI, APP_* branding, JWT_*, CORS_* |
Full variable list: CONFIG.md.
4. Common commands
All run from api/:
| Command | What it does |
|---|---|
pnpm dev | Start the API with file watch (nest start --watch) |
pnpm build | Compile TypeScript to dist/ |
pnpm start | Run the compiled output (node dist/main.js) |
pnpm seed | Seed the database with roles, the default surface, the platform list, and a default group |
pnpm test | Run unit tests |
pnpm test:e2e | Run integration tests against a real Mongo |
pnpm lint | Lint + typecheck (future) |
From the repo root:
| Command | What it does |
|---|---|
docker compose up -d | Start Mongo + Mongo Express |
docker compose down | Stop containers (preserve volumes) |
docker compose down -v | Stop and wipe the Mongo volume — destroys data |
./scripts/verify.sh | End-to-end smoke test (curl-based) |
./scripts/seed.sh | Seed demo roles + users |
./scripts/reset.sh | Nuke the volume and restart |
./scripts/gen-docs.sh | Regenerate docs-site/docs/generated/ + docs-site/docs/api-reference/ from source |
5. Mongo Express
http://localhost:8083, basic auth with ME_USER / ME_PASSWORD from the root .env. Useful for spot-checking data during development. Never expose it in production.
6. Seeding for development
api/scripts/seed.ts (future) is idempotent. Safe to re-run. It upserts:
- Roles:
admin,moderator,member. - A single surface:
{ slug: 'content', ... }. - A default group:
{ slug: 'general', surfaceSlug: 'content' }. - The starter platform list:
youtube,twitter,bluesky,reddit,article,generic. - A development admin user if
DEV_SEED_ADMIN_EMAIL+DEV_SEED_ADMIN_PASSWORDare set (never do this in prod).
Re-running after you've modified documents does NOT overwrite them — findOneAndUpdate({ upsert: true, setOnInsert: { ... } }) is used for records that should not be reset.
For the current (pre-content) sandbox, ./scripts/seed.sh seeds demo roles + users via the HTTP API.
7. Testing strategy
Three layers, each with a different purpose and speed budget.
Unit tests
- Target: pure functions (slug generation, URL→platform inference, scoring math), service methods with mocked repositories.
- Framework: Jest.
- Run:
pnpm test. - Fast — should stay under 10 seconds total for the whole suite.
Integration tests
- Target: controller + service + real Mongoose against a real (ephemeral) Mongo.
- Mechanism:
mongodb-memory-server(in-process) OR a short-livedtestcontainersMongo instance. - Run:
pnpm test:int. - Each test suite creates an isolated DB, seeds its fixtures, asserts, drops. No shared state.
- Don't mock Mongo — integration tests that mock the database are contract-lying.
End-to-end tests
- Target: HTTP surface. Boot the Nest app, issue real requests, assert envelope shape + status codes.
- Mechanism: supertest against
NestFactory.create(AppModule); Mongo via the same ephemeral strategy. - Run:
pnpm test:e2e. - Use for: auth flows, approval flows, catalog invalidation.
What NOT to test
- Mongoose schema defaults (Mongoose already tests its own library).
ValidationPipebehavior (Nest already tests its own library).- Purely presentational DTOs with no logic.
8. Debugging
NODE_OPTIONS='--inspect'beforepnpm devexposes a debugger on 9229; connect from VS Code (launch.jsonsnippet in the repo once it exists).- Mongoose query log:
mongoose.set('debug', true)inmain.ts(dev only) prints every query. X-Request-Id: every request gets one; it's in logs and inmeta.requestId. Match a failing response to server logs by this ID.- Slow query?
db.collection.explain('executionStats').find(...)in Mongo Express.
9. Common pitfalls
DTO validation doesn't fire.Make sure the property is on a class with@Expose()/@Type()where relevant, and that the controller argument is declared with the class type (notany).ObjectId vs string.Nest serializes ObjectIds to strings via.toJSON()automatically on.lean()results; in tests you may needtoString()to compare.Indexes not applied.Mongoose creates indexes lazily unlessautoIndex: true. Callmodel.syncIndexes()on boot in dev; production should use explicit scripts.Transactions silently fail.Mongo transactions require a replica set. The dev docker-compose uses a standalone — transactions will error. When implementing tag-rename, switch dev Mongo to a single-node replica set or mock the session in unit tests and test the real path in integration against a replica-set testcontainer.