Billing Service — Local Dev Setup
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template
1. Prereqs
| Tool | Version |
|---|---|
| Node.js | 22.x LTS |
| pnpm | 9.x |
| Docker + Docker Compose | 24+ |
| psql client | 16 |
| nats-cli | latest |
2. Bootstrap
# From application monorepo root (D:\GhasiTech\Ghasi-edTech for edTech; Ghasi-eHealth app repo when created)
pnpm install
pnpm --filter @ghasi/service-billing build
3. docker-compose (dev stack)
# infra/dev/billing/docker-compose.yml
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: dev
POSTGRES_DB: billing_dev
ports: ["5435:5432"]
nats:
image: nats:2.10-alpine
command: ["-js"]
ports: ["4222:4222", "8222:8222"]
minio:
image: minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: dev
MINIO_ROOT_PASSWORD: devdevdev
ports: ["9000:9000", "9001:9001"]
redis:
image: redis:7-alpine
ports: ["6380:6379"]
docker compose -f infra/dev/billing/docker-compose.yml up -d
4. Env (.env.local)
PORT=3035
NODE_ENV=development
DATABASE_URL=postgres://postgres:dev@localhost:5435/billing_dev
NATS_URL=nats://localhost:4222
REDIS_URL=redis://localhost:6380
JWKS_URL=http://localhost:3010/.well-known/jwks.json
TENANT_SERVICE_URL=http://localhost:3011
TERMINOLOGY_SERVICE_URL=http://localhost:3012
FHIR_GATEWAY_URL=http://localhost:3020
OBJECT_STORE_ENDPOINT=http://localhost:9000
OBJECT_STORE_BUCKET=billing-dev
OBJECT_STORE_ACCESS_KEY=dev
OBJECT_STORE_SECRET_KEY=devdevdev
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
LOG_LEVEL=debug
5. Run
pnpm --filter @ghasi/service-billing drizzle:migrate
pnpm --filter @ghasi/service-billing seed
pnpm --filter @ghasi/service-billing dev
The seed script loads one tenant (ten_dev), one facility (fac_dev), a published price list, one tax rule, one patient account, and a dummy encounter.
6. Common commands
| Command | Purpose |
|---|---|
pnpm --filter @ghasi/service-billing test | Unit tests |
pnpm --filter @ghasi/service-billing test:integration | Integration (requires docker stack) |
pnpm --filter @ghasi/service-billing test:e2e | E2E revenue cycle |
pnpm --filter @ghasi/service-billing typecheck | tsc --noEmit |
pnpm --filter @ghasi/service-billing lint | ESLint with import-restriction |
pnpm --filter @ghasi/service-billing drizzle:generate | Generate migration |
pnpm --filter @ghasi/service-billing seed:reset | Reset and reseed dev DB |
7. Smoke test
# Capture charge
TOKEN=$(./scripts/dev-token.sh ten_dev billing_clerk)
curl -sS -X POST http://localhost:3035/charges \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"patientId":"pat_dev_001",
"encounterId":"enc_dev_001",
"facilityId":"fac_dev",
"serviceDate":"2026-04-17",
"items":[{"code":{"system":"CPT","code":"99213"},"units":1,"modifiers":[]}]
}' | jq
# Post payment
curl -sS -X POST http://localhost:3035/payments \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"accountId":"acc_dev_001","method":"CASH","amount":{"currency":"AFN","minor_units":250000}}' | jq
8. Tearing down
docker compose -f infra/dev/billing/docker-compose.yml down -v