CREATE TABLE IF NOT EXISTS router_log_settings ( id INTEGER PRIMARY KEY CHECK (id = 1), enabled BOOLEAN NOT NULL DEFAULT false, interval_sec INTEGER NOT NULL DEFAULT 10 CHECK (interval_sec BETWEEN 5 AND 3600), retention_days INTEGER NOT NULL DEFAULT 14 CHECK (retention_days BETWEEN 1 AND 365) ); INSERT INTO router_log_settings(id) VALUES (1) ON CONFLICT DO NOTHING; -- No foreign key: collected history survives device deletion. CREATE TABLE IF NOT EXISTS router_log_collection_state ( server_id INTEGER PRIMARY KEY, server_name TEXT NOT NULL, host TEXT NOT NULL, generation INTEGER NOT NULL DEFAULT 0, snapshot JSONB NOT NULL DEFAULT '[]', last_collected_at TIMESTAMPTZ, last_error TEXT, gap_at TIMESTAMPTZ, next_poll_at TIMESTAMPTZ, failures INTEGER NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS router_log_entries ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, server_id INTEGER NOT NULL, server_name TEXT NOT NULL, host TEXT NOT NULL, router_id TEXT NOT NULL, raw_time TEXT NOT NULL, event_at TIMESTAMPTZ, received_at TIMESTAMPTZ NOT NULL, effective_at TIMESTAMPTZ NOT NULL, topics TEXT[] NOT NULL, level TEXT NOT NULL, message TEXT NOT NULL, generation INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS router_logs_server_time ON router_log_entries(server_id, effective_at DESC, id DESC); CREATE INDEX IF NOT EXISTS router_logs_time ON router_log_entries(effective_at DESC, id DESC); CREATE INDEX IF NOT EXISTS router_logs_level_time ON router_log_entries(level, effective_at DESC); CREATE INDEX IF NOT EXISTS router_logs_topics ON router_log_entries USING gin(topics); CREATE INDEX IF NOT EXISTS router_logs_received ON router_log_entries(received_at); CREATE INDEX IF NOT EXISTS router_logs_server_cursor ON router_log_entries(server_id, id);