|
|
|
|
@@ -13,6 +13,7 @@ CREATE TABLE users (
|
|
|
|
|
provider TEXT NOT NULL,
|
|
|
|
|
email TEXT,
|
|
|
|
|
display_name TEXT,
|
|
|
|
|
password_hash TEXT,
|
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
|
|
|
);
|
|
|
|
|
@@ -39,12 +40,20 @@ CREATE TABLE groups (
|
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Built-in Admins group
|
|
|
|
|
INSERT INTO groups (id, name) VALUES
|
|
|
|
|
('00000000-0000-0000-0000-000000000010', 'Admins');
|
|
|
|
|
|
|
|
|
|
CREATE TABLE group_roles (
|
|
|
|
|
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
|
|
|
|
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
|
|
|
|
PRIMARY KEY (group_id, role_id)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Assign ADMIN role to Admins group
|
|
|
|
|
INSERT INTO group_roles (group_id, role_id) VALUES
|
|
|
|
|
('00000000-0000-0000-0000-000000000010', '00000000-0000-0000-0000-000000000004');
|
|
|
|
|
|
|
|
|
|
CREATE TABLE user_groups (
|
|
|
|
|
user_id TEXT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
|
|
|
|
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
|
|
|
|
|
@@ -70,7 +79,7 @@ CREATE TABLE executions (
|
|
|
|
|
execution_id TEXT NOT NULL,
|
|
|
|
|
route_id TEXT NOT NULL,
|
|
|
|
|
agent_id TEXT NOT NULL,
|
|
|
|
|
group_name TEXT NOT NULL,
|
|
|
|
|
application_name TEXT NOT NULL,
|
|
|
|
|
status TEXT NOT NULL,
|
|
|
|
|
correlation_id TEXT,
|
|
|
|
|
exchange_id TEXT,
|
|
|
|
|
@@ -89,7 +98,7 @@ SELECT create_hypertable('executions', 'start_time', chunk_time_interval => INTE
|
|
|
|
|
|
|
|
|
|
CREATE INDEX idx_executions_agent_time ON executions (agent_id, start_time DESC);
|
|
|
|
|
CREATE INDEX idx_executions_route_time ON executions (route_id, start_time DESC);
|
|
|
|
|
CREATE INDEX idx_executions_group_time ON executions (group_name, start_time DESC);
|
|
|
|
|
CREATE INDEX idx_executions_app_time ON executions (application_name, start_time DESC);
|
|
|
|
|
CREATE INDEX idx_executions_correlation ON executions (correlation_id);
|
|
|
|
|
|
|
|
|
|
CREATE TABLE processor_executions (
|
|
|
|
|
@@ -98,7 +107,7 @@ CREATE TABLE processor_executions (
|
|
|
|
|
processor_id TEXT NOT NULL,
|
|
|
|
|
processor_type TEXT NOT NULL,
|
|
|
|
|
diagram_node_id TEXT,
|
|
|
|
|
group_name TEXT NOT NULL,
|
|
|
|
|
application_name TEXT NOT NULL,
|
|
|
|
|
route_id TEXT NOT NULL,
|
|
|
|
|
depth INT NOT NULL,
|
|
|
|
|
parent_processor_id TEXT,
|
|
|
|
|
@@ -138,6 +147,13 @@ SELECT create_hypertable('agent_metrics', 'collected_at', chunk_time_interval =>
|
|
|
|
|
|
|
|
|
|
CREATE INDEX idx_metrics_agent_name ON agent_metrics (agent_id, metric_name, collected_at DESC);
|
|
|
|
|
|
|
|
|
|
-- Retention: drop agent_metrics chunks older than 90 days
|
|
|
|
|
SELECT add_retention_policy('agent_metrics', INTERVAL '90 days', if_not_exists => true);
|
|
|
|
|
|
|
|
|
|
-- Compression: compress agent_metrics chunks older than 7 days
|
|
|
|
|
ALTER TABLE agent_metrics SET (timescaledb.compress);
|
|
|
|
|
SELECT add_compression_policy('agent_metrics', INTERVAL '7 days', if_not_exists => true);
|
|
|
|
|
|
|
|
|
|
-- =============================================================
|
|
|
|
|
-- Route diagrams
|
|
|
|
|
-- =============================================================
|
|
|
|
|
@@ -153,22 +169,56 @@ CREATE TABLE route_diagrams (
|
|
|
|
|
CREATE INDEX idx_diagrams_route_agent ON route_diagrams (route_id, agent_id);
|
|
|
|
|
|
|
|
|
|
-- =============================================================
|
|
|
|
|
-- OIDC configuration
|
|
|
|
|
-- Agent events
|
|
|
|
|
-- =============================================================
|
|
|
|
|
|
|
|
|
|
CREATE TABLE oidc_config (
|
|
|
|
|
config_id TEXT PRIMARY KEY DEFAULT 'default',
|
|
|
|
|
enabled BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
|
issuer_uri TEXT,
|
|
|
|
|
client_id TEXT,
|
|
|
|
|
client_secret TEXT,
|
|
|
|
|
roles_claim TEXT,
|
|
|
|
|
default_roles TEXT[] NOT NULL DEFAULT '{}',
|
|
|
|
|
auto_signup BOOLEAN DEFAULT false,
|
|
|
|
|
display_name_claim TEXT,
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
|
|
|
CREATE TABLE agent_events (
|
|
|
|
|
id BIGSERIAL PRIMARY KEY,
|
|
|
|
|
agent_id TEXT NOT NULL,
|
|
|
|
|
app_id TEXT NOT NULL,
|
|
|
|
|
event_type TEXT NOT NULL,
|
|
|
|
|
detail TEXT,
|
|
|
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX idx_agent_events_agent ON agent_events(agent_id, timestamp DESC);
|
|
|
|
|
CREATE INDEX idx_agent_events_app ON agent_events(app_id, timestamp DESC);
|
|
|
|
|
CREATE INDEX idx_agent_events_time ON agent_events(timestamp DESC);
|
|
|
|
|
|
|
|
|
|
-- =============================================================
|
|
|
|
|
-- Server configuration
|
|
|
|
|
-- =============================================================
|
|
|
|
|
|
|
|
|
|
CREATE TABLE server_config (
|
|
|
|
|
config_key TEXT PRIMARY KEY,
|
|
|
|
|
config_val JSONB NOT NULL,
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
|
|
|
updated_by TEXT
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- =============================================================
|
|
|
|
|
-- Admin
|
|
|
|
|
-- =============================================================
|
|
|
|
|
|
|
|
|
|
CREATE TABLE audit_log (
|
|
|
|
|
id BIGSERIAL PRIMARY KEY,
|
|
|
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
|
|
|
username TEXT NOT NULL,
|
|
|
|
|
action TEXT NOT NULL,
|
|
|
|
|
category TEXT NOT NULL,
|
|
|
|
|
target TEXT,
|
|
|
|
|
detail JSONB,
|
|
|
|
|
result TEXT NOT NULL,
|
|
|
|
|
ip_address TEXT,
|
|
|
|
|
user_agent TEXT
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX idx_audit_log_timestamp ON audit_log (timestamp DESC);
|
|
|
|
|
CREATE INDEX idx_audit_log_username ON audit_log (username);
|
|
|
|
|
CREATE INDEX idx_audit_log_category ON audit_log (category);
|
|
|
|
|
CREATE INDEX idx_audit_log_action ON audit_log (action);
|
|
|
|
|
CREATE INDEX idx_audit_log_target ON audit_log (target);
|
|
|
|
|
|
|
|
|
|
-- =============================================================
|
|
|
|
|
-- Continuous aggregates
|
|
|
|
|
-- =============================================================
|
|
|
|
|
@@ -197,7 +247,7 @@ CREATE MATERIALIZED VIEW stats_1m_app
|
|
|
|
|
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
|
|
|
|
|
SELECT
|
|
|
|
|
time_bucket('1 minute', start_time) AS bucket,
|
|
|
|
|
group_name,
|
|
|
|
|
application_name,
|
|
|
|
|
COUNT(*) AS total_count,
|
|
|
|
|
COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count,
|
|
|
|
|
COUNT(*) FILTER (WHERE status = 'RUNNING') AS running_count,
|
|
|
|
|
@@ -206,7 +256,7 @@ SELECT
|
|
|
|
|
approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration
|
|
|
|
|
FROM executions
|
|
|
|
|
WHERE status IS NOT NULL
|
|
|
|
|
GROUP BY bucket, group_name
|
|
|
|
|
GROUP BY bucket, application_name
|
|
|
|
|
WITH NO DATA;
|
|
|
|
|
|
|
|
|
|
SELECT add_continuous_aggregate_policy('stats_1m_app',
|
|
|
|
|
@@ -218,7 +268,7 @@ CREATE MATERIALIZED VIEW stats_1m_route
|
|
|
|
|
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
|
|
|
|
|
SELECT
|
|
|
|
|
time_bucket('1 minute', start_time) AS bucket,
|
|
|
|
|
group_name,
|
|
|
|
|
application_name,
|
|
|
|
|
route_id,
|
|
|
|
|
COUNT(*) AS total_count,
|
|
|
|
|
COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count,
|
|
|
|
|
@@ -228,7 +278,7 @@ SELECT
|
|
|
|
|
approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration
|
|
|
|
|
FROM executions
|
|
|
|
|
WHERE status IS NOT NULL
|
|
|
|
|
GROUP BY bucket, group_name, route_id
|
|
|
|
|
GROUP BY bucket, application_name, route_id
|
|
|
|
|
WITH NO DATA;
|
|
|
|
|
|
|
|
|
|
SELECT add_continuous_aggregate_policy('stats_1m_route',
|
|
|
|
|
@@ -240,7 +290,7 @@ CREATE MATERIALIZED VIEW stats_1m_processor
|
|
|
|
|
WITH (timescaledb.continuous, timescaledb.materialized_only = false) AS
|
|
|
|
|
SELECT
|
|
|
|
|
time_bucket('1 minute', start_time) AS bucket,
|
|
|
|
|
group_name,
|
|
|
|
|
application_name,
|
|
|
|
|
route_id,
|
|
|
|
|
processor_type,
|
|
|
|
|
COUNT(*) AS total_count,
|
|
|
|
|
@@ -249,7 +299,7 @@ SELECT
|
|
|
|
|
MAX(duration_ms) AS duration_max,
|
|
|
|
|
approx_percentile(0.99, percentile_agg(duration_ms::DOUBLE PRECISION)) AS p99_duration
|
|
|
|
|
FROM processor_executions
|
|
|
|
|
GROUP BY bucket, group_name, route_id, processor_type
|
|
|
|
|
GROUP BY bucket, application_name, route_id, processor_type
|
|
|
|
|
WITH NO DATA;
|
|
|
|
|
|
|
|
|
|
SELECT add_continuous_aggregate_policy('stats_1m_processor',
|
|
|
|
|
@@ -257,33 +307,23 @@ SELECT add_continuous_aggregate_policy('stats_1m_processor',
|
|
|
|
|
end_offset => INTERVAL '1 minute',
|
|
|
|
|
schedule_interval => INTERVAL '1 minute');
|
|
|
|
|
|
|
|
|
|
-- =============================================================
|
|
|
|
|
-- Admin
|
|
|
|
|
-- =============================================================
|
|
|
|
|
CREATE MATERIALIZED VIEW stats_1m_processor_detail
|
|
|
|
|
WITH (timescaledb.continuous) AS
|
|
|
|
|
SELECT
|
|
|
|
|
time_bucket('1 minute', start_time) AS bucket,
|
|
|
|
|
application_name,
|
|
|
|
|
route_id,
|
|
|
|
|
processor_id,
|
|
|
|
|
processor_type,
|
|
|
|
|
COUNT(*) AS total_count,
|
|
|
|
|
COUNT(*) FILTER (WHERE status = 'FAILED') AS failed_count,
|
|
|
|
|
SUM(duration_ms) AS duration_sum,
|
|
|
|
|
MAX(duration_ms) AS duration_max,
|
|
|
|
|
approx_percentile(0.99, percentile_agg(duration_ms)) AS p99_duration
|
|
|
|
|
FROM processor_executions
|
|
|
|
|
GROUP BY bucket, application_name, route_id, processor_id, processor_type;
|
|
|
|
|
|
|
|
|
|
CREATE TABLE admin_thresholds (
|
|
|
|
|
id INTEGER PRIMARY KEY DEFAULT 1,
|
|
|
|
|
config JSONB NOT NULL DEFAULT '{}',
|
|
|
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
|
|
|
updated_by TEXT NOT NULL,
|
|
|
|
|
CONSTRAINT single_row CHECK (id = 1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE TABLE audit_log (
|
|
|
|
|
id BIGSERIAL PRIMARY KEY,
|
|
|
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
|
|
|
username TEXT NOT NULL,
|
|
|
|
|
action TEXT NOT NULL,
|
|
|
|
|
category TEXT NOT NULL,
|
|
|
|
|
target TEXT,
|
|
|
|
|
detail JSONB,
|
|
|
|
|
result TEXT NOT NULL,
|
|
|
|
|
ip_address TEXT,
|
|
|
|
|
user_agent TEXT
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX idx_audit_log_timestamp ON audit_log (timestamp DESC);
|
|
|
|
|
CREATE INDEX idx_audit_log_username ON audit_log (username);
|
|
|
|
|
CREATE INDEX idx_audit_log_category ON audit_log (category);
|
|
|
|
|
CREATE INDEX idx_audit_log_action ON audit_log (action);
|
|
|
|
|
CREATE INDEX idx_audit_log_target ON audit_log (target);
|
|
|
|
|
SELECT add_continuous_aggregate_policy('stats_1m_processor_detail',
|
|
|
|
|
start_offset => INTERVAL '1 hour',
|
|
|
|
|
end_offset => INTERVAL '1 minute',
|
|
|
|
|
schedule_interval => INTERVAL '1 minute');
|
|
|
|
|
|