Skip to main content

compliance-engine — Local Development Setup

Status: populated | Last updated: 2026-04-18

1. Prerequisites

ToolVersionPurpose
Node.js20 LTS+Runtime
pnpm9+Package manager
Docker Desktop24+Postgres, Redis, NATS containers
grpcurllatestgRPC testing
mkcertlatestLocal 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/health
  • http://localhost:3002/ready
  • http://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

IssueFix
Could not connect to PostgresEnsure docker compose up postgres is running; check DATABASE_URL
gRPC call hangsCheck GRPC_TLS_ENABLED=false in .env.local
AI classification always returns same resultMock 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 evaluationRule set cache TTL 300 s; run pnpm cache:clear or wait