Skip to main content

LOCAL_DEV_SETUP — bff-consumer-service

Sibling: DEPLOYMENT_TOPOLOGY · TESTING_STRATEGY · DATA_MODEL

1. Prerequisites

ToolVersionNotes
Node.js20.x LTSUse nvm / fnm; engines.node = "20.x" enforced in package.json
pnpm9.xWorkspace package manager
Docker DesktoplatestRequired for Postgres + Redis
Docker Composev2Bundled with Docker Desktop
Google Cloud SDKlatestFor impersonating bff-consumer-sa against staging when needed
mkcertlatestLocal TLS for cookie Secure flag testing
gh CLIlatestPR helpers

Repository: this BFF lives in the future application monorepo at services/bff-consumer-service/. The 17 markdown specs live in this documentation repo.

2. One-time setup

# Clone (application monorepo, future state)
gh repo clone ghasitech/ghasi-melmastoon
cd ghasi-melmastoon

# Install workspace
pnpm install --frozen-lockfile

# Set up local TLS for cookie Secure flag testing
mkcert -install
mkcert -cert-file ./certs/local.pem -key-file ./certs/local-key.pem \
bff-consumer.local.melmastoon.test localhost

# Bootstrap env file
cp services/bff-consumer-service/.env.example services/bff-consumer-service/.env.local

Edit .env.local and fill in:

NODE_ENV=development
PORT=8081
LOG_LEVEL=debug

DATABASE_URL=postgres://bff_consumer:bff_consumer@localhost:5440/bff_consumer
REDIS_URL=redis://localhost:6390/0

PUBSUB_PROJECT_ID=local
PUBSUB_EMULATOR_HOST=localhost:8085

BFF_CONSUMER_HANDOFF_HMAC_KEY_CURRENT=dev-rotating-key-do-not-ship-001
BFF_CONSUMER_HANDOFF_HMAC_KEY_PREVIOUS=
BFF_CONSUMER_PEPPER=dev-pepper-do-not-ship
BFF_CONSUMER_RECAPTCHA_SECRET=test-key

UPSTREAM_SEARCH_BASE_URL=http://localhost:8090
UPSTREAM_PRICING_BASE_URL=http://localhost:8091
UPSTREAM_PROPERTY_BASE_URL=http://localhost:8092
UPSTREAM_THEME_BASE_URL=http://localhost:8093
UPSTREAM_TENANT_BASE_URL=http://localhost:8094
UPSTREAM_BFF_TENANT_BOOKING_BASE_URL=http://localhost:8082

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

3. Stand up dependencies

docker compose -f services/bff-consumer-service/docker-compose.dev.yml up -d
# Brings up:
# postgres (5440 → 5432) seeded with tenants, properties, theme peek
# redis (6390 → 6379)
# pubsub-emulator (8085)
# wiremock-search-aggregation (8090) — pre-recorded fixtures
# wiremock-pricing (8091)
# wiremock-property (8092)
# wiremock-theme (8093)
# wiremock-tenant (8094)
# wiremock-bff-tenant (8082) — minimal stub for handoff handshake
# otel-collector + jaeger-ui (16686)

4. Run the service

pnpm --filter @ghasi/service-bff-consumer dev
# starts in watch mode on http://bff-consumer.local.melmastoon.test:8081

Smoke check:

curl -k https://bff-consumer.local.melmastoon.test:8081/bff/consumer/v1/health/ready
curl -k -c /tmp/c.jar -b /tmp/c.jar -H 'Accept-Language: ps-AF' \
-H 'Content-Type: application/json' \
-X POST https://bff-consumer.local.melmastoon.test:8081/bff/consumer/v1/search \
-d '{"geo":{"mode":"city","cityId":"city_kabul"},"checkIn":"2026-05-20","checkOut":"2026-05-22","occupancy":{"adults":2,"children":0,"rooms":1}}'

Trace appears in Jaeger UI at http://localhost:16686.

5. Common commands

CommandPurpose
pnpm --filter @ghasi/service-bff-consumer devRun with hot reload
pnpm --filter @ghasi/service-bff-consumer test:unitVitest unit tests
pnpm --filter @ghasi/service-bff-consumer test:integrationVitest + Testcontainers
pnpm --filter @ghasi/service-bff-consumer test:contractPact consumer + provider
pnpm --filter @ghasi/service-bff-consumer lintESLint + import-boundary rules
pnpm --filter @ghasi/service-bff-consumer typechecktsc --noEmit
pnpm --filter @ghasi/service-bff-consumer migrateDrizzle migrations against local Postgres
pnpm --filter @ghasi/service-bff-consumer migrate:make <name>Generate new migration
pnpm --filter @ghasi/service-bff-consumer seedSeed dev data (tenants, properties, fixture pages)
pnpm --filter @ghasi/service-bff-consumer openapiRegenerate openapi.json from controllers
pnpm --filter @ghasi/service-bff-consumer buildProduction build
docker compose -f services/bff-consumer-service/docker-compose.dev.yml logs -fTail dependencies

6. Working against real upstreams (staging)

For high-fidelity composition tests, point the BFF at staging upstreams while still running locally:

gcloud auth application-default login
gcloud auth print-identity-token --impersonate-service-account=bff-consumer-sa@melmastoon-stage.iam.gserviceaccount.com

# In .env.local override:
UPSTREAM_SEARCH_BASE_URL=https://search-agg.staging.melmastoon.internal
UPSTREAM_PRICING_BASE_URL=https://pricing.staging.melmastoon.internal
# ...
USE_GOOGLE_ID_TOKEN=true

Cloud Armor allow-lists the developer IP for the staging-internal ingress so this works from a corp network.

7. Seed data

pnpm seed populates:

  • 5 tenants (tnt_kabul_grand, tnt_herat_bazaar, tnt_mazar_pearl, tnt_jalalabad_orchard, tnt_bamiyan_cliff).
  • 60 properties across the 5 tenants.
  • 12 theme peeks (one per random property + 5 tenants).
  • 200 wishlist rows distributed across 30 anonymous sessions.
  • 1 active marketing campaign attribution (spring-2026).
  • 50 telemetry rows in the outbox awaiting drain.

The Pub/Sub emulator topics are auto-created on first publish.

8. Useful local URLs

URLPurpose
https://bff-consumer.local.melmastoon.test:8081/bff/consumer/v1/health/readyReadiness
http://localhost:16686Jaeger trace explorer
http://localhost:8025(optional) Mailhog if SMTP testing wired
http://localhost:8090/__adminWireMock admin for search-aggregation-service stubs

9. Resetting state

docker compose -f services/bff-consumer-service/docker-compose.dev.yml down -v
docker compose -f services/bff-consumer-service/docker-compose.dev.yml up -d
pnpm --filter @ghasi/service-bff-consumer migrate
pnpm --filter @ghasi/service-bff-consumer seed

10. Troubleshooting

SymptomLikely causeFix
ECONNREFUSED on PostgresPort collision (another Postgres on 5440)Change services/bff-consumer-service/docker-compose.dev.yml port mapping
Cookie not set on curlSecure flag rejected on plain HTTPUse https URL with mkcert cert or curl -k
WireMock fixture missing for upstream callNew endpoint not stubbedAdd fixture to services/bff-consumer-service/test/fixtures/wiremock/<service>/; restart compose
JWT key not configured startup fail.env.local missing BFF_CONSUMER_HANDOFF_HMAC_KEY_CURRENTRe-copy from .env.example
Pact verification fails locallyStale pact in broker; pull latestpnpm test:contract -- --pull-pacts