Skip to content

dhiway/dpg-scoring

Repository files navigation

dpg-scoring

Fastify + Zod microservice for DPG scoring.

Current scope

  • health endpoints
  • readiness endpoint
  • AI-backed match-score module
  • HMAC API key auth for protected routes

Endpoints

  • GET /
  • GET /health
  • GET /ready
  • POST /api/v1/scores/match
  • GET /docs
  • GET /docs/json

Run locally

Create local secret files from the example files first.

cp config/auth.keys.example.json config/auth.keys.json
cp config/ai.providers.example.json config/ai.providers.json
docker compose up -d redis
pnpm install
pnpm dev

Redis host port comes from REDIS_PORT in your environment or .env file.

Format the codebase with:

pnpm format
pnpm format:check

Run with Docker Compose

Create local secret files from the example files first.

cp config/auth.keys.example.json config/auth.keys.json
cp config/ai.providers.example.json config/ai.providers.json

Then start the full stack:

docker compose up --build -d

This starts:

  • dpg-scoring-app on http://localhost:3000
  • dpg-scoring-redis on localhost:${REDIS_PORT:-6379}

The app container:

  • loads non-secret settings from .env
  • mounts config/auth.keys.json and config/ai.providers.json read-only at runtime
  • connects to Redis using the Compose service name via REDIS_URL=redis://dpg-scoring-redis:6379
  • waits for Redis to become healthy before starting

Healthchecks:

  • dpg-scoring-redis uses redis-cli ping
  • dpg-scoring-app checks GET /ready inside the container

Useful commands:

docker compose logs -f dpg-scoring-app
docker compose ps
docker compose down

Open the API docs at:

http://localhost:3000/docs

If you update .env, rebuild and restart the app:

docker compose up --build -d dpg-scoring-app

API docs

OpenAPI docs are available at:

  • http://localhost:3000/docs
  • http://localhost:3000/docs/json

Swagger UI is the primary docs surface for this service. The generated OpenAPI spec should remain the source of truth so the UI can be swapped later if needed.

Auth secrets file

Store local API keys in config/auth.keys.json.

Example shape:

{
  "keys": [
    {
      "keyId": "match-score-client",
      "secret": "replace-with-a-strong-secret-1"
    },
    {
      "keyId": "admin-dashboard",
      "secret": "replace-with-a-strong-secret-3"
    }
  ]
}

This file is git-ignored.

AI provider secrets file

Store local provider keys in config/ai.providers.json.

Example shape:

{
  "providers": {
    "gemini": {
      "apiKey": "replace-with-your-gemini-api-key"
    },
    "openai": {
      "apiKey": "replace-with-your-openai-api-key"
    }
  }
}

This file is also git-ignored.

Redis

Redis is used for:

  • shared nonce replay protection for HMAC auth
  • match-score response caching

Default local config:

REDIS_ENABLED=true
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_URL=redis://localhost:6379
MATCH_SCORE_CACHE_ENABLED=true
MATCH_SCORE_CACHE_TTL_SECONDS=600

Start Redis locally:

docker compose up -d redis

Stop Redis:

docker compose down

If you want to run the service without Redis temporarily:

REDIS_ENABLED=false
MATCH_SCORE_CACHE_ENABLED=false

In that mode:

  • auth nonce protection falls back to in-memory storage
  • match-score caching is disabled

Auth headers

Protected routes require these headers:

  • x-dpg-key
  • x-dpg-timestamp
  • x-dpg-nonce
  • x-dpg-signature

Signature base string:

METHOD
PATH
TIMESTAMP
NONCE

Signature format:

sha256=<hex-hmac>

Swagger documents these headers as required security headers for protected /api/v1 endpoints.

Example request

curl -X POST http://localhost:3000/api/v1/scores/match \
  -H "x-dpg-key: match-score-client" \
  -H "x-dpg-timestamp: 1710000000" \
  -H "x-dpg-nonce: abc123" \
  -H "x-dpg-signature: sha256=<signature>" \
  -H "content-type: application/json" \
  -d '{
    "version": "v1",
    "promptVersion": "match-compatibility-v1",
    "itemA": {
      "item_network": "yellow_dot",
      "item_domain": "student",
      "item_type": "profile_1.0",
      "item_id": "5413356c-2ced-4892-8050-bb19dfdf9928",
      "item_instance_url": "https://ubi-backend.onest.dhiway.net",
      "item_schema_url": "https://ubi-backend.onest.dhiway.net/api/v1/network/schema/yellow_dot/student/profile_1.0",
      "item_state": {
        "city": "Secunderabad",
        "name": "Student Example",
        "grade": "10",
        "preferred_subject": "maths, Physics"
      },
      "item_latitude": null,
      "item_longitude": null
    },
    "itemB": {
      "item_network": "yellow_dot",
      "item_domain": "tutor",
      "item_type": "profile_1.0",
      "item_id": "f7f124fe-6746-45bb-8323-5b7ec95f5d07",
      "item_instance_url": "https://ubi-backend.onest.dhiway.net",
      "item_schema_url": "https://ubi-backend.onest.dhiway.net/api/v1/network/schema/yellow_dot/tutor/profile_1.0",
      "item_state": {
        "name": "Tutor Example",
        "subjects": ["English"],
        "teaching_mode": "online",
        "experience_years": 2
      },
      "item_latitude": null,
      "item_longitude": null
    }
  }'

Match scoring behavior

  • API version defaults to v1
  • prompt version defaults to match-compatibility-v1
  • promptVersion is optional on the request
  • API v1 can later run with newer prompt versions without changing the route contract
  • provider selection is configurable and currently defaults to Gemini
  • Redis-backed caching is configurable and enabled by default for local development

Local test helper

Use the included helper to sign and send a sample request:

pnpm call:match-score

Optional flags:

pnpm call:match-score -- --url http://localhost:3000/api/v1/scores/match
pnpm call:match-score -- --key-id match-score-client
pnpm call:match-score -- --payload ./scripts/match-score.sample.json

If --payload is not provided, the script sends a built-in sample student/tutor payload.

Generate auth headers only:

pnpm auth:headers
pnpm auth:headers -- --format curl
pnpm auth:headers -- --method GET --url http://localhost:3000/api/v1/scores/match

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors