Skip to main content

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-service in the monorepo.


1. Prerequisites

ToolVersionNotes
Node.js20.x LTSnvm install 20 && nvm use 20
pnpm9.xcorepack enable && corepack prepare pnpm@latest --activate
Docker DesktoplatestLinux containers
Google Cloud SDKlatestfor gcloud beta emulators pubsub
gcloud beta componentsinstallgcloud components install beta pubsub-emulator
OpenSSLanyfor self-signed certs
(optional) Postman / curllatestAPI 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 — DB housekeeping_dev.
  • pubsub-emulator on :8085 — pre-creates the topics and subscriptions for our consumed/published subjects.
  • redis on :6379 — for Idempotency jti cache and short-TTL board cache.
  • mailhog on :8025 — for any notification stubs in dev.
  • iam-stub — issues dev JWTs for local roles via POST /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

SymptomCauseFix
ECONNREFUSED 127.0.0.1:5432Postgres container not uppnpm dev:up
permission denied for table housekeeping.housekeeping_tasksRLS without app.tenant_id setconfirm TenantContext middleware is on; in local SQL: SET app.tenant_id = 'tnt_dev'
Push subscription returns 401OIDC verifier strict in devdev mode bypasses OIDC if BYPASS_OIDC=1 is set in .env.local
Outbox not drainingRelay process not runningpnpm dev:relay
k6 perf smoke fails on cold runsCold startrerun; min instances ignored locally