compliance-engine — Local Development Setup
Status: populated | Last updated: 2026-04-18
1. Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Node.js | 20 LTS+ | Runtime |
| pnpm | 9+ | Package manager |
| Docker Desktop | 24+ | Postgres, Redis, NATS containers |
| grpcurl | latest | gRPC testing |
| mkcert | latest | Local mTLS certs |
2. Clone and Install
git clone git@github.com:ghasi/sms-gateway.git
cd sms-gateway/services/compliance-engine
pnpm install
3. Start Infrastructure
Use the monorepo's shared docker-compose.yml from the repo root:
# From repo root
docker compose up -d postgres redis nats
This starts:
- PostgreSQL on
localhost:5432(user:ghasi, password:ghasi_dev) - Redis on
localhost:6379 - NATS JetStream on
localhost:4222
4. Database Setup
# From services/compliance-engine
pnpm prisma migrate dev --name init_compliance_schema
pnpm prisma db seed
The seed script populates:
- Default rule set (
is_default = true) - Platform-level example rules (keyword, regex, geo-restriction)
- Sample keyword lists (gambling, phishing, fraud — English only for dev)
- Mock tenant compliance scores
5. Environment Variables
Create .env.local in services/compliance-engine/:
NODE_ENV=development
LOG_LEVEL=debug
GRPC_PORT=50052
HTTP_PORT=3002
DATABASE_URL=postgresql://ghasi:ghasi_dev@localhost:5432/ghasi_dev?schema=compliance
REDIS_URL=redis://localhost:6379/3
NATS_URL=nats://localhost:4222
# Disable mTLS for local dev
GRPC_TLS_ENABLED=false
# AI mock mode — no real LLM calls
AI_PROVIDER=mock
ANONYMIZE_BODY_BEFORE_AI=false
EVAL_BUDGET_MS=450
HOLD_QUEUE_TTL_HOURS=24
SCORING_INTERVAL_MINUTES=15
To test against a real local LLM (requires local vLLM or Ollama):
AI_PROVIDER=local
LOCAL_LLM_URL=http://localhost:8000
LOCAL_LLM_MODEL=llama-3.1-8b-instruct-awq
To test against external LLM as failover:
AI_PROVIDER=local
AI_FAILOVER_PROVIDER=claude
AI_API_KEY=<your Claude API key>
AI_MODEL=claude-haiku-4-5-20251001
6. Run the Service
# Development with hot reload
pnpm start:dev
# Or run in debug mode
pnpm start:debug
Service logs appear in the terminal. Health endpoints:
http://localhost:3002/healthhttp://localhost:3002/readyhttp://localhost:3002/metrics
7. Test the gRPC Endpoint
# Using grpcurl with the proto file
grpcurl -plaintext \
-proto src/proto/compliance.proto \
-d '{
"message_id": "00000000-0000-4000-8000-000000000001",
"tenant_id": "00000000-0000-4000-8000-000000000002",
"account_id": "00000000-0000-4000-8000-000000000003",
"to": "+93701234567",
"from_id": "GhasiDev",
"body": "Your OTP is 123456",
"message_type": "SMS",
"segments": 1,
"encoding": "GSM7",
"idempotency_key": "local-test-1"
}' \
localhost:50052 \
ghasi.sms.compliance.v1.ComplianceService/EvaluateCompliance
Expected response:
{
"evaluationId": "...",
"verdict": "ALLOW",
"findings": [],
"ruleSetId": "...",
"evaluationLatencyMs": "8"
}
Try a blocked keyword:
# Body contains "casino" which is in the seeded gambling keyword list
grpcurl -plaintext \
-proto src/proto/compliance.proto \
-d '{
...
"body": "Win at CASINO today!"
}' \
localhost:50052 \
ghasi.sms.compliance.v1.ComplianceService/EvaluateCompliance
Expected: verdict: "BLOCK" with a KEYWORD finding.
8. Test the REST API
# List rules
curl -H "Authorization: Bearer $DEV_JWT" \
http://localhost:3002/compliance/rules
# List hold queue
curl -H "Authorization: Bearer $DEV_JWT" \
"http://localhost:3002/compliance/hold-queue?status=PENDING"
# Review a held message
curl -X POST \
-H "Authorization: Bearer $DEV_JWT" \
-H "Content-Type: application/json" \
-d '{"action": "RELEASE", "notes": "manual verification - legitimate OTP"}' \
http://localhost:3002/compliance/hold-queue/{holdId}/review
# Get tenant ranking
curl -H "Authorization: Bearer $DEV_JWT" \
http://localhost:3002/compliance/tenants
A dev JWT can be generated via pnpm token:dev — this uses a pre-signed dev JWKS from auth-service.
9. Running Tests
# Unit tests (fast)
pnpm test
# Unit tests with coverage
pnpm test:cov
# Integration tests (requires Docker running)
pnpm test:integration
# Watch mode
pnpm test:watch
# E2E tests
pnpm test:e2e
10. Database Migrations
# Create a new migration
pnpm prisma migrate dev --name add_new_rule_type_enum
# Apply pending migrations
pnpm prisma migrate deploy
# Reset and reseed (destructive)
pnpm prisma migrate reset
11. Helpful Dev Commands
# Seed a new test rule
pnpm seed:rule --type=KEYWORD --action=BLOCK --keywords="test1,test2"
# Trigger a scoring cycle manually (useful for testing tier transitions)
pnpm scoring:run
# Clear Redis caches
pnpm cache:clear
# Tail structured logs
pnpm logs:tail | jq
# Generate gRPC proto TypeScript types
pnpm proto:generate
12. Common Issues
| Issue | Fix |
|---|---|
Could not connect to Postgres | Ensure docker compose up postgres is running; check DATABASE_URL |
| gRPC call hangs | Check GRPC_TLS_ENABLED=false in .env.local |
| AI classification always returns same result | Mock provider always returns pre-configured response; switch AI_PROVIDER=claude for real calls |
| Tests fail with "relation does not exist" | Run pnpm prisma migrate dev to apply schema |
| Rule changes not reflected in evaluation | Rule set cache TTL 300 s; run pnpm cache:clear or wait |