109 lines
4.4 KiB
MySQL
109 lines
4.4 KiB
MySQL
|
|
-- 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)
|
||
|
|
);
|