Patient Chart Service — Local Dev Setup
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template
1. Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Node.js | 22 LTS | Runtime |
| pnpm | 9.x | Package manager |
| Docker Desktop | 4.x | Compose stack |
| kubectl | 1.29+ | Optional — K8s access |
| nats-cli | latest | NATS stream inspection |
2. Repository layout
Patient-chart-service lives in the application monorepo at services/patient-chart-service/. Documentation lives at d:/GhasiTech/ghasi-e-documentation/Ghasi-eHealth/services/patient-chart-service/.
3. docker-compose.yml (patient-chart dev stack)
version: "3.9"
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: patient_chart_dev
POSTGRES_USER: patient_chart_app
POSTGRES_PASSWORD: dev_password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./docker/init.sql:/docker-entrypoint-initdb.d/init.sql
nats:
image: nats:2.10-alpine
command: ["--jetstream", "--store_dir=/data"]
ports:
- "4222:4222"
- "8222:8222" # monitoring
volumes:
- nats_data:/data
terminology-service-mock:
image: mockserver/mockserver:latest
ports:
- "3020:1080"
environment:
MOCKSERVER_INITIALIZATION_JSON_PATH: /config/terminology.json
volumes:
- ./docker/mocks/terminology.json:/config/terminology.json
registration-service-mock:
image: mockserver/mockserver:latest
ports:
- "3000:1080"
volumes:
- ./docker/mocks/registration.json:/config/registration.json
ai-gateway-mock:
image: mockserver/mockserver:latest
ports:
- "3050:1080"
volumes:
- ./docker/mocks/ai-gateway.json:/config/ai-gateway.json
volumes:
postgres_data:
nats_data:
4. Environment variables (.env.example)
# App
NODE_ENV=development
PORT=3010
LOG_LEVEL=debug
# Database
DATABASE_URL=postgresql://patient_chart_app:dev_password@localhost:5432/patient_chart_dev
DATABASE_SCHEMA=patient_chart
# NATS
NATS_URL=nats://localhost:4222
NATS_STREAM_PATIENT_CHART=PATIENT_CHART
# Downstream services (mock ports for local)
TERMINOLOGY_SERVICE_URL=http://localhost:3020
REGISTRATION_SERVICE_URL=http://localhost:3000
AI_GATEWAY_URL=http://localhost:3050
PROVIDER_DIR_SERVICE_URL=http://localhost:3030
FACILITY_SERVICE_URL=http://localhost:3040
DOCUMENT_SERVICE_URL=http://localhost:3060
MEDICATION_SERVICE_URL=http://localhost:3070
LAB_SERVICE_URL=http://localhost:3080
RADIOLOGY_SERVICE_URL=http://localhost:3090
IMMUNIZATIONS_SERVICE_URL=http://localhost:3091
CARE_PLAN_SERVICE_URL=http://localhost:3092
# Keycloak (local dev — bypass with mock JWT)
KEYCLOAK_REALM_URL=http://localhost:8080/realms/dev
JWT_PUBLIC_KEY_PATH=./docker/dev-jwt-public.pem
# Telemetry
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=patient-chart-service
5. Start the dev stack
# 1. Clone monorepo
git clone <repo>
cd services/patient-chart-service
# 2. Install dependencies
pnpm install
# 3. Start dependencies
docker compose up -d postgres nats terminology-service-mock registration-service-mock ai-gateway-mock
# 4. Run DB migrations
pnpm db:migrate
# 5. Seed dev data
pnpm db:seed
# 6. Start service in watch mode
pnpm dev
6. Database migration commands
| Command | Description |
|---|---|
pnpm db:migrate | Apply pending Drizzle migrations |
pnpm db:migrate:dry | Show pending SQL without executing |
pnpm db:seed | Load dev seed data (synthetic patients, problems, allergies, vitals, notes) |
pnpm db:reset | Drop schema + re-run migrations + seed (dev only) |
pnpm db:studio | Open Drizzle Studio UI at localhost:4983 |
7. Common development commands
| Command | Description |
|---|---|
pnpm dev | NestJS watch mode |
pnpm build | TypeScript compile |
pnpm test | All tests (unit + integration) |
pnpm test:unit | Unit tests only |
pnpm test:integration | Integration tests (requires compose stack running) |
pnpm test:e2e | E2E tests against running service |
pnpm test:coverage | Coverage report |
pnpm lint | ESLint |
pnpm typecheck | tsc --noEmit |
8. Seed data overview
The seed script creates the following synthetic (non-PHI) data:
| Entity | Count | Notes |
|---|---|---|
| Tenants | 2 | ten_dev_a and ten_dev_b for tenant-isolation testing |
| Patients | 10 per tenant | Synthetic names; pat_dev_* prefix |
| Problems | 3–5 per patient | Mix of active, resolved, inactive |
| Allergies | 1–3 per patient | Includes 1 NKA patient |
| VitalsSets | 5–10 per patient | Last 30 days; normal and abnormal values |
| ClinicalNotes | 2–4 per patient | Mix of draft, signed, amended |
9. NATS stream inspection
# View messages in PATIENT_CHART stream
nats stream view PATIENT_CHART --count 10
# Publish a test event
nats pub patient_chart.problem.added.v1 '{"decisionId":"test","tenantId":"ten_dev_a"}'
# Check consumer lag
nats consumer info PATIENT_CHART audit-service-consumer
10. Troubleshooting
| Issue | Resolution |
|---|---|
DATABASE_URL connection refused | Ensure docker compose up -d postgres is running |
| Migration error: relation already exists | Run pnpm db:reset (dev only) |
| JWT validation fails | Check JWT_PUBLIC_KEY_PATH points to dev public key |
| Terminology service 503 | Verify mock container is running on port 3020 |
| Outbox events not publishing | Check NATS connection; inspect outbox table for unpublished rows |