housekeeping-service — LOCAL_DEV_SETUP
Stack: Node.js 20 LTS · NestJS · TypeScript strict · Postgres 15 (Docker) · Pub/Sub emulator · pnpm workspaces. Repo path:
apps/services/housekeeping-servicein the monorepo.
1. Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Node.js | 20.x LTS | nvm install 20 && nvm use 20 |
| pnpm | 9.x | corepack enable && corepack prepare pnpm@latest --activate |
| Docker Desktop | latest | Linux containers |
| Google Cloud SDK | latest | for gcloud beta emulators pubsub |
gcloud beta components | install | gcloud components install beta pubsub-emulator |
| OpenSSL | any | for self-signed certs |
| (optional) Postman / curl | latest | API smoke testing |
2. Clone & install
git clone git@github.com:melmastoon/platform.git
cd platform
pnpm install
cd apps/services/housekeeping-service
cp .env.example .env.local
3. Local containers (docker-compose.local.yml)
The compose file ships:
postgres(15-alpine) on:5432— DBhousekeeping_dev.pubsub-emulatoron:8085— pre-creates the topics and subscriptions for our consumed/published subjects.redison:6379— for Idempotencyjticache and short-TTL board cache.mailhogon:8025— for any notification stubs in dev.iam-stub— issues dev JWTs for local roles viaPOST /dev/token { role, tenantId, staffId, properties[] }.
Bring up:
pnpm run dev:up # docker compose -f docker-compose.local.yml up -d
pnpm run db:migrate
pnpm run db:seed # seeds tenants, properties, rooms, staff, checklists, sample tasks
Tear down:
pnpm run dev:down # docker compose -f docker-compose.local.yml down -v
4. Run the service
pnpm dev # nest start --watch on :3203
pnpm dev:relay # outbox relay, separate process
pnpm dev:scheds # local cron runner for the four schedulers
Health: curl http://localhost:3203/health/ready.
5. Get a dev JWT
TOKEN=$(curl -s http://localhost:4000/dev/token \
-H 'content-type: application/json' \
-d '{"role":"housekeeping_supervisor","tenantId":"tnt_dev","staffId":"stf_sup1","properties":["prp_dev1"]}' \
| jq -r .token)
6. Smoke test
# Create a turnover task
curl -s http://localhost:3203/api/v1/housekeeping/tasks \
-H "Authorization: Bearer $TOKEN" \
-H "X-Tenant-Id: tnt_dev" \
-H "Idempotency-Key: $(uuidgen)" \
-H 'content-type: application/json' \
-d '{"kind":"turnover","propertyId":"prp_dev1","roomId":"rom_dev1","priority":"high"}' | jq
# Read the board
curl -s http://localhost:3203/api/v1/housekeeping/board?propertyId=prp_dev1 \
-H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tnt_dev" | jq
7. Replay an upstream event
pnpm dev:emit reservation.checked_out.v1 \
--tenant tnt_dev --property prp_dev1 --room rom_dev2 --reservation rsv_dev1
This script publishes a synthetic envelope to the local Pub/Sub emulator. Watch the service logs for the consumer handler running and a turnover task appearing in the DB.
8. Tests
pnpm test # unit + contract (no docker required)
pnpm test:int # integration with testcontainers (Docker required)
pnpm test:int -- --runInBand --testPathPattern=tenant-isolation
pnpm test:cov # coverage
pnpm test:perf:smoke # 60-second k6 smoke
9. Database utilities
pnpm db:console # opens psql against housekeeping_dev
pnpm db:reset # drop + create + migrate + seed
pnpm db:diff # diff live schema vs migrations/
10. Common issues
| Symptom | Cause | Fix |
|---|---|---|
ECONNREFUSED 127.0.0.1:5432 | Postgres container not up | pnpm dev:up |
permission denied for table housekeeping.housekeeping_tasks | RLS without app.tenant_id set | confirm TenantContext middleware is on; in local SQL: SET app.tenant_id = 'tnt_dev' |
| Push subscription returns 401 | OIDC verifier strict in dev | dev mode bypasses OIDC if BYPASS_OIDC=1 is set in .env.local |
| Outbox not draining | Relay process not running | pnpm dev:relay |
| k6 perf smoke fails on cold runs | Cold start | rerun; min instances ignored locally |
11. Cross-link
- Repo conventions: monorepo
README.md. - Schema:
DATA_MODEL.md. - API:
API_CONTRACTS.md. - Events:
EVENT_SCHEMAS.md.