Add dd0c/route project scaffolding: migrations, docker-compose, README
- PostgreSQL schema: orgs, users, api_keys, provider_configs, routing_rules, cost_tables, feature_flags - TimescaleDB schema: request_events hypertable, hourly/daily continuous aggregates, compression, retention - docker-compose.yml: postgres, timescaledb, redis for local dev - README with quick start, architecture overview, pricing tiers - .env.example, .gitignore
This commit is contained in:
13
products/01-llm-cost-router/.env.example
Normal file
13
products/01-llm-cost-router/.env.example
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
DATABASE_URL=postgres://dd0c:dd0c@localhost:5432/dd0c
|
||||||
|
TIMESCALE_URL=postgres://dd0c:dd0c@localhost:5433/dd0c_telemetry
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
JWT_SECRET=dev-secret-change-me-in-production
|
||||||
|
PROXY_PORT=8080
|
||||||
|
API_PORT=3000
|
||||||
|
AUTH_MODE=local
|
||||||
|
GOVERNANCE_MODE=audit
|
||||||
|
TELEMETRY_CHANNEL_SIZE=1000
|
||||||
|
|
||||||
|
# Provider keys (add yours)
|
||||||
|
# OPENAI_API_KEY=sk-...
|
||||||
|
# ANTHROPIC_API_KEY=sk-ant-...
|
||||||
4
products/01-llm-cost-router/.gitignore
vendored
Normal file
4
products/01-llm-cost-router/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/target
|
||||||
|
.env
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
53
products/01-llm-cost-router/README.md
Normal file
53
products/01-llm-cost-router/README.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# dd0c/route — LLM Cost Router & Optimization Dashboard
|
||||||
|
|
||||||
|
Drop-in OpenAI-compatible proxy that routes AI requests to the cheapest capable model.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start local infra
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Run the proxy
|
||||||
|
OPENAI_API_KEY=sk-your-key cargo run --bin dd0c-proxy
|
||||||
|
|
||||||
|
# Test it
|
||||||
|
curl http://localhost:8080/v1/chat/completions \
|
||||||
|
-H "Authorization: Bearer your-dd0c-key" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Proxy Engine** (Rust/Axum) — <5ms overhead, SSE streaming, async telemetry
|
||||||
|
- **Router Brain** — Complexity classification, cost-based routing, fallback chains
|
||||||
|
- **Dashboard API** — REST API for config, analytics, team management
|
||||||
|
- **TimescaleDB** — Time-series telemetry with continuous aggregates
|
||||||
|
- **PostgreSQL** — Config, auth, routing rules
|
||||||
|
- **Redis** — API key cache, rate limiting
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
proxy/ — Proxy server (main entry point)
|
||||||
|
api/ — Dashboard API server
|
||||||
|
worker/ — Background jobs (digests, alerts)
|
||||||
|
router/ — Routing logic & complexity classifier
|
||||||
|
auth/ — API key validation, JWT, OAuth
|
||||||
|
config/ — App configuration
|
||||||
|
data/ — Data layer traits (EventQueue, ObjectStore)
|
||||||
|
analytics/ — PostHog PLG instrumentation
|
||||||
|
migrations/ — PostgreSQL + TimescaleDB schemas
|
||||||
|
tests/ — Unit, integration, E2E tests
|
||||||
|
infra/ — CDK / deployment configs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pricing
|
||||||
|
|
||||||
|
| Tier | Price | Requests/mo | Retention |
|
||||||
|
|------|-------|-------------|-----------|
|
||||||
|
| Free | $0 | 10K | 7 days |
|
||||||
|
| Pro | $49/mo | 1M | 90 days |
|
||||||
|
| Enterprise | Custom | Unlimited | 1 year |
|
||||||
50
products/01-llm-cost-router/docker-compose.yml
Normal file
50
products/01-llm-cost-router/docker-compose.yml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# dd0c/route — Local Development
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: dd0c
|
||||||
|
POSTGRES_PASSWORD: dd0c
|
||||||
|
POSTGRES_DB: dd0c
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- pg_data:/var/lib/postgresql/data
|
||||||
|
- ./migrations/001_init.sql:/docker-entrypoint-initdb.d/001_init.sql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U dd0c"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
timescaledb:
|
||||||
|
image: timescale/timescaledb:latest-pg16
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: dd0c
|
||||||
|
POSTGRES_PASSWORD: dd0c
|
||||||
|
POSTGRES_DB: dd0c_telemetry
|
||||||
|
ports:
|
||||||
|
- "5433:5432"
|
||||||
|
volumes:
|
||||||
|
- ts_data:/var/lib/postgresql/data
|
||||||
|
- ./migrations/002_timescale.sql:/docker-entrypoint-initdb.d/002_timescale.sql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U dd0c"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pg_data:
|
||||||
|
ts_data:
|
||||||
108
products/01-llm-cost-router/migrations/001_init.sql
Normal file
108
products/01-llm-cost-router/migrations/001_init.sql
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
-- dd0c/route V1 schema — PostgreSQL (config + auth)
|
||||||
|
|
||||||
|
-- Organizations
|
||||||
|
CREATE TABLE organizations (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
slug TEXT NOT NULL UNIQUE,
|
||||||
|
tier TEXT NOT NULL DEFAULT 'free' CHECK (tier IN ('free', 'pro', 'enterprise')),
|
||||||
|
stripe_customer_id TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Users (GitHub OAuth)
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
github_id BIGINT UNIQUE,
|
||||||
|
email TEXT NOT NULL,
|
||||||
|
name TEXT,
|
||||||
|
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner', 'member', 'viewer')),
|
||||||
|
avatar_url TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_users_org ON users(org_id);
|
||||||
|
CREATE INDEX idx_users_github ON users(github_id);
|
||||||
|
|
||||||
|
-- API Keys (proxy auth)
|
||||||
|
CREATE TABLE api_keys (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
key_prefix CHAR(8) NOT NULL, -- first 8 chars for fast lookup
|
||||||
|
key_hash TEXT NOT NULL, -- bcrypt hash of full key
|
||||||
|
name TEXT NOT NULL DEFAULT 'Default',
|
||||||
|
scopes TEXT[] NOT NULL DEFAULT '{"proxy"}',
|
||||||
|
last_used_at TIMESTAMPTZ,
|
||||||
|
revoked_at TIMESTAMPTZ,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX idx_api_keys_prefix ON api_keys(key_prefix) WHERE revoked_at IS NULL;
|
||||||
|
CREATE INDEX idx_api_keys_org ON api_keys(org_id);
|
||||||
|
|
||||||
|
-- Provider Configs (encrypted API keys for upstream providers)
|
||||||
|
CREATE TABLE provider_configs (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
provider TEXT NOT NULL, -- 'openai', 'anthropic', etc.
|
||||||
|
encrypted_api_key BYTEA NOT NULL, -- AES-256-GCM encrypted
|
||||||
|
base_url TEXT, -- custom endpoint override
|
||||||
|
is_default BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
UNIQUE(org_id, provider)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Routing Rules
|
||||||
|
CREATE TABLE routing_rules (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||||
|
priority INT NOT NULL DEFAULT 0,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
-- Match conditions
|
||||||
|
match_model TEXT, -- e.g. 'gpt-4o'
|
||||||
|
match_feature TEXT, -- X-DD0C-Feature header
|
||||||
|
match_team TEXT, -- X-DD0C-Team header
|
||||||
|
match_complexity TEXT CHECK (match_complexity IN ('low', 'medium', 'high')),
|
||||||
|
-- Routing action
|
||||||
|
strategy TEXT NOT NULL DEFAULT 'passthrough' CHECK (strategy IN ('passthrough', 'cheapest', 'quality-first', 'cascading')),
|
||||||
|
target_model TEXT, -- override model
|
||||||
|
target_provider TEXT, -- override provider
|
||||||
|
fallback_models TEXT[], -- for cascading strategy
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_routing_rules_org ON routing_rules(org_id, priority);
|
||||||
|
|
||||||
|
-- Cost Tables (provider pricing, refreshed daily)
|
||||||
|
CREATE TABLE cost_tables (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
provider TEXT NOT NULL,
|
||||||
|
model TEXT NOT NULL,
|
||||||
|
input_cost_per_1k NUMERIC(10, 6) NOT NULL,
|
||||||
|
output_cost_per_1k NUMERIC(10, 6) NOT NULL,
|
||||||
|
effective_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||||
|
UNIQUE(provider, model, effective_date)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Seed current pricing
|
||||||
|
INSERT INTO cost_tables (provider, model, input_cost_per_1k, output_cost_per_1k) VALUES
|
||||||
|
('openai', 'gpt-4o', 0.005000, 0.015000),
|
||||||
|
('openai', 'gpt-4o-mini', 0.000150, 0.000600),
|
||||||
|
('openai', 'gpt-4-turbo', 0.010000, 0.030000),
|
||||||
|
('openai', 'gpt-3.5-turbo', 0.000500, 0.001500),
|
||||||
|
('anthropic', 'claude-3-opus', 0.015000, 0.075000),
|
||||||
|
('anthropic', 'claude-3-sonnet', 0.003000, 0.015000),
|
||||||
|
('anthropic', 'claude-3-haiku', 0.000250, 0.001250),
|
||||||
|
('anthropic', 'claude-3.5-sonnet', 0.003000, 0.015000);
|
||||||
|
|
||||||
|
-- Feature flags (Transparent Factory: Atomic Flagging)
|
||||||
|
CREATE TABLE feature_flags (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE, -- NULL = global
|
||||||
|
flag_key TEXT NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
rollout_pct INT NOT NULL DEFAULT 0 CHECK (rollout_pct BETWEEN 0 AND 100),
|
||||||
|
metadata JSONB NOT NULL DEFAULT '{}',
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
UNIQUE(org_id, flag_key)
|
||||||
|
);
|
||||||
88
products/01-llm-cost-router/migrations/002_timescale.sql
Normal file
88
products/01-llm-cost-router/migrations/002_timescale.sql
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
-- dd0c/route V1 — TimescaleDB schema (telemetry)
|
||||||
|
|
||||||
|
-- Request events (the core telemetry table)
|
||||||
|
CREATE TABLE request_events (
|
||||||
|
time TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
org_id UUID NOT NULL,
|
||||||
|
original_model TEXT NOT NULL,
|
||||||
|
routed_model TEXT NOT NULL,
|
||||||
|
provider TEXT NOT NULL,
|
||||||
|
strategy TEXT NOT NULL,
|
||||||
|
latency_ms INT NOT NULL,
|
||||||
|
status_code SMALLINT NOT NULL,
|
||||||
|
is_streaming BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
prompt_tokens INT NOT NULL DEFAULT 0,
|
||||||
|
completion_tokens INT NOT NULL DEFAULT 0,
|
||||||
|
cost_original NUMERIC(10, 6),
|
||||||
|
cost_actual NUMERIC(10, 6),
|
||||||
|
cost_saved NUMERIC(10, 6)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Convert to hypertable (7-day chunks)
|
||||||
|
SELECT create_hypertable('request_events', 'time', chunk_time_interval => INTERVAL '7 days');
|
||||||
|
|
||||||
|
-- Indexes for dashboard queries
|
||||||
|
CREATE INDEX idx_events_org_time ON request_events (org_id, time DESC);
|
||||||
|
CREATE INDEX idx_events_model ON request_events (org_id, original_model, time DESC);
|
||||||
|
|
||||||
|
-- Continuous aggregates for dashboard rollups
|
||||||
|
|
||||||
|
-- Hourly rollup
|
||||||
|
CREATE MATERIALIZED VIEW request_events_hourly
|
||||||
|
WITH (timescaledb.continuous) AS
|
||||||
|
SELECT
|
||||||
|
time_bucket('1 hour', time) AS bucket,
|
||||||
|
org_id,
|
||||||
|
original_model,
|
||||||
|
routed_model,
|
||||||
|
provider,
|
||||||
|
strategy,
|
||||||
|
COUNT(*) AS request_count,
|
||||||
|
AVG(latency_ms)::INT AS avg_latency_ms,
|
||||||
|
PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY latency_ms)::INT AS p99_latency_ms,
|
||||||
|
SUM(prompt_tokens) AS total_prompt_tokens,
|
||||||
|
SUM(completion_tokens) AS total_completion_tokens,
|
||||||
|
SUM(cost_original) AS total_cost_original,
|
||||||
|
SUM(cost_actual) AS total_cost_actual,
|
||||||
|
SUM(cost_saved) AS total_cost_saved
|
||||||
|
FROM request_events
|
||||||
|
GROUP BY bucket, org_id, original_model, routed_model, provider, strategy;
|
||||||
|
|
||||||
|
-- Refresh policy: every hour, lag 10 minutes
|
||||||
|
SELECT add_continuous_aggregate_policy('request_events_hourly',
|
||||||
|
start_offset => INTERVAL '2 hours',
|
||||||
|
end_offset => INTERVAL '10 minutes',
|
||||||
|
schedule_interval => INTERVAL '1 hour');
|
||||||
|
|
||||||
|
-- Daily rollup
|
||||||
|
CREATE MATERIALIZED VIEW request_events_daily
|
||||||
|
WITH (timescaledb.continuous) AS
|
||||||
|
SELECT
|
||||||
|
time_bucket('1 day', time) AS bucket,
|
||||||
|
org_id,
|
||||||
|
original_model,
|
||||||
|
routed_model,
|
||||||
|
COUNT(*) AS request_count,
|
||||||
|
SUM(prompt_tokens) AS total_prompt_tokens,
|
||||||
|
SUM(completion_tokens) AS total_completion_tokens,
|
||||||
|
SUM(cost_original) AS total_cost_original,
|
||||||
|
SUM(cost_actual) AS total_cost_actual,
|
||||||
|
SUM(cost_saved) AS total_cost_saved
|
||||||
|
FROM request_events
|
||||||
|
GROUP BY bucket, org_id, original_model, routed_model;
|
||||||
|
|
||||||
|
SELECT add_continuous_aggregate_policy('request_events_daily',
|
||||||
|
start_offset => INTERVAL '3 days',
|
||||||
|
end_offset => INTERVAL '1 hour',
|
||||||
|
schedule_interval => INTERVAL '1 day');
|
||||||
|
|
||||||
|
-- Compression policy: compress chunks older than 30 days
|
||||||
|
ALTER TABLE request_events SET (
|
||||||
|
timescaledb.compress,
|
||||||
|
timescaledb.compress_segmentby = 'org_id',
|
||||||
|
timescaledb.compress_orderby = 'time DESC'
|
||||||
|
);
|
||||||
|
SELECT add_compression_policy('request_events', INTERVAL '30 days');
|
||||||
|
|
||||||
|
-- Retention policy: drop data older than 1 year (free tier: 30 days via app logic)
|
||||||
|
SELECT add_retention_policy('request_events', INTERVAL '365 days');
|
||||||
Reference in New Issue
Block a user