SIP_GoldBees_Database/db_migrations/20260118_admin_rbac_views.sql
2026-02-01 14:14:57 +00:00

236 lines
7.3 KiB
PL/PgSQL

BEGIN;
ALTER TABLE app_user ADD COLUMN IF NOT EXISTS is_admin boolean NOT NULL DEFAULT false;
CREATE INDEX IF NOT EXISTS idx_app_user_is_admin ON app_user (is_admin);
CREATE INDEX IF NOT EXISTS idx_strategy_run_user_status ON strategy_run (user_id, status);
CREATE INDEX IF NOT EXISTS idx_strategy_run_user_created ON strategy_run (user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_engine_event_user_run_ts ON engine_event (user_id, run_id, ts DESC);
CREATE INDEX IF NOT EXISTS idx_strategy_log_user_run_ts ON strategy_log (user_id, run_id, ts DESC);
CREATE INDEX IF NOT EXISTS idx_event_ledger_user_run_logical ON event_ledger (user_id, run_id, logical_time);
CREATE INDEX IF NOT EXISTS idx_paper_order_user_run_ts ON paper_order (user_id, run_id, "timestamp" DESC);
CREATE INDEX IF NOT EXISTS idx_paper_trade_user_run_ts ON paper_trade (user_id, run_id, "timestamp" DESC);
CREATE INDEX IF NOT EXISTS idx_mtm_ledger_user_run_ts ON mtm_ledger (user_id, run_id, "timestamp" DESC);
CREATE INDEX IF NOT EXISTS idx_paper_equity_curve_user_run_ts ON paper_equity_curve (user_id, run_id, "timestamp" DESC);
CREATE INDEX IF NOT EXISTS idx_engine_status_user_run ON engine_status (user_id, run_id);
CREATE INDEX IF NOT EXISTS idx_engine_state_paper_user_run ON engine_state_paper (user_id, run_id);
CREATE OR REPLACE VIEW admin_user_metrics AS
WITH session_stats AS (
SELECT
user_id,
MIN(created_at) AS first_session_at,
MAX(COALESCE(last_seen_at, created_at)) AS last_login_at
FROM app_session
GROUP BY user_id
),
run_stats AS (
SELECT
user_id,
COUNT(*) AS runs_count,
MAX(CASE WHEN status = 'RUNNING' THEN run_id END) AS active_run_id,
MAX(CASE WHEN status = 'RUNNING' THEN status END) AS active_run_status,
MIN(created_at) AS first_run_at
FROM strategy_run
GROUP BY user_id
),
broker_stats AS (
SELECT user_id, BOOL_OR(connected) AS broker_connected
FROM user_broker
GROUP BY user_id
)
SELECT
u.id AS user_id,
u.username,
u.is_admin,
COALESCE(session_stats.first_session_at, run_stats.first_run_at) AS created_at,
session_stats.last_login_at,
COALESCE(run_stats.runs_count, 0) AS runs_count,
run_stats.active_run_id,
run_stats.active_run_status,
COALESCE(broker_stats.broker_connected, FALSE) AS broker_connected
FROM app_user u
LEFT JOIN session_stats ON session_stats.user_id = u.id
LEFT JOIN run_stats ON run_stats.user_id = u.id
LEFT JOIN broker_stats ON broker_stats.user_id = u.id;
CREATE OR REPLACE VIEW admin_run_metrics AS
WITH order_stats AS (
SELECT user_id, run_id, COUNT(*) AS order_count, MAX("timestamp") AS last_order_time
FROM paper_order
GROUP BY user_id, run_id
),
trade_stats AS (
SELECT user_id, run_id, COUNT(*) AS trade_count, MAX("timestamp") AS last_trade_time
FROM paper_trade
GROUP BY user_id, run_id
),
event_stats AS (
SELECT
user_id,
run_id,
MAX("timestamp") AS last_event_time,
MAX(CASE WHEN event = 'SIP_EXECUTED' THEN "timestamp" END) AS last_sip_time
FROM event_ledger
GROUP BY user_id, run_id
),
equity_latest AS (
SELECT DISTINCT ON (user_id, run_id)
user_id,
run_id,
equity AS equity_latest,
pnl AS pnl_latest,
"timestamp" AS equity_ts
FROM paper_equity_curve
ORDER BY user_id, run_id, "timestamp" DESC
),
mtm_latest AS (
SELECT DISTINCT ON (user_id, run_id)
user_id,
run_id,
"timestamp" AS mtm_ts
FROM mtm_ledger
ORDER BY user_id, run_id, "timestamp" DESC
),
log_latest AS (
SELECT user_id, run_id, MAX(ts) AS last_log_time
FROM strategy_log
GROUP BY user_id, run_id
),
engine_latest AS (
SELECT user_id, run_id, MAX(ts) AS last_engine_time
FROM engine_event
GROUP BY user_id, run_id
),
activity AS (
SELECT user_id, run_id, MAX(ts) AS last_event_time
FROM (
SELECT user_id, run_id, ts FROM engine_event
UNION ALL
SELECT user_id, run_id, ts FROM strategy_log
UNION ALL
SELECT user_id, run_id, "timestamp" AS ts FROM paper_order
UNION ALL
SELECT user_id, run_id, "timestamp" AS ts FROM paper_trade
UNION ALL
SELECT user_id, run_id, "timestamp" AS ts FROM mtm_ledger
UNION ALL
SELECT user_id, run_id, "timestamp" AS ts FROM paper_equity_curve
UNION ALL
SELECT user_id, run_id, "timestamp" AS ts FROM event_ledger
) t
GROUP BY user_id, run_id
)
SELECT
sr.run_id,
sr.user_id,
sr.status,
sr.created_at,
sr.started_at,
sr.stopped_at,
sr.strategy,
sr.mode,
sr.broker,
sc.sip_amount,
sc.sip_frequency_value,
sc.sip_frequency_unit,
sc.next_run AS next_sip_time,
activity.last_event_time,
event_stats.last_sip_time,
COALESCE(order_stats.order_count, 0) AS order_count,
COALESCE(trade_stats.trade_count, 0) AS trade_count,
equity_latest.equity_latest,
equity_latest.pnl_latest
FROM strategy_run sr
LEFT JOIN strategy_config sc
ON sc.user_id = sr.user_id AND sc.run_id = sr.run_id
LEFT JOIN order_stats
ON order_stats.user_id = sr.user_id AND order_stats.run_id = sr.run_id
LEFT JOIN trade_stats
ON trade_stats.user_id = sr.user_id AND trade_stats.run_id = sr.run_id
LEFT JOIN event_stats
ON event_stats.user_id = sr.user_id AND event_stats.run_id = sr.run_id
LEFT JOIN equity_latest
ON equity_latest.user_id = sr.user_id AND equity_latest.run_id = sr.run_id
LEFT JOIN mtm_latest
ON mtm_latest.user_id = sr.user_id AND mtm_latest.run_id = sr.run_id
LEFT JOIN log_latest
ON log_latest.user_id = sr.user_id AND log_latest.run_id = sr.run_id
LEFT JOIN engine_latest
ON engine_latest.user_id = sr.user_id AND engine_latest.run_id = sr.run_id
LEFT JOIN activity
ON activity.user_id = sr.user_id AND activity.run_id = sr.run_id;
CREATE OR REPLACE VIEW admin_engine_health AS
WITH activity AS (
SELECT user_id, run_id, MAX(ts) AS last_event_time
FROM (
SELECT user_id, run_id, ts FROM engine_event
UNION ALL
SELECT user_id, run_id, ts FROM strategy_log
UNION ALL
SELECT user_id, run_id, "timestamp" AS ts FROM event_ledger
) t
GROUP BY user_id, run_id
)
SELECT
sr.run_id,
sr.user_id,
sr.status,
activity.last_event_time,
es.status AS engine_status,
es.last_updated AS engine_status_ts
FROM strategy_run sr
LEFT JOIN activity
ON activity.user_id = sr.user_id AND activity.run_id = sr.run_id
LEFT JOIN engine_status es
ON es.user_id = sr.user_id AND es.run_id = sr.run_id;
CREATE OR REPLACE VIEW admin_order_stats AS
SELECT
user_id,
run_id,
COUNT(*) AS total_orders,
COUNT(*) FILTER (WHERE "timestamp" >= now() - interval '24 hours') AS orders_last_24h,
COUNT(*) FILTER (WHERE status = 'FILLED') AS filled_orders
FROM paper_order
GROUP BY user_id, run_id;
CREATE OR REPLACE VIEW admin_ledger_stats AS
WITH mtm_latest AS (
SELECT DISTINCT ON (user_id, run_id)
user_id,
run_id,
portfolio_value,
pnl,
"timestamp" AS mtm_ts
FROM mtm_ledger
ORDER BY user_id, run_id, "timestamp" DESC
),
equity_latest AS (
SELECT DISTINCT ON (user_id, run_id)
user_id,
run_id,
equity,
pnl,
"timestamp" AS equity_ts
FROM paper_equity_curve
ORDER BY user_id, run_id, "timestamp" DESC
)
SELECT
sr.user_id,
sr.run_id,
mtm_latest.portfolio_value AS mtm_value,
mtm_latest.pnl AS mtm_pnl,
mtm_latest.mtm_ts,
equity_latest.equity AS equity_value,
equity_latest.pnl AS equity_pnl,
equity_latest.equity_ts
FROM strategy_run sr
LEFT JOIN mtm_latest
ON mtm_latest.user_id = sr.user_id AND mtm_latest.run_id = sr.run_id
LEFT JOIN equity_latest
ON equity_latest.user_id = sr.user_id AND equity_latest.run_id = sr.run_id;
COMMIT;