Skip to content

Djones-qa/feature-flag-engine

Repository files navigation

feature-flag-engine

CI TypeScript Node.js Redis PostgreSQL Kubernetes Docker License: MIT

Production-grade, self-hosted feature flag evaluation engine — targeting rules, gradual rollouts, A/B testing, and audit logging. Built on TypeScript/Node.js with Redis caching, PostgreSQL persistence, and Kubernetes-native deployment.


Architecture

graph TD
    Client["Client / SDK"] -->|POST /evaluate| EvalService["eval-service :3001"]
    Client -->|CRUD /flags| FlagAPI["flag-api :3000"]
    FlagAPI -->|Read/Write| Postgres["PostgreSQL (source of truth)"]
    FlagAPI -->|Invalidate cache| Redis["Redis (cache + stream)"]
    EvalService -->|Cache lookup/fill| Redis
    EvalService -->|Fallback read| Postgres
    EvalService -->|XADD eval event| RedisStream["Redis Stream"]
    AuditWorker["audit-worker"] -->|XREAD events| RedisStream
    AuditWorker -->|INSERT audit records| Postgres
Loading

Services

Service Port Description
flag-api 3000 Control plane — CRUD for flags and targeting rules
eval-service 3001 High-throughput evaluation engine — Redis-cached, sub-millisecond p99
audit-worker Background worker — consumes Redis Stream, writes structured audit records to PostgreSQL

Quick Start

# Clone the repo
git clone https://github.com/Djones-qa/feature-flag-engine.git
cd feature-flag-engine

# Start all services with real PostgreSQL + Redis
docker compose up --build

Once running, try it out:

# Create a flag
curl -s -X POST http://localhost:3000/flags \
  -H 'Content-Type: application/json' \
  -d '{
    "key": "checkout-v2",
    "name": "Checkout V2",
    "description": "New checkout flow",
    "enabled": true,
    "rolloutPercentage": 50,
    "rules": [
      {
        "attribute": "plan",
        "operator": "eq",
        "values": ["enterprise"],
        "variant": "on",
        "priority": 1
      }
    ],
    "defaultVariant": "off"
  }' | jq

# Evaluate the flag for an enterprise user (matches targeting rule → "on")
curl -s -X POST http://localhost:3000/flags/checkout-v2/evaluate \
  -H 'Content-Type: application/json' \
  -d '{"userId": "user-001", "plan": "enterprise"}' | jq

# Evaluate via eval-service directly (high-throughput path)
curl -s -X POST http://localhost:3001/evaluate \
  -H 'Content-Type: application/json' \
  -d '{"flagKey": "checkout-v2", "context": {"userId": "user-002", "plan": "free"}}' | jq

# Batch evaluation
curl -s -X POST http://localhost:3001/evaluate/batch \
  -H 'Content-Type: application/json' \
  -d '{
    "flagKeys": ["checkout-v2"],
    "context": {"userId": "user-003"}
  }' | jq

# Get audit trail
curl -s http://localhost:3000/flags/checkout-v2/audit | jq

API Reference

flag-api (port 3000)

Method Path Description
POST /flags Create a flag
GET /flags List all active flags
GET /flags/:key Get flag by key
PUT /flags/:key Update flag (toggle, rules, rollout %)
DELETE /flags/:key Archive a flag
POST /flags/:key/evaluate Evaluate a flag for a user context
GET /flags/:key/audit Get audit trail for a flag
GET /health Liveness probe
GET /ready Readiness probe (Redis + PostgreSQL)

eval-service (port 3001)

Method Path Description
POST /evaluate Evaluate a single flag
POST /evaluate/batch Evaluate multiple flags at once
GET /health Liveness probe

Evaluation Logic

  1. FLAG_DISABLEDflag.enabled === false → return off
  2. TARGETING_RULE — evaluate rules in ascending priority order; first match wins
  3. ROLLOUT — hash userId:flagKey → bucket [0-99]; serve on if bucket < rolloutPercentage
  4. DEFAULT — return flag.defaultVariant

Configuration

All services are configured via environment variables:

Variable Default Description
PORT 3000 / 3001 HTTP listen port
POSTGRES_HOST localhost PostgreSQL host
POSTGRES_PORT 5432 PostgreSQL port
POSTGRES_DB featureflags Database name
POSTGRES_USER postgres Database user
POSTGRES_PASSWORD postgres Database password
REDIS_HOST localhost Redis host
REDIS_PORT 6379 Redis port
REDIS_PASSWORD Redis password (optional)

Development

Prerequisites

  • Node.js 20+
  • npm 10+
  • Docker (for integration tests)

Setup

# Install all dependencies
npm ci

# Build all packages
npm run build

# Run unit tests (with property-based tests)
npm test

# Run unit tests with coverage
npm run test:coverage

# Typecheck all packages
npm run typecheck

Project Structure

feature-flag-engine/
├── packages/
│   ├── shared/           # Shared types, evaluation engine, DB + cache layers
│   │   ├── src/
│   │   │   ├── types.ts          # Core interfaces
│   │   │   ├── evaluator.ts      # Targeting rule operator logic
│   │   │   ├── bucketer.ts       # Rollout bucketing (MurmurHash)
│   │   │   ├── engine.ts         # Full evaluation pipeline
│   │   │   ├── db/               # PostgreSQL repositories
│   │   │   ├── cache/            # Redis flag cache
│   │   │   └── stream/           # Audit stream producer
│   ├── flag-api/         # Control plane API (port 3000)
│   ├── eval-service/     # Evaluation engine (port 3001)
│   ├── audit-worker/     # Redis Stream → PostgreSQL worker
│   └── integration-tests/# testcontainers-based integration tests
├── k8s/                  # Kubernetes manifests
├── .github/workflows/    # GitHub Actions CI
└── docker-compose.yml

Running Integration Tests

Integration tests require Docker:

npm run test --workspace=packages/integration-tests

Kubernetes Deployment

# Apply all manifests to a cluster
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/rbac.yaml

# Create the postgres credentials secret
kubectl create secret generic postgres-credentials \
  --namespace=feature-flags \
  --from-literal=username=postgres \
  --from-literal=password=<your-password>

kubectl apply -f k8s/

Testing

The test suite covers:

  • Property-based tests (fast-check): targeting operator contracts, bucketer determinism and uniformity, disabled flag short-circuit, evaluation exhaustiveness, batch consistency, cache round-trips
  • Unit tests (Jest): all CRUD endpoints, error paths, audit worker event processing, stream producer
  • Integration tests (testcontainers): full evaluation pipeline with real Redis + PostgreSQL, cache invalidation, audit worker end-to-end

License

MIT © 2024 Darrius Jones


Author

Darrius Jones
GitHub: @Djones-qa
LinkedIn: darrius-jones-28226b350

About

Production-grade feature flag evaluation engine — targeting rules, gradual rollouts, A/B testing, audit logging. TypeScript/Node.js + Redis + PostgreSQL + Docker + GitHub Actions CI.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors