feat(monitor/db): goose migrations 0001-0003 (alerts, panel data, collector state)

This commit is contained in:
CarterPerez-dev 2026-05-01 06:28:51 -04:00
parent 618aaf43e8
commit 73c56333e6
3 changed files with 281 additions and 0 deletions

View File

@ -0,0 +1,110 @@
-- ©AngelaMos | 2026
-- 0001_alerts.sql
-- +goose Up
-- +goose StatementBegin
CREATE TABLE alert_rules (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name text NOT NULL,
topic text NOT NULL,
predicate text NOT NULL,
cooldown_sec integer NOT NULL DEFAULT 300,
enabled boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX idx_alert_rules_user ON alert_rules(user_id) WHERE enabled = true;
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE alert_channels (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type text NOT NULL,
label text NOT NULL,
config_enc bytea NOT NULL,
nonce bytea NOT NULL,
invalid boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX idx_alert_channels_user ON alert_channels(user_id);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE alert_rule_channels (
rule_id uuid NOT NULL REFERENCES alert_rules(id) ON DELETE CASCADE,
channel_id uuid NOT NULL REFERENCES alert_channels(id) ON DELETE CASCADE,
PRIMARY KEY (rule_id, channel_id)
);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE alert_history (
id bigserial PRIMARY KEY,
rule_id uuid NOT NULL REFERENCES alert_rules(id) ON DELETE CASCADE,
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
fired_at timestamptz NOT NULL DEFAULT now(),
payload jsonb NOT NULL,
delivered_to text[] NOT NULL DEFAULT '{}',
delivery_errors jsonb
);
CREATE INDEX idx_alert_history_user_time ON alert_history(user_id, fired_at DESC);
CREATE INDEX idx_alert_history_fired_brin ON alert_history USING BRIN (fired_at);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE telegram_webhooks (
user_id uuid PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
webhook_uuid uuid NOT NULL UNIQUE,
secret_token text NOT NULL,
bot_token_enc bytea NOT NULL,
bot_token_nonce bytea NOT NULL,
chat_id bigint,
pending_link boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now()
);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE user_preferences (
user_id uuid PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
watched_country text,
watched_asns integer[] NOT NULL DEFAULT '{}',
observer_lat double precision,
observer_lon double precision,
observer_alt_m double precision,
digest_enabled boolean NOT NULL DEFAULT false,
digest_local_tz text NOT NULL DEFAULT 'UTC',
digest_local_time time NOT NULL DEFAULT '08:00',
digest_window_hours integer NOT NULL DEFAULT 24,
digest_channel_ids uuid[] NOT NULL DEFAULT '{}',
chime_enabled boolean NOT NULL DEFAULT true,
chime_audio_object text,
presentation_default boolean NOT NULL DEFAULT false,
updated_at timestamptz NOT NULL DEFAULT now()
);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE digest_runs (
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
fired_date date NOT NULL,
fired_at timestamptz NOT NULL DEFAULT now(),
status text NOT NULL,
error text,
PRIMARY KEY (user_id, fired_date)
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS digest_runs;
DROP TABLE IF EXISTS user_preferences;
DROP TABLE IF EXISTS telegram_webhooks;
DROP TABLE IF EXISTS alert_history;
DROP TABLE IF EXISTS alert_rule_channels;
DROP TABLE IF EXISTS alert_channels;
DROP TABLE IF EXISTS alert_rules;
-- +goose StatementEnd

View File

@ -0,0 +1,151 @@
-- ©AngelaMos | 2026
-- 0002_panel_data.sql
-- +goose Up
-- +goose StatementBegin
CREATE TABLE cve_events (
cve_id text PRIMARY KEY,
published timestamptz,
last_modified timestamptz NOT NULL,
severity text,
cvss_score numeric(3,1),
epss_score numeric(5,4),
epss_percentile numeric(5,4),
in_kev boolean NOT NULL DEFAULT false,
payload jsonb NOT NULL
);
CREATE INDEX idx_cve_lastmod_brin ON cve_events USING BRIN (last_modified);
CREATE INDEX idx_cve_severity_lastmod ON cve_events (severity, last_modified DESC);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE kev_entries (
cve_id text PRIMARY KEY,
vendor text,
product text,
vulnerability_name text,
date_added date NOT NULL,
due_date date,
ransomware_use text,
payload jsonb NOT NULL
);
CREATE INDEX idx_kev_dateadded ON kev_entries (date_added DESC);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE earthquakes (
id text PRIMARY KEY,
occurred_at timestamptz NOT NULL,
mag numeric(3,1) NOT NULL,
place text,
geom_lon double precision NOT NULL,
geom_lat double precision NOT NULL,
depth_km double precision,
payload jsonb NOT NULL
);
CREATE INDEX idx_quakes_time_brin ON earthquakes USING BRIN (occurred_at);
CREATE INDEX idx_quakes_mag ON earthquakes (mag DESC, occurred_at DESC);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE ransomware_victims (
id text PRIMARY KEY,
post_title text NOT NULL,
group_name text NOT NULL,
discovered_at timestamptz NOT NULL,
country text,
sector text,
payload jsonb NOT NULL
);
CREATE INDEX idx_rans_time_brin ON ransomware_victims USING BRIN (discovered_at);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE btc_eth_ticks (
symbol text NOT NULL,
ts timestamptz NOT NULL,
price numeric(18,8) NOT NULL,
volume_24h numeric(20,8),
PRIMARY KEY (symbol, ts)
);
CREATE INDEX idx_ticks_time_brin ON btc_eth_ticks USING BRIN (ts);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE btc_eth_minute (
symbol text NOT NULL,
minute timestamptz NOT NULL,
open numeric(18,8) NOT NULL,
high numeric(18,8) NOT NULL,
low numeric(18,8) NOT NULL,
close numeric(18,8) NOT NULL,
volume numeric(20,8),
PRIMARY KEY (symbol, minute)
);
CREATE INDEX idx_minute_time_brin ON btc_eth_minute USING BRIN (minute);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE outage_events (
id text PRIMARY KEY,
started_at timestamptz NOT NULL,
ended_at timestamptz,
locations text[] NOT NULL DEFAULT '{}',
asns integer[] NOT NULL DEFAULT '{}',
cause text,
outage_type text,
payload jsonb NOT NULL
);
CREATE INDEX idx_outage_start_brin ON outage_events USING BRIN (started_at);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE bgp_hijack_events (
id bigint PRIMARY KEY,
detected_at timestamptz NOT NULL,
started_at timestamptz NOT NULL,
duration_sec integer,
confidence smallint,
hijacker_asn integer,
victim_asns integer[] NOT NULL DEFAULT '{}',
prefixes cidr[] NOT NULL DEFAULT '{}',
payload jsonb NOT NULL
);
CREATE INDEX idx_hijack_time_brin ON bgp_hijack_events USING BRIN (detected_at);
CREATE INDEX idx_hijack_conf_time ON bgp_hijack_events (confidence DESC, detected_at DESC);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE dshield_snapshots (
ts timestamptz NOT NULL,
kind text NOT NULL,
payload jsonb NOT NULL,
PRIMARY KEY (ts, kind)
);
CREATE INDEX idx_dshield_ts_brin ON dshield_snapshots USING BRIN (ts);
-- +goose StatementEnd
-- +goose StatementBegin
CREATE TABLE world_events (
id text PRIMARY KEY,
source text NOT NULL,
occurred_at timestamptz NOT NULL,
headline text NOT NULL,
payload jsonb NOT NULL
);
CREATE INDEX idx_world_time_brin ON world_events USING BRIN (occurred_at);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS world_events;
DROP TABLE IF EXISTS dshield_snapshots;
DROP TABLE IF EXISTS bgp_hijack_events;
DROP TABLE IF EXISTS outage_events;
DROP TABLE IF EXISTS btc_eth_minute;
DROP TABLE IF EXISTS btc_eth_ticks;
DROP TABLE IF EXISTS ransomware_victims;
DROP TABLE IF EXISTS earthquakes;
DROP TABLE IF EXISTS kev_entries;
DROP TABLE IF EXISTS cve_events;
-- +goose StatementEnd

View File

@ -0,0 +1,20 @@
-- ©AngelaMos | 2026
-- 0003_collector_state.sql
-- +goose Up
-- +goose StatementBegin
CREATE TABLE collector_state (
name text PRIMARY KEY,
state text NOT NULL,
last_success_at timestamptz,
last_error_at timestamptz,
last_error text,
last_event_count bigint NOT NULL DEFAULT 0,
updated_at timestamptz NOT NULL DEFAULT now()
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS collector_state;
-- +goose StatementEnd