merge upstream main
This commit is contained in:
15
backend/migrations/006_add_users_allowed_groups_compat.sql
Normal file
15
backend/migrations/006_add_users_allowed_groups_compat.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- 兼容旧库:若尚未创建 user_allowed_groups,则确保 users.allowed_groups 存在,避免 007 迁移回填失败。
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regclass('public.user_allowed_groups') IS NULL THEN
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'users'
|
||||
) THEN
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS allowed_groups BIGINT[] DEFAULT NULL;
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
27
backend/migrations/006b_guard_users_allowed_groups.sql
Normal file
27
backend/migrations/006b_guard_users_allowed_groups.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
-- 兼容缺失 users.allowed_groups 的老库,确保 007 回填可执行。
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'users'
|
||||
) THEN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'users'
|
||||
AND column_name = 'allowed_groups'
|
||||
) THEN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM schema_migrations
|
||||
WHERE filename = '014_drop_legacy_allowed_groups.sql'
|
||||
) THEN
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS allowed_groups BIGINT[] DEFAULT NULL;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
21
backend/migrations/042_add_usage_cleanup_tasks.sql
Normal file
21
backend/migrations/042_add_usage_cleanup_tasks.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
-- 042_add_usage_cleanup_tasks.sql
|
||||
-- 使用记录清理任务表
|
||||
|
||||
CREATE TABLE IF NOT EXISTS usage_cleanup_tasks (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
status VARCHAR(20) NOT NULL,
|
||||
filters JSONB NOT NULL,
|
||||
created_by BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
|
||||
deleted_rows BIGINT NOT NULL DEFAULT 0,
|
||||
error_message TEXT,
|
||||
started_at TIMESTAMPTZ,
|
||||
finished_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_cleanup_tasks_status_created_at
|
||||
ON usage_cleanup_tasks(status, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_cleanup_tasks_created_at
|
||||
ON usage_cleanup_tasks(created_at DESC);
|
||||
10
backend/migrations/043_add_usage_cleanup_cancel_audit.sql
Normal file
10
backend/migrations/043_add_usage_cleanup_cancel_audit.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- 043_add_usage_cleanup_cancel_audit.sql
|
||||
-- usage_cleanup_tasks 取消任务审计字段
|
||||
|
||||
ALTER TABLE usage_cleanup_tasks
|
||||
ADD COLUMN IF NOT EXISTS canceled_by BIGINT REFERENCES users(id) ON DELETE SET NULL,
|
||||
ADD COLUMN IF NOT EXISTS canceled_at TIMESTAMPTZ;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_cleanup_tasks_canceled_at
|
||||
ON usage_cleanup_tasks(canceled_at DESC);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- 043_add_group_invalid_request_fallback.sql
|
||||
-- 043b_add_group_invalid_request_fallback.sql
|
||||
-- 添加无效请求兜底分组配置
|
||||
|
||||
-- 添加 fallback_group_id_on_invalid_request 字段:无效请求兜底使用的分组
|
||||
12
backend/migrations/044_add_user_totp.sql
Normal file
12
backend/migrations/044_add_user_totp.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- 为 users 表添加 TOTP 双因素认证字段
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS totp_secret_encrypted TEXT DEFAULT NULL,
|
||||
ADD COLUMN IF NOT EXISTS totp_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ADD COLUMN IF NOT EXISTS totp_enabled_at TIMESTAMPTZ DEFAULT NULL;
|
||||
|
||||
COMMENT ON COLUMN users.totp_secret_encrypted IS 'AES-256-GCM 加密的 TOTP 密钥';
|
||||
COMMENT ON COLUMN users.totp_enabled IS '是否启用 TOTP 双因素认证';
|
||||
COMMENT ON COLUMN users.totp_enabled_at IS 'TOTP 启用时间';
|
||||
|
||||
-- 创建索引以支持快速查询启用 2FA 的用户
|
||||
CREATE INDEX IF NOT EXISTS idx_users_totp_enabled ON users(totp_enabled) WHERE deleted_at IS NULL AND totp_enabled = true;
|
||||
44
backend/migrations/045_add_announcements.sql
Normal file
44
backend/migrations/045_add_announcements.sql
Normal file
@@ -0,0 +1,44 @@
|
||||
-- 创建公告表
|
||||
CREATE TABLE IF NOT EXISTS announcements (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
title VARCHAR(200) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||||
targeting JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
starts_at TIMESTAMPTZ DEFAULT NULL,
|
||||
ends_at TIMESTAMPTZ DEFAULT NULL,
|
||||
created_by BIGINT DEFAULT NULL REFERENCES users(id) ON DELETE SET NULL,
|
||||
updated_by BIGINT DEFAULT NULL REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 公告已读表
|
||||
CREATE TABLE IF NOT EXISTS announcement_reads (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
announcement_id BIGINT NOT NULL REFERENCES announcements(id) ON DELETE CASCADE,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
read_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(announcement_id, user_id)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX IF NOT EXISTS idx_announcements_status ON announcements(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_announcements_starts_at ON announcements(starts_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_announcements_ends_at ON announcements(ends_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_announcements_created_at ON announcements(created_at);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_announcement_reads_announcement_id ON announcement_reads(announcement_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_announcement_reads_user_id ON announcement_reads(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_announcement_reads_read_at ON announcement_reads(read_at);
|
||||
|
||||
COMMENT ON TABLE announcements IS '系统公告';
|
||||
COMMENT ON COLUMN announcements.status IS '状态: draft, active, archived';
|
||||
COMMENT ON COLUMN announcements.targeting IS '展示条件(JSON 规则)';
|
||||
COMMENT ON COLUMN announcements.starts_at IS '开始展示时间(为空表示立即生效)';
|
||||
COMMENT ON COLUMN announcements.ends_at IS '结束展示时间(为空表示永久生效)';
|
||||
|
||||
COMMENT ON TABLE announcement_reads IS '公告已读记录';
|
||||
COMMENT ON COLUMN announcement_reads.read_at IS '用户首次已读时间';
|
||||
|
||||
Reference in New Issue
Block a user