Skip to content

Repository files navigation

PulseFlag

Status: Experimental License: MIT TypeScript Next.js PostgreSQL Redis Docker

Open-source feature flag and progressive delivery platform built with TypeScript.

Current status: Experimental (v0.1.0). PulseFlag is a portfolio-grade systems and platform engineering project. It is not production-ready.

Overview

PulseFlag manages feature flags across development, staging, and production. PostgreSQL is the source of truth, Redis accelerates evaluation and distributes invalidations, a Fastify API exposes management and SDK contracts, and a Next.js dashboard provides the control plane. The independent evaluation engine handles targeting and deterministic percentage rollout without importing HTTP, database, cache, or UI code.

Why PulseFlag?

A useful feature flag system is more than a CRUD screen. It must make the same decision for the same subject, isolate environments, protect SDK credentials, bound untrusted evaluation payloads, propagate changes, degrade safely when cache infrastructure is unavailable, and explain why a variation was served. PulseFlag keeps those concerns explicit and inspectable.

Features

  • Projects with automatically provisioned development, staging, and production environments
  • Boolean, string, and number flags with typed variations
  • Independent per-environment flag configuration
  • Priority-ordered targeting rules with AND conditions
  • Stable 10,000-bucket percentage rollouts using integer basis points
  • Remote single and bulk evaluation APIs
  • Environment-scoped SDK keys stored only as prefix and SHA-256 hash
  • PostgreSQL source of truth with Drizzle schema and SQL migration
  • Local and Redis evaluation snapshot cache with bounded TTL
  • Redis Pub/Sub invalidation and Server-Sent Events
  • Audit log with cursor pagination and secret-free metadata
  • JavaScript/TypeScript SDK with timeout, cancellation, and typed fallbacks
  • Next.js and Tailwind management dashboard
  • Structured Pino logging with credential redaction
  • Health, readiness, CORS, body limits, rate limiting, OpenAPI, and graceful shutdown
  • Multi-stage non-root API and web containers

Architecture

flowchart LR
    Dashboard["Dashboard / Next.js"] --> API["PulseFlag API / Fastify"]
    SDK["JavaScript SDK"] --> API
    API --> PostgreSQL["PostgreSQL / source of truth"]
    API --> Redis["Redis"]
    API --> Core["Evaluation Core"]
    Redis --> Cache["Snapshot cache"]
    Redis --> PubSub["Pub/Sub invalidation"]
    PubSub --> SSE["SSE clients"]
Loading

The deployment is a modular monolith rather than a collection of microservices. Package boundaries keep the decision engine reusable while one API process owns lifecycle and infrastructure resources. See Architecture.

Evaluation Engine

The pure @pulseflag/evaluation-core package applies this fixed sequence:

flowchart TD
    Request["SDK evaluation"] --> Key["Authenticate environment SDK key"]
    Key --> Snapshot["Load environment flag snapshot"]
    Snapshot --> Enabled{"Flag enabled?"}
    Enabled -->|No| Disabled["Disabled variation"]
    Enabled -->|Yes| Rules["Rules by ascending priority"]
    Rules -->|First match| Target["Target variation"]
    Rules -->|No match| Rollout["Deterministic rollout bucket"]
    Rollout -->|Allocated| Variation["Rollout variation"]
    Rollout -->|Not configured| Default["Default variation"]
Loading

Results include FLAG_DISABLED, TARGET_MATCH, ROLLOUT, DEFAULT, or FLAG_NOT_FOUND. The engine never uses Math.random().

Targeting Rules

Conditions support equals, not_equals, in, not_in, contains, starts_with, and ends_with. Every condition inside one rule must match. Rules are evaluated by ascending numeric priority and the first matching rule wins. Context key is mandatory; optional attributes may be string, finite number, boolean, or a bounded string array.

Deterministic Rollouts

PulseFlag hashes flagKey:environmentKey:context.key with stable 32-bit FNV-1a and maps it to a bucket in 0..9999. Flag, environment, and context identity therefore produce the same bucket across requests and API instances.

Percentage Rollouts

Allocations use integer basis points: 100 = 1%, 2500 = 25%, and 10000 = 100%. When configured, allocations must total exactly 10,000. Cumulative intervals select a variation without floating-point rounding.

Environments

FeatureFlag owns identity and variations. EnvironmentFlagConfig owns enabled state, default and disabled variations, targeting rules, and rollout for one environment. A flag can therefore be open in development, partially rolled out in staging, and conservative in production.

Dashboard

The web application includes overview, projects, project detail, environments, feature flags, a complete environment-aware flag editor, audit log, and API key management. The administrator enters PULSEFLAG_ADMIN_TOKEN; the dashboard keeps it in session storage and sends it only as the API bearer credential.

SDK

import { PulseFlagClient } from "@pulseflag/sdk-js";

const client = new PulseFlagClient({
  baseUrl: "https://flags.example.com",
  sdkKey: process.env.PULSEFLAG_SDK_KEY!,
  timeoutMs: 1500,
});

const enabled = await client.getBoolean("new-checkout", false, {
  key: "user-123",
  attributes: { country: "BR", plan: "premium" },
});

getBoolean, getString, and getNumber return their caller-provided fallback for expected transport, timeout, response, or type failures. evaluate and bulkEvaluate expose structured results and errors for callers that need them. close() cancels outstanding and future work.

API

Management APIs live under /api/v1 and require Authorization: Bearer <admin-token>. Evaluation and stream endpoints accept x-pulseflag-sdk-key or a bearer SDK key. The development API exposes OpenAPI UI at /docs. See API Reference.

Quick Start

Prerequisites are Node.js 22+, pnpm 10+, PostgreSQL, and optionally Redis.

cp .env.example .env
pnpm install
pnpm db:migrate
pnpm dev

Replace PULSEFLAG_ADMIN_TOKEN before exposing the service. The dashboard defaults to http://localhost:3000 and API to http://localhost:8080.

Configuration

Variable Default/example Purpose
NODE_ENV development Runtime policy and docs visibility
PULSEFLAG_API_HOST 0.0.0.0 API bind address
PULSEFLAG_API_PORT 8080 API port
DATABASE_URL PostgreSQL URL Required source-of-truth connection
REDIS_URL Redis URL Optional cache, Pub/Sub, and degraded fallback
PULSEFLAG_ADMIN_TOKEN change-me Administrator bearer token; invalid in production
PULSEFLAG_ALLOWED_ORIGINS http://localhost:3000 Comma-separated CORS allowlist
PULSEFLAG_CACHE_TTL_SECONDS 30 Local and Redis snapshot TTL
PULSEFLAG_EVALUATION_RATE_LIMIT 600 Requests per minute per source IP
PULSEFLAG_MAX_BULK_FLAGS 100 Maximum flags per bulk evaluation
NEXT_PUBLIC_PULSEFLAG_API_URL http://localhost:8080 Browser-visible dashboard API URL
LOG_LEVEL info Pino log level

PostgreSQL

The relational model includes projects, environments, flags, variations, environment configs, rules, conditions, rollout allocations, API keys, and audit events. Foreign keys, unique constraints, checks, and lookup indexes are present in both the Drizzle schema and db/migrations/0000_initial.sql.

Redis

Redis is not authoritative. Evaluation snapshots are cached with a TTL. Writes commit to PostgreSQL, delete local and Redis entries, publish a compact invalidation event, and notify connected SSE clients. API instances evict matching local snapshots when they receive Pub/Sub events. If Redis cannot connect or an operation fails, evaluation loads from PostgreSQL.

Realtime Updates

GET /api/v1/stream authenticates an environment SDK key and streams flag.created, flag.updated, and flag.deleted events. Events identify project, environment, and flag but contain no values, rules, user context, or credentials.

Docker

Dockerfile.api and Dockerfile.web are multi-stage, run as non-root users, and target Node.js 24 Alpine. compose.yml defines PostgreSQL, Redis, API, web, health checks, and persistent volumes.

PULSEFLAG_ADMIN_TOKEN="replace-with-a-long-secret" docker compose up --build

Container files are provided for deployment review. They were intentionally not executed for v0.1.

Project Structure

apps/
  api/                    Fastify management and evaluation API
  web/                    Next.js management dashboard
packages/
  evaluation-core/        pure deterministic decision engine
  sdk-js/                 typed network SDK
  shared/                 domain contracts and Zod schemas
db/migrations/            PostgreSQL migration SQL
docs/                     architecture, evaluation, API, security, ADRs
Dockerfile.api
Dockerfile.web
compose.yml

Security

Administrative routes require a constant-time compared bearer token. SDK credentials use 256 bits of randomness, reveal the complete secret once, and store only a prefix and SHA-256 digest. Logs redact authorization fields. Production rejects the example administrator token. CORS is an allowlist, request bodies are bounded, evaluation is rate-limited, inputs are validated, and internal stack details are not returned. See Security.

Design Decisions

Limitations

  • V0.1 uses one global administrator token; there are no users, organizations, or RBAC.
  • SDK key hashes are unkeyed SHA-256 because secrets are high entropy; deployment-level database access remains sensitive.
  • Evaluation is remote; the SDK does not maintain an offline flag cache or consume SSE yet.
  • Redis fallback preserves correctness but increases PostgreSQL load and loses cross-instance realtime invalidation while degraded.
  • Audit events identify administrator actions but not individual actors.
  • No automated tests, CI, runtime validation, benchmark, or load result is claimed for this version.
  • Dashboard access should be restricted at the network edge until user authentication exists.

Roadmap

V0.2

  • automated test suite
  • GitHub Actions CI
  • user accounts, organizations, RBAC, and team management
  • richer targeting operators
  • improved SDK caching
  • OpenTelemetry

V0.3

  • Go, Python, and Java SDKs
  • flag prerequisites
  • scheduled flag changes
  • approval workflows

V0.4

  • experimentation and analytics
  • automated progressive rollout
  • multi-region experiments

No milestone has a promised date.

Contributing

Focused issues and pull requests are welcome. Keep the evaluation core infrastructure-independent, preserve strict TypeScript, avoid secrets in fixtures or logs, and document changes to evaluation semantics.

License

PulseFlag is available under the MIT License. Copyright 2026 Thiago Montozo.

About

Open-source feature flag and progressive delivery platform built with TypeScript.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages