Skip to content

opendecree/decree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

149 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

OpenDecree

OpenDecree

CI Release Go Reference Go Report Card License Project Status: WIP

Schema-driven business configuration management for multi-tenant services.

Alpha Software β€” OpenDecree is under active development. APIs, proto definitions, configuration formats, and behavior may change without notice between versions. Not recommended for production use yet.

OpenDecree quickstart demo: schema β†’ config β†’ watch

What is this?

OpenDecree manages business-oriented configuration β€” approval rules, fee structures, settlement windows, feature parameters β€” the kind of config that lives between your infrastructure settings and your application code.

How is this different?

OpenDecree sits between feature flags (release toggles) and infrastructure config (low-level key-value) β€” purpose-built for typed business configuration.

Capability Feature Flags Infrastructure Config* OpenDecree
Typed values bool / variant only strings only βœ“ native types (int, number, string, bool, time, duration, url, json)
Schema validation βœ— βœ— βœ“ constraints + JSON Schema, enforced on every write
Multi-tenant limited (segments) βœ— βœ“ first-class, with field-level locking
Audit trail limited βœ— βœ“ full who/what/when/why history
Real-time updates βœ“ SDK polling/SSE βœ“ watch APIs βœ“ gRPC streaming subscriptions
Admin UI βœ“ (vendor-hosted) βœ— βœ“ open-source admin GUI
Versioning + rollback limited βœ— βœ“ every change versioned, rollback to any state

Examples by category: feature flags (LaunchDarkly, ConfigCat, Flagsmith), infrastructure config (etcd, Consul, Spring Cloud Config, AWS AppConfig, Azure App Configuration).

* Cloud config services (AWS AppConfig, Azure App Configuration) offer limited validation, but lack schema registries, multi-tenancy, and gRPC streaming β€” and are vendor-locked.

What makes OpenDecree unique: no other open-source tool combines schema-first typed configuration with native multi-tenancy, field-level locking, gRPC streaming, and versioned rollback in a single Go binary.

Features

  • Typed values β€” native proto types (integer, number, string, bool, timestamp, duration, url, json) with wire-level type safety
  • Schema validation β€” constraints (min/max, pattern, enum, JSON Schema) enforced on every write
  • Multi-tenancy β€” apply schemas to tenants with role-based access and field-level locking
  • Versioned configs β€” every change creates a version; rollback to any previous state
  • Real-time subscriptions β€” gRPC streaming pushes changes to consumers instantly
  • Audit trail β€” full history of who changed what, when, and why
  • Import/Export β€” portable schemas and configs in YAML format
  • Optimistic concurrency β€” safe read-modify-write with checksum validation
  • Null support β€” null and empty string are distinct values

SDKs

SDK Language Protocol Status Version Install
decree Go gRPC alpha Go release go get github.com/opendecree/decree/sdk/grpctransport@latest
decree-python Python gRPC alpha PyPI pip install opendecree
decree-typescript TypeScript gRPC alpha npm npm install @opendecree/sdk
REST API Any REST alpha β€” curl

Go

The core SDK modules require Go 1.22+ and have zero external dependencies. The grpctransport module (default transport) requires Go 1.24+ because google.golang.org/grpc pins that version β€” if you need a Go 1.22-compatible transport, πŸ‘ or comment on #90 to signal demand.

// configclient β€” application runtime reads and writes
client := grpctransport.NewConfigClient(conn, grpctransport.WithSubject("myapp"))
val, _ := client.GetInt(ctx, tenantID, "payments.retries")

// configwatcher β€” live typed values with auto-reconnect
w := grpctransport.NewWatcher(conn, tenantID, grpctransport.WithSubject("myapp"))
fee := w.Float("payments.fee", 0.01)
w.Start(ctx)
fmt.Println(fee.Get()) // always fresh
go get github.com/opendecree/decree/sdk/grpctransport@latest  # gRPC transport (pulls in configclient, etc.)
go get github.com/opendecree/decree/sdk/configclient@latest   # core client (no gRPC dependency)
go get github.com/opendecree/decree/sdk/adminclient@latest    # admin operations
go get github.com/opendecree/decree/sdk/configwatcher@latest  # live config watcher
go get github.com/opendecree/decree/sdk/tools@latest          # diff, docgen, validate, seed, dump

Go API docs on pkg.go.dev: grpctransport Β· configclient Β· adminclient Β· configwatcher Β· tools

Python

from opendecree import ConfigClient

with ConfigClient("localhost:9090", subject="myapp") as client:
    retries = client.get("tenant-id", "payments.retries", int)

    with client.watch("tenant-id") as watcher:
        fee = watcher.field("payments.fee", float, default=0.01)
        print(fee.value)  # always fresh

Docs: decree-python

TypeScript

import { ConfigClient } from "@opendecree/sdk";

const client = new ConfigClient("localhost:9090", { subject: "myapp" });
const retries = await client.get("tenant-id", "payments.retries", Number);

const watcher = client.watch("tenant-id");
const fee = watcher.field("payments.fee", Number, { default: 0.01 });
await watcher.start();
console.log(fee.value); // always fresh

Docs: decree-typescript

Examples

Runnable examples in examples/ β€” each is a standalone Go module you can copy into your own project.

Example What it shows
quickstart Connect and read typed values
feature-flags Live feature toggles with configwatcher
live-config HTTP server with hot-reloadable config
multi-tenant Same schema, different tenant values
optimistic-concurrency Safe concurrent updates with CAS
schema-lifecycle Create, publish, and manage schemas
environment-bootstrap Bootstrap from a single YAML file
config-validation Offline validation (no server needed)
cd examples && make setup   # start server + seed data
cd quickstart && go run .   # run any example

CLI

go install github.com/opendecree/decree/cmd/decree@latest

decree schema list
decree schema import --publish decree.schema.yaml  # import + auto-publish

decree tenant create --name acme --schema payroll-service --schema-version 1
decree config set acme payments.fee 0.5%          # use tenant name or UUID
decree config get-all acme
decree config versions acme
decree config rollback acme 2

decree watch acme                                  # live stream
decree lock set acme payments.currency             # lock field
decree audit query --tenant acme --since 24h

# Power tools
decree seed fixtures/billing.yaml                 # bootstrap from a fixture
decree dump acme > backup.yaml                    # full tenant backup
decree diff acme 1 2                              # diff two config versions
decree diff --old v1.yaml --new v2.yaml           # diff two files
decree docgen payroll-service                      # use schema name or UUID
decree validate --schema decree.schema.yaml --config decree.config.yaml

Global flags: --server, --subject, --role, --output table|json|yaml, --wait, --wait-timeout

Use --wait in Docker/Kubernetes init containers to wait for the server to be ready:

decree seed examples/seed.yaml --server decree:9090 --wait --wait-timeout 60s

Quick Start

Try it instantly (no Docker needed)

go install github.com/opendecree/decree/cmd/server@latest

# Start with in-memory storage β€” zero dependencies
INSECURE_LISTEN=1 STORAGE_BACKEND=memory HTTP_PORT=8080 decree-server

# Open http://localhost:8080/docs for Swagger UI
# All requests need x-subject header:
curl -H "x-subject: admin" http://localhost:8080/v1/schemas

TLS required in production. INSECURE_LISTEN=1 disables TLS for local development only. See Transport Security (TLS) for production setup.

Docker Compose (production-like)

git clone https://github.com/opendecree/decree.git
cd decree

# Start the full stack (PostgreSQL + Redis + migrations + service)
docker compose up -d --wait service

# gRPC at localhost:9090, REST/JSON at localhost:8080
# No JWT required β€” metadata auth is the default

REST API

The entire gRPC API is also available as REST/JSON (via grpc-gateway). Set HTTP_PORT to enable:

# Version check
curl http://localhost:8080/v1/version

# List schemas
curl -H "x-subject: admin" http://localhost:8080/v1/schemas

# Create a schema
curl -X POST http://localhost:8080/v1/schemas \
  -H "Content-Type: application/json" \
  -H "x-subject: admin" \
  -d '{"name":"payments","fields":[{"path":"fee","type":7}]}'

# Get config
curl -H "x-subject: admin" http://localhost:8080/v1/tenants/{id}/config

OpenAPI spec: docs/api/openapi.swagger.json

Using the CLI

# Set auth identity
export DECREE_SUBJECT=admin@example.com

# Create and publish a schema
decree schema import --publish examples/config-validation/decree.schema.yaml

# Create a tenant and set config
decree tenant create --name acme --schema <schema-id> --schema-version 1
decree config set <tenant-id> payments.fee "0.5%"
decree config get-all <tenant-id>

Architecture

flowchart LR
    subgraph Clients
        direction TB
        SDKs["πŸ”§ SDKs\nGo Β· Python Β· TypeScript"]
        CLI[">_ CLI\ndecree"]
        UI["πŸ–₯️ Admin UI\ndecree-ui"]
        Direct["πŸ”— Direct\ncurl, custom"]
    end

    SDKs & CLI -->|gRPC| GW
    UI & Direct -->|REST| GW

    GW{{"πŸ” Gateway\nauth Β· routing"}}

    subgraph Server["βš™οΈ OpenDecree"]
        SS["πŸ“‹ SchemaService\nschemas, tenants"]
        CS["πŸ“ ConfigService\nread, write, subscribe"]
        AS["πŸ“Š AuditService\nhistory, usage"]
    end

    GW --> SS & CS & AS

    subgraph Backends["πŸ’Ύ Pluggable Backends"]
        Storage[("Storage")]
        Cache[("Cache")]
        PubSub[("Pub/Sub")]
    end

    SS & CS & AS --> Storage
    CS --> Cache
    CS <--> PubSub
Loading

Single binary exposing three gRPC services + REST/JSON gateway. All external dependencies (storage, cache, pub/sub) are behind Go interfaces β€” swap implementations via STORAGE_BACKEND=memory for zero-dependency evaluation or testing. Deploy with ENABLE_SERVICES to control which services run on each instance.

Configuration

Server

Variable Description Default
GRPC_PORT gRPC listen port 9090
HTTP_PORT REST/JSON gateway port (disabled if empty) disabled
STORAGE_BACKEND postgres or memory postgres
DB_WRITE_URL PostgreSQL primary connection string required if postgres
DB_READ_URL PostgreSQL read replica connection string DB_WRITE_URL
REDIS_URL Redis connection string required if postgres
ENABLE_SERVICES Services to enable: schema, config, audit all
LOG_LEVEL debug, info, warn, error info
INSECURE_LISTEN Set to 1 to accept plaintext gRPC (local dev only) disabled
TLS_CERT_FILE Path to PEM server certificate required unless INSECURE_LISTEN=1
TLS_KEY_FILE Path to PEM server private key required unless INSECURE_LISTEN=1
TLS_CLIENT_CA_FILE CA bundle for client certificates (enables mTLS) disabled
RATE_LIMIT_ENABLED Set to false to disable rate limiting true
RATE_LIMIT_ANON_RPS Requests per second for unauthenticated callers 10
RATE_LIMIT_AUTHED_RPS Requests per second per authenticated tenant 100
RATE_LIMIT_SUPERADMIN_RPS Requests per second per superadmin (0 = unlimited) 0
RATE_LIMIT_BURST Token bucket burst size (all role classes) 10

Authentication

JWT is opt-in. By default, the service uses metadata-based auth:

Variable Description Default
JWT_JWKS_URL JWKS endpoint β€” enables JWT validation disabled
JWT_ISSUER Expected JWT issuer optional

Without JWT, pass identity via gRPC metadata headers:

  • x-subject (required) β€” actor identity
  • x-role β€” superadmin (default), admin, or user
  • x-tenant-id β€” required for non-superadmin roles

Observability (all opt-in)

Variable Description
OTEL_ENABLED Master switch β€” initializes SDK + slog trace correlation
OTEL_TRACES_GRPC gRPC server spans
OTEL_TRACES_DB PostgreSQL query spans
OTEL_TRACES_REDIS Redis command spans
OTEL_METRICS_GRPC gRPC request count/latency
OTEL_METRICS_DB_POOL Connection pool gauges
OTEL_METRICS_CACHE Cache hit/miss counters
OTEL_METRICS_CONFIG Config write counter + version gauge
OTEL_METRICS_SCHEMA Schema publish counter

Standard OTel variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME) are respected by the SDK.

API

The API is defined in Protocol Buffers under proto/, published to BSR at buf.build/opendecree/decree. Three gRPC services:

  • SchemaService β€” create, version, and manage config schemas and tenants
  • ConfigService β€” read/write typed config values, subscribe to changes, version management
  • AuditService β€” query change history and usage statistics

Values use a TypedValue oneof β€” integer, number, string, bool, timestamp, duration, url, json β€” with null support.

The schema YAML format authors write to define their config shape is documented in Schema Format. The corresponding JSON Schema 2020-12 meta-schemas for editor IntelliSense and CI validation are published at:

  • https://schemas.opendecree.dev/schema/v0.1.0/decree-schema.json β€” validates *.decree.schema.yaml
  • https://schemas.opendecree.dev/schema/v0.1.0/decree-config.json β€” validates *.decree.config.yaml

All endpoints that accept a tenant or schema ID also accept the name slug β€” the server resolves automatically. Use UUIDs or human-readable names interchangeably:

Generate client stubs in any language from BSR, or use the official SDKs:

Repo Package
Go this repo github.com/opendecree/decree/sdk/*
Python decree-python opendecree
TypeScript decree-typescript @opendecree/sdk

Test Coverage

Coverage badges reflect business logic only β€” infrastructure wrappers that are tested at the integration/e2e level are excluded from the calculation:

Excluded Reason
store_pg.go PostgreSQL store implementations β€” thin DB wrappers, tested via e2e
redis.go Redis cache/pubsub implementations β€” thin wrappers, tested via e2e
storage/dbstore/ sqlc-generated query code
storage/postgres.go Interface definitions only
telemetry/ OpenTelemetry provider wiring boilerplate

Run ./scripts/coverage.sh to calculate the server coverage, or ./scripts/coverage.sh -v for a per-function breakdown.

Demos

Want to see OpenDecree in action without reading docs? The demos repo has self-contained, runnable examples β€” from a 5-minute quickstart to production patterns. Each demo runs with a single docker compose up.

Contributing

See CONTRIBUTING.md for development setup, build instructions, and contribution guidelines.

License

Apache License 2.0 β€” see LICENSE for details.