- DB Migration 081: 新增 account_behavior_hourly / account_risk_scores 表 - 行为采集:Gateway/OpenAI Gateway RecordUsage 注入 fire-and-forget CollectBehaviorAsync - SQL 打分引擎:CTE 加权特征向量 → risk_score [0-1],UPSERT 保留 idle_override - RiskSettings:Redis 缓存 → DB fallback → 默认值(observe 模式) - REST API:/admin/risk/summary|accounts|accounts/:id|settings - 前端:Pinia store + RiskControlView + 6 子组件(donut/radar/line 纯 SVG 图表) - 侧边栏新增 Risk Control 入口(ShieldExclamationIcon) - 反风控优化:移除 Antigravity 后台定时刷新,改为按需刷新避免 idle 封号
50 lines
2.3 KiB
SQL
50 lines
2.3 KiB
SQL
-- +migrate Up
|
|
|
|
CREATE TABLE IF NOT EXISTS account_behavior_hourly (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
hour_bucket TIMESTAMPTZ NOT NULL,
|
|
api_call_count BIGINT NOT NULL DEFAULT 0,
|
|
stream_count BIGINT NOT NULL DEFAULT 0,
|
|
total_input_tokens BIGINT NOT NULL DEFAULT 0,
|
|
total_output_tokens BIGINT NOT NULL DEFAULT 0,
|
|
total_duration_ms BIGINT NOT NULL DEFAULT 0,
|
|
p50_duration_ms INT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT uq_account_behavior_hourly UNIQUE (account_id, hour_bucket)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_account_behavior_hourly_account_id ON account_behavior_hourly (account_id);
|
|
CREATE INDEX IF NOT EXISTS idx_account_behavior_hourly_hour_bucket ON account_behavior_hourly (hour_bucket DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS account_risk_scores (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
account_id BIGINT NOT NULL,
|
|
risk_score DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
risk_level VARCHAR(16) NOT NULL DEFAULT 'LOW',
|
|
risk_reasons JSONB NOT NULL DEFAULT '{}',
|
|
feature_vector JSONB NOT NULL DEFAULT '{}',
|
|
scored_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
model_version INT NOT NULL DEFAULT 1,
|
|
idle_override BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT uq_account_risk_scores_account_id UNIQUE (account_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_account_risk_scores_risk_level ON account_risk_scores (risk_level);
|
|
CREATE INDEX IF NOT EXISTS idx_account_risk_scores_risk_score ON account_risk_scores (risk_score DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_account_risk_scores_scored_at ON account_risk_scores (scored_at DESC);
|
|
|
|
-- +migrate Down
|
|
|
|
DROP INDEX IF EXISTS idx_account_risk_scores_scored_at;
|
|
DROP INDEX IF EXISTS idx_account_risk_scores_risk_score;
|
|
DROP INDEX IF EXISTS idx_account_risk_scores_risk_level;
|
|
DROP TABLE IF EXISTS account_risk_scores;
|
|
|
|
DROP INDEX IF EXISTS idx_account_behavior_hourly_hour_bucket;
|
|
DROP INDEX IF EXISTS idx_account_behavior_hourly_account_id;
|
|
DROP TABLE IF EXISTS account_behavior_hourly;
|