91 lines
3.5 KiB
MySQL
91 lines
3.5 KiB
MySQL
|
|
-- dd0c/alert V1 schema — DynamoDB-style in PostgreSQL (Neon)
|
||
|
|
|
||
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||
|
|
|
||
|
|
-- Tenants
|
||
|
|
CREATE TABLE tenants (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
name TEXT NOT NULL,
|
||
|
|
slug TEXT NOT NULL UNIQUE,
|
||
|
|
tier TEXT NOT NULL DEFAULT 'free' CHECK (tier IN ('free', 'pro')),
|
||
|
|
alert_count_month INT NOT NULL DEFAULT 0,
|
||
|
|
alert_count_reset_at TIMESTAMPTZ NOT NULL DEFAULT date_trunc('month', now()) + interval '1 month',
|
||
|
|
stripe_customer_id TEXT,
|
||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
|
|
);
|
||
|
|
|
||
|
|
-- Webhook secrets per provider per tenant
|
||
|
|
CREATE TABLE webhook_secrets (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||
|
|
provider TEXT NOT NULL CHECK (provider IN ('datadog', 'pagerduty', 'opsgenie', 'grafana', 'custom')),
|
||
|
|
secret TEXT NOT NULL,
|
||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
|
|
UNIQUE(tenant_id, provider)
|
||
|
|
);
|
||
|
|
|
||
|
|
-- Incidents (correlation output)
|
||
|
|
CREATE TABLE incidents (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||
|
|
incident_key TEXT NOT NULL,
|
||
|
|
fingerprint TEXT NOT NULL,
|
||
|
|
service TEXT,
|
||
|
|
title TEXT NOT NULL,
|
||
|
|
severity TEXT NOT NULL CHECK (severity IN ('critical', 'high', 'medium', 'low', 'info')),
|
||
|
|
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'acknowledged', 'resolved', 'suppressed')),
|
||
|
|
alert_count INT NOT NULL DEFAULT 1,
|
||
|
|
first_alert_at TIMESTAMPTZ NOT NULL,
|
||
|
|
last_alert_at TIMESTAMPTZ NOT NULL,
|
||
|
|
resolved_at TIMESTAMPTZ,
|
||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
|
|
);
|
||
|
|
CREATE INDEX idx_incidents_tenant ON incidents(tenant_id, status, created_at DESC);
|
||
|
|
CREATE INDEX idx_incidents_fingerprint ON incidents(tenant_id, fingerprint);
|
||
|
|
|
||
|
|
-- Alerts (raw, linked to incidents)
|
||
|
|
CREATE TABLE alerts (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||
|
|
incident_id UUID REFERENCES incidents(id) ON DELETE SET NULL,
|
||
|
|
source_provider TEXT NOT NULL,
|
||
|
|
source_id TEXT NOT NULL,
|
||
|
|
fingerprint TEXT NOT NULL,
|
||
|
|
title TEXT NOT NULL,
|
||
|
|
severity TEXT NOT NULL,
|
||
|
|
status TEXT NOT NULL,
|
||
|
|
service TEXT,
|
||
|
|
environment TEXT,
|
||
|
|
tags JSONB NOT NULL DEFAULT '{}',
|
||
|
|
raw_payload JSONB NOT NULL,
|
||
|
|
received_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
|
|
);
|
||
|
|
CREATE INDEX idx_alerts_tenant ON alerts(tenant_id, received_at DESC);
|
||
|
|
CREATE INDEX idx_alerts_incident ON alerts(incident_id);
|
||
|
|
|
||
|
|
-- Notification configs
|
||
|
|
CREATE TABLE notification_configs (
|
||
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
||
|
|
channel TEXT NOT NULL CHECK (channel IN ('slack', 'email', 'webhook')),
|
||
|
|
config JSONB NOT NULL DEFAULT '{}',
|
||
|
|
min_severity TEXT NOT NULL DEFAULT 'medium',
|
||
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
||
|
|
UNIQUE(tenant_id, channel)
|
||
|
|
);
|
||
|
|
|
||
|
|
-- Free tier enforcement: 10K alerts/month, 7-day retention
|
||
|
|
-- Pro tier: unlimited alerts, 90-day retention
|
||
|
|
|
||
|
|
-- RLS
|
||
|
|
ALTER TABLE incidents ENABLE ROW LEVEL SECURITY;
|
||
|
|
ALTER TABLE alerts ENABLE ROW LEVEL SECURITY;
|
||
|
|
ALTER TABLE notification_configs ENABLE ROW LEVEL SECURITY;
|
||
|
|
|
||
|
|
CREATE POLICY tenant_iso_incidents ON incidents
|
||
|
|
USING (tenant_id::text = current_setting('app.tenant_id', true));
|
||
|
|
CREATE POLICY tenant_iso_alerts ON alerts
|
||
|
|
USING (tenant_id::text = current_setting('app.tenant_id', true));
|
||
|
|
CREATE POLICY tenant_iso_notif ON notification_configs
|
||
|
|
USING (tenant_id::text = current_setting('app.tenant_id', true));
|