-- ConfigVault Database Schema -- Run this in your Supabase SQL Editor -- Enable UUID extension CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- ============================================ -- APPS TABLE -- ============================================ CREATE TABLE apps ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, slug TEXT UNIQUE NOT NULL, description TEXT, icon_url TEXT, api_key TEXT UNIQUE NOT NULL DEFAULT encode(gen_random_bytes(32), 'hex'), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- ============================================ -- ENVIRONMENTS TABLE -- ============================================ CREATE TABLE environments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE, name TEXT NOT NULL CHECK (name IN ('development', 'staging', 'production')), UNIQUE(app_id, name) ); -- ============================================ -- CONFIG ENTRIES TABLE -- ============================================ CREATE TABLE config_entries ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), environment_id UUID NOT NULL REFERENCES environments(id) ON DELETE CASCADE, key TEXT NOT NULL, value TEXT NOT NULL, type TEXT NOT NULL DEFAULT 'text' CHECK (type IN ('text', 'secret', 'url', 'json', 'boolean', 'number')), description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(environment_id, key) ); -- ============================================ -- AUDIT LOGS TABLE -- ============================================ CREATE TABLE audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), app_id UUID REFERENCES apps(id) ON DELETE SET NULL, environment TEXT, action TEXT NOT NULL CHECK (action IN ('create', 'update', 'delete', 'rotate_key', 'create_app', 'delete_app')), key TEXT, old_value TEXT, -- null for creates actor TEXT NOT NULL DEFAULT 'admin', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- ============================================ -- AUTO-CREATE 3 ENVIRONMENTS ON NEW APP -- ============================================ CREATE OR REPLACE FUNCTION create_default_environments() RETURNS TRIGGER AS $$ BEGIN INSERT INTO environments (app_id, name) VALUES (NEW.id, 'development'), (NEW.id, 'staging'), (NEW.id, 'production'); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER on_app_created AFTER INSERT ON apps FOR EACH ROW EXECUTE FUNCTION create_default_environments(); -- ============================================ -- AUTO-UPDATE updated_at -- ============================================ CREATE OR REPLACE FUNCTION update_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER apps_updated_at BEFORE UPDATE ON apps FOR EACH ROW EXECUTE FUNCTION update_updated_at(); CREATE TRIGGER config_entries_updated_at BEFORE UPDATE ON config_entries FOR EACH ROW EXECUTE FUNCTION update_updated_at(); -- ============================================ -- ROW LEVEL SECURITY (disable for service role) -- ============================================ ALTER TABLE apps DISABLE ROW LEVEL SECURITY; ALTER TABLE environments DISABLE ROW LEVEL SECURITY; ALTER TABLE config_entries DISABLE ROW LEVEL SECURITY; ALTER TABLE audit_logs DISABLE ROW LEVEL SECURITY; -- ============================================ -- INDEXES -- ============================================ CREATE INDEX idx_environments_app_id ON environments(app_id); CREATE INDEX idx_config_entries_environment_id ON config_entries(environment_id); CREATE INDEX idx_audit_logs_app_id ON audit_logs(app_id); CREATE INDEX idx_apps_api_key ON apps(api_key); CREATE INDEX idx_apps_slug ON apps(slug);