Skip to main content

LOCAL_DEV_SETUP — theme-config-service

Sibling: DEPLOYMENT_TOPOLOGY · TESTING_STRATEGY

Platform anchors: docs/standards/SERVICE_TEMPLATE.md

This guide walks a new engineer from a clean machine to "service running locally with seeded data, hot reload, and tests green" in under 30 minutes.


1. Prerequisites

ToolVersionWhy
Node.js22.x LTSruntime
pnpm9.xmonorepo package manager
Docker25+local Postgres/Redis/emulators
Docker Compose v22.27+service stack
GCP CLI (gcloud)latestoptional — only for live integration
direnv2.34+env-var loading
psql16.xDB inspection
redis-cli7.xcache inspection
mkcertlatestlocal TLS for mTLS endpoints

Repository root scripts assume bash/zsh; Windows users should use WSL2.


2. Repository layout

ghasi-melmastoon/
├── services/
│ └── theme-config-service/
│ ├── src/
│ │ ├── domain/
│ │ ├── application/
│ │ │ ├── ports/
│ │ │ ├── use-cases/
│ │ │ └── queries/
│ │ ├── infrastructure/
│ │ │ ├── adapters/
│ │ │ ├── persistence/
│ │ │ └── messaging/
│ │ ├── interface/
│ │ │ ├── http/
│ │ │ └── workers/
│ │ └── main.ts
│ ├── test/
│ ├── prompts/
│ ├── evals/
│ ├── contracts/
│ ├── openapi/
│ ├── runbooks/
│ ├── observability/
│ ├── tools/
│ ├── docker-compose.local.yml
│ ├── package.json
│ ├── tsconfig.json
│ └── README.md
└── packages/
├── domain-primitives/
├── eventing/
├── observability/
└── testing-helpers/

3. Bootstrap

git clone https://github.com/ghasi/melmastoon ghasi-melmastoon
cd ghasi-melmastoon
pnpm install
cp services/theme-config-service/.env.example services/theme-config-service/.env.local
direnv allow

.env.local defaults are safe for the local Docker stack (no real GCP credentials required).


4. Local Docker stack

cd services/theme-config-service
docker compose -f docker-compose.local.yml up -d

Started containers:

ContainerPortPurpose
theme-pg5432Postgres 16
theme-pgbouncer6432pooler (optional; service can use 5432 directly)
theme-redis6379Memorystore stand-in
theme-pubsub8085Pub/Sub emulator
theme-gcs4443fake-gcs-server
theme-cdn-mock8089mock CDN invalidation API
theme-ai-mock8090AI orchestrator stub (cassettes)
theme-otel4318OTel collector to local Jaeger + Prom

Healthcheck: pnpm run dev:health waits until all containers report ready.


5. Database

pnpm run db:create # creates 'theme_config' database + roles
pnpm run db:migrate # applies Drizzle migrations
pnpm run db:seed # platform default scaffold + 3 demo tenants
pnpm run db:rls:verify # asserts RLS policies present on every tenant-scoped table

Demo tenants:

TenantDefault localeTheme aestheticNotes
tnt_dev_kabul_continentalps-AFwarm earth, primary #0F4C81RTL+LTR mix, 3 content blocks
tnt_dev_panjsher_lodgefa-AFmountain palette, primary #13A3A1RTL, video-hero variant
tnt_dev_test_chain_phase2en-USminimalLTR, used to exercise property-scoped Phase 2

Each tenant has one published version + one draft so the editor surface has something to render.


6. Run the service

pnpm run dev # NestJS hot reload on http://localhost:7041
pnpm run dev:workers # spawns outbox-publisher + inbox-consumers + sweeper jobs in one process

OpenAPI: http://localhost:7041/docs. Health: http://localhost:7041/healthz. Metrics: http://localhost:7041/metrics.


7. Useful scripts

CommandWhat it does
pnpm run lintESLint + Prettier check
pnpm run typechecktsc --noEmit
pnpm run testVitest unit + application tests
pnpm run test:integrationVitest integration with Testcontainers
pnpm run test:httpsupertest HTTP suite
pnpm run test:contract:openapispectral against the platform ruleset
pnpm run test:contract:eventsajv against event fixtures
pnpm run test:evals -- palette.contrastrun a specific AI eval suite
pnpm run db:resetdrop + recreate + migrate + seed
pnpm run pubsub:tail melmastoon.theme.eventstail the local emulator
pnpm run gcs:lslist local fake-gcs bundles
pnpm run cli:publish-demopublishes a sample new draft to exercise the full flow
pnpm run cli:build-bundle <versionId>builds & prints the bundle JSON without persisting
pnpm run openapi:generateregenerates openapi/theme-config-service.openapi.yaml
pnpm run openapi:diffdiffs against main's spec; fails on breaking change

8. Frontend integration (optional)

To exercise authoring against the local backoffice:

cd ../bff-backoffice-service && pnpm run dev
cd ../../apps/backoffice-console && pnpm run dev

The console points at http://localhost:7041 by default in apps/backoffice-console/.env.local.

To see the public booking flow render the published bundle:

cd apps/booking-flow && pnpm run dev # opens http://localhost:5173

The booking flow reads http://localhost:7041/public/themes/<themeId>/published.json.


9. Working with AI surfaces

The theme-ai-mock container replays cassettes from services/theme-config-service/evals/cassettes/. To record new cassettes against the real orchestrator:

export AI_MODE=record
export AI_ORCHESTRATOR_URL=https://ai-orchestrator.dev.melmastoon.app
gcloud auth print-identity-token # for orchestrator mTLS
pnpm run dev

Generated cassettes go into evals/cassettes/<surface>/<test-name>.json and should be committed.


10. Common gotchas

  • app.tenant_id not set: queries return zero rows due to RLS. Use withTenantCtx(...) in tests; in REPL set SET app.tenant_id = 'tnt_dev_kabul_continental'; first.
  • OCC mismatch in tests: the test builder aTheme().buildPersisted() returns the saved aggregate; use that, not the input.
  • Bundle SHA differs across runs: check Node version; the canonicaliser depends on stable JSON ordering. Re-run after nvm use.
  • Pub/Sub emulator port collision: ensure no other Pub/Sub emulator is running (lsof -i :8085).
  • Memorystore connection refused: the local Redis sometimes takes ~ 3 s to listen; the dev script retries.
  • Time-zone surprises: all timestamps are UTC; if the editor shows a wrong "published at", the issue is likely the BFF, not this service.

11. Editor setup

  • VS Code extensions: ms-azuretools.vscode-docker, bradlc.vscode-tailwindcss (for the editor app, not this service), Vitest.explorer, Prisma.prisma (for DB schema viewing only).
  • Recommended .vscode/settings.json:
    {
    "editor.formatOnSave": true,
    "eslint.workingDirectories": [{ "pattern": "services/theme-config-service" }],
    "vitest.commandLine": "pnpm run test --"
    }

12. Where to go next


13. References