Config Service — Local Dev Setup
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template
1. Prerequisites
| Tool | Version |
|---|---|
| Node.js | 22 LTS |
| pnpm | 9.x |
| Docker + Docker Compose | 24+ |
| PostgreSQL client (psql) | 16 (for manual queries) |
2. docker-compose.yml (config-service dev stack)
version: "3.9"
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: ghasi_config
POSTGRES_USER: ghasi
POSTGRES_PASSWORD: ghasi_dev
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
command: redis-server --requirepass redis_dev
nats:
image: nats:2.10-alpine
ports:
- "4222:4222"
- "8222:8222"
command: --jetstream
config-service:
build:
context: .
dockerfile: Dockerfile.dev
environment:
DATABASE_URL: postgres://ghasi:ghasi_dev@postgres:5432/ghasi_config
REDIS_URL: redis://:redis_dev@redis:6379
NATS_URL: nats://nats:4222
PORT: 3015
NODE_ENV: development
IDENTITY_JWT_ISSUER: http://keycloak:8080/realms/ghasi-dev
HIERARCHY_SERVICE_URL: http://facility-service:3010
PLATFORM_ADMIN_SERVICE_URL: http://platform-admin-service:3011
ACCESS_POLICY_SERVICE_URL: http://access-policy:3005
IDENTITY_SERVICE_URL: http://identity-service:3001
ports:
- "3015:3015"
depends_on:
- postgres
- redis
- nats
volumes:
postgres_data:
3. Environment Variables
Copy .env.example to .env:
DATABASE_URL=postgres://ghasi:ghasi_dev@localhost:5432/ghasi_config
REDIS_URL=redis://:redis_dev@localhost:6379
NATS_URL=nats://localhost:4222
PORT=3015
NODE_ENV=development
IDENTITY_JWT_ISSUER=http://localhost:8080/realms/ghasi-dev
HIERARCHY_SERVICE_URL=http://localhost:3010
PLATFORM_ADMIN_SERVICE_URL=http://localhost:3011
ACCESS_POLICY_SERVICE_URL=http://localhost:3005
IDENTITY_SERVICE_URL=http://localhost:3001
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
All env vars are validated at startup via Zod in src/infrastructure/config/env.ts. Service fails fast if any required var is missing.
4. Common Commands
# Start all dependencies
docker compose up -d postgres redis nats
# Install dependencies
pnpm install
# Run database migrations
pnpm db:migrate
# Seed platform GLOBAL node + system roles
pnpm db:seed
# Start in development mode (hot reload)
pnpm dev
# Run unit tests
pnpm test:unit
# Run integration tests (requires docker compose running)
pnpm test:integration
# Run all tests
pnpm test
# Check coverage
pnpm test:coverage
# Lint + type check
pnpm lint && pnpm typecheck
5. Seed Data
The seed script (scripts/seed-dev.ts) creates:
| Seed item | Details |
|---|---|
| GLOBAL ConfigNode | Platform root |
| TENANT ConfigNode | ten_afg_moph_001 (Afghanistan MoPH) |
MODULE: CLIN-MEDS | Medications module |
MODULE: CLIN-NOTES | Clinical notes module |
Features: ViewMedications, PrescribeMedication, ManageClinicalNotes | Standard feature set |
Roles: ClinicalStaff (abstract), NURSE, PHYSICIAN | Standard role hierarchy |
| RoleInheritance: NURSE → ClinicalStaff, PHYSICIAN → ClinicalStaff | — |
Design tokens: MoPH branding (brand.primary: #006600, RTL direction) | Afghan MoPH theme |
UserNodeOverride: nurse1 explicit allow for medication:write at ward_a | Test scenario |
6. Testing with curl
# Resolve a permission (internal endpoint — no Kong in local dev)
curl "http://localhost:3015/internal/config/resolve?userId=usr_nurse_001&tenantId=ten_afg_moph_001&nodeId=cfgn_sdk_ward_a&moduleKey=CLIN-MEDS&featureKey=ViewMedications&action=medication:read&includeUI=true&includeTokens=true" \
-H "Authorization: Bearer <dev-jwt>"