Files
team-api/migrations/000005_v0_1_5_version.sql
2026-05-30 01:28:09 +08:00

196 lines
9.0 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- +goose Up
-- 租户等级系统 + 模型分组功能 + 补充缺失索引
-- ============================================================
-- 一、租户等级系统:基于累计充值的自动等级体系
-- ============================================================
-- 1. 新建等级配置表
CREATE TABLE tnt_tenant_level_configs (
id BIGSERIAL PRIMARY KEY,
level INT NOT NULL,
name VARCHAR(32) NOT NULL,
cumulative_recharge_threshold NUMERIC(20,10) NOT NULL,
max_members INT NOT NULL DEFAULT 5,
max_concurrency INT NOT NULL DEFAULT 10,
price_multiplier NUMERIC(5,4) NOT NULL DEFAULT 1.0000,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT now() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL,
CONSTRAINT uk_tnt_tenant_level_configs_level UNIQUE (level)
);
COMMENT ON TABLE tnt_tenant_level_configs IS '租户等级配置表';
COMMENT ON COLUMN tnt_tenant_level_configs.level IS '等级号(1, 2, 3...)';
COMMENT ON COLUMN tnt_tenant_level_configs.name IS '等级名称';
COMMENT ON COLUMN tnt_tenant_level_configs.cumulative_recharge_threshold IS '累计充值阈值(USD),达到此值自动升级';
COMMENT ON COLUMN tnt_tenant_level_configs.max_members IS '该等级最大成员数';
COMMENT ON COLUMN tnt_tenant_level_configs.max_concurrency IS '该等级最大并发数,0=无限';
COMMENT ON COLUMN tnt_tenant_level_configs.price_multiplier IS '价格乘数(折扣,如 0.9=九折)';
COMMENT ON COLUMN tnt_tenant_level_configs.sort_order IS '排序权重';
-- 2. 插入默认等级数据
INSERT INTO tnt_tenant_level_configs (level, name, cumulative_recharge_threshold, max_members, max_concurrency, price_multiplier, sort_order) VALUES
(1, 'LV1', 0, 5, 10, 1.0000, 1),
(2, 'LV2', 1000, 10, 20, 0.9500, 2),
(3, 'LV3', 10000, 20, 50, 0.9000, 3),
(4, 'LV4', 100000, 50, 100, 0.8500, 4),
(5, 'LV5', 500000, 0, 0, 0.8000, 5);
-- 3. bil_wallets 添加累计充值字段
ALTER TABLE bil_wallets ADD COLUMN cumulative_recharge NUMERIC(20,10) DEFAULT 0 NOT NULL;
COMMENT ON COLUMN bil_wallets.cumulative_recharge IS '累计充值总额(USD)';
-- 4. tnt_tenants 添加等级字段
ALTER TABLE tnt_tenants ADD COLUMN level INT DEFAULT 1 NOT NULL;
COMMENT ON COLUMN tnt_tenants.level IS '当前等级(对应 tnt_tenant_level_configs.level)';
-- ============================================================
-- 二、模型分组功能:通过分组批量管理租户可用的模型
-- ============================================================
-- 模型分组定义
CREATE TABLE mdl_model_groups (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
code VARCHAR(50) NOT NULL,
description TEXT,
status VARCHAR(20) DEFAULT 'active' NOT NULL,
created_at TIMESTAMPTZ DEFAULT now() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL,
CONSTRAINT uk_mdl_model_groups_code UNIQUE (code)
);
COMMENT ON TABLE mdl_model_groups IS '模型分组定义';
COMMENT ON COLUMN mdl_model_groups.id IS '主键ID';
COMMENT ON COLUMN mdl_model_groups.name IS '分组名称(如"全量模型"、"基础对话")';
COMMENT ON COLUMN mdl_model_groups.code IS '分组唯一标识(如 full_access、basic_chat)';
COMMENT ON COLUMN mdl_model_groups.description IS '分组描述';
COMMENT ON COLUMN mdl_model_groups.status IS '状态:active(启用)/ disabled(禁用)';
COMMENT ON COLUMN mdl_model_groups.created_at IS '创建时间';
COMMENT ON COLUMN mdl_model_groups.updated_at IS '更新时间';
-- 分组-模型关联(多对多)
CREATE TABLE mdl_group_models (
id BIGSERIAL PRIMARY KEY,
group_id BIGINT NOT NULL,
model_id BIGINT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL,
CONSTRAINT uk_mdl_group_models UNIQUE (group_id, model_id)
);
CREATE INDEX idx_mdl_group_models_model_id ON mdl_group_models (model_id);
COMMENT ON TABLE mdl_group_models IS '分组-模型关联';
COMMENT ON COLUMN mdl_group_models.id IS '主键ID';
COMMENT ON COLUMN mdl_group_models.group_id IS '分组ID(关联 mdl_model_groups.id)';
COMMENT ON COLUMN mdl_group_models.model_id IS '模型ID(关联 mdl_models.id)';
COMMENT ON COLUMN mdl_group_models.created_at IS '创建时间';
COMMENT ON COLUMN mdl_group_models.updated_at IS '更新时间';
-- 租户-分组关联(多对多)
CREATE TABLE mdl_tenant_groups (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
group_id BIGINT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL,
CONSTRAINT uk_mdl_tenant_groups UNIQUE (tenant_id, group_id)
);
CREATE INDEX idx_mdl_tenant_groups_tenant_id ON mdl_tenant_groups (tenant_id);
COMMENT ON TABLE mdl_tenant_groups IS '租户-分组关联';
COMMENT ON COLUMN mdl_tenant_groups.id IS '主键ID';
COMMENT ON COLUMN mdl_tenant_groups.tenant_id IS '租户ID(关联 tnt_tenants.id)';
COMMENT ON COLUMN mdl_tenant_groups.group_id IS '分组ID(关联 mdl_model_groups.id)';
COMMENT ON COLUMN mdl_tenant_groups.created_at IS '创建时间';
COMMENT ON COLUMN mdl_tenant_groups.updated_at IS '更新时间';
-- ============================================================
-- 三、补充缺失的外键列索引
-- ============================================================
CREATE INDEX idx_api_keys_user ON api_keys (user_id);
CREATE INDEX idx_bil_records_channel ON bil_records (channel_id) WHERE channel_id IS NOT NULL;
CREATE INDEX idx_fil_files_user ON fil_files (user_id);
CREATE INDEX idx_ord_promo_code_usages_user ON ord_promo_code_usages (user_id);
CREATE INDEX idx_ord_promo_code_usages_order ON ord_promo_code_usages (order_id);
CREATE INDEX idx_pln_tenant_plans_plan ON pln_tenant_plans (plan_id);
CREATE INDEX idx_spt_feedbacks_user ON spt_feedbacks (tenant_id, user_id);
CREATE INDEX idx_spt_replies_user ON spt_replies (user_id);
-- ============================================================
-- 四、租户 max_members 和 max_concurrency 改为可 NULL
-- NULL 表示跟随等级配置(tnt_tenant_level_configs),非 NULL 表示自定义覆盖
-- ============================================================
ALTER TABLE tnt_tenants ALTER COLUMN max_members DROP NOT NULL;
ALTER TABLE tnt_tenants ALTER COLUMN max_members SET DEFAULT NULL;
ALTER TABLE tnt_tenants ALTER COLUMN max_concurrency DROP NOT NULL;
ALTER TABLE tnt_tenants ALTER COLUMN max_concurrency SET DEFAULT NULL;
COMMENT ON COLUMN tnt_tenants.max_members IS '最大成员数上限(NULL表示跟随等级配置)';
COMMENT ON COLUMN tnt_tenants.max_concurrency IS '租户总并发上限(NULL表示跟随等级配置,0表示不限制)';
-- ============================================================
-- 五、sys_sessions 添加 jti 列(JWT ID,用于会话吊销)
-- ============================================================
ALTER TABLE sys_sessions ADD COLUMN jti VARCHAR(36) NOT NULL DEFAULT '';
UPDATE sys_sessions SET jti = 'legacy-' || id WHERE jti = '';
ALTER TABLE sys_sessions ADD CONSTRAINT uk_sys_sessions_jti UNIQUE (jti);
COMMENT ON COLUMN sys_sessions.jti IS 'JWT ID (jti),会话唯一标识符(UUID),用于 Redis 吊销缓存';
-- +goose Down
-- 五、撤销 jti
ALTER TABLE sys_sessions DROP CONSTRAINT IF EXISTS uk_sys_sessions_jti;
ALTER TABLE sys_sessions DROP COLUMN IF EXISTS jti;
-- 四、恢复 max_members / max_concurrency 为 NOT NULL
UPDATE tnt_tenants t
SET max_members = COALESCE(
(SELECT lc.max_members FROM tnt_tenant_level_configs lc WHERE lc.level = t.level),
10
)
WHERE t.max_members IS NULL;
UPDATE tnt_tenants t
SET max_concurrency = COALESCE(
(SELECT lc.max_concurrency FROM tnt_tenant_level_configs lc WHERE lc.level = t.level),
0
)
WHERE t.max_concurrency IS NULL;
ALTER TABLE tnt_tenants ALTER COLUMN max_members SET DEFAULT 10;
ALTER TABLE tnt_tenants ALTER COLUMN max_members SET NOT NULL;
ALTER TABLE tnt_tenants ALTER COLUMN max_concurrency SET DEFAULT 0;
ALTER TABLE tnt_tenants ALTER COLUMN max_concurrency SET NOT NULL;
COMMENT ON COLUMN tnt_tenants.max_members IS '最大成员数上限';
COMMENT ON COLUMN tnt_tenants.max_concurrency IS '租户总并发上限(0表示不限制)';
-- 三、删除索引
DROP INDEX IF EXISTS idx_spt_replies_user;
DROP INDEX IF EXISTS idx_spt_feedbacks_user;
DROP INDEX IF EXISTS idx_pln_tenant_plans_plan;
DROP INDEX IF EXISTS idx_ord_promo_code_usages_order;
DROP INDEX IF EXISTS idx_ord_promo_code_usages_user;
DROP INDEX IF EXISTS idx_fil_files_user;
DROP INDEX IF EXISTS idx_bil_records_channel;
DROP INDEX IF EXISTS idx_api_keys_user;
-- 二、删除模型分组
DROP TABLE IF EXISTS mdl_tenant_groups;
DROP TABLE IF EXISTS mdl_group_models;
DROP TABLE IF EXISTS mdl_model_groups;
-- 一、删除租户等级
ALTER TABLE tnt_tenants DROP COLUMN IF EXISTS level;
ALTER TABLE bil_wallets DROP COLUMN IF EXISTS cumulative_recharge;
DROP TABLE IF EXISTS tnt_tenant_level_configs;