sub2api/backend/migrations/142_user_platform_quotas.sql
DaydreamCoding 6b39b344d8 feat(quota): 用户 × 平台 USD 配额
为用户在 anthropic/openai/gemini/antigravity 四个平台上提供日/周/月
三个窗口的 USD 配额管控。配额语义:未设置=不限制,0=禁用,>0=美元上限。

两层模型:
- 配置层:系统默认配额,以及 email/linuxdo/oidc/wechat/github/google/
  dingtalk 七个鉴权来源的默认配额,存于 settings,以嵌套 JSON 整体读写
  (系统 1 个 key + 每个来源 1 个 key),整体替换语义。
- 运行时层:user_platform_quota 表按用户记录实际配额,与配置层解耦。

后端:新增 ent schema 与 140_user_platform_quotas.sql 迁移、repository
与 service 端口、计费链路集成、管理端与用户端读写接口。
前端:管理端设置页配额编辑、用户配额管理 Modal、用户 Dashboard 展示、
中英文案。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 10:49:20 +08:00

37 lines
1.7 KiB
SQL
Raw 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.

-- 用户平台维度配额表。每个 (user_id, platform) 对独立记录日/周/月三层 USD 限额与用量。
-- nil limit = 不限制沿用上层默认0 = 显式禁用,>0 = USD 上限。
-- 软删除deleted_at IS NULL 的记录为活跃记录,部分唯一索引保证同用户同平台只有一条活跃配额。
CREATE TABLE IF NOT EXISTS user_platform_quotas (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
platform VARCHAR(32) NOT NULL CHECK (platform IN ('anthropic', 'openai', 'gemini', 'antigravity')),
-- 日 / 周 / 月 USD 上限NULL = 不限制0 = 显式禁用,>0 = 上限
daily_limit_usd DECIMAL(20,10),
weekly_limit_usd DECIMAL(20,10),
monthly_limit_usd DECIMAL(20,10),
-- 当前窗口已用量
daily_usage_usd DECIMAL(20,10) NOT NULL DEFAULT 0,
weekly_usage_usd DECIMAL(20,10) NOT NULL DEFAULT 0,
monthly_usage_usd DECIMAL(20,10) NOT NULL DEFAULT 0,
-- 窗口起点NULL = 首次尚未初始化)
daily_window_start TIMESTAMPTZ,
weekly_window_start TIMESTAMPTZ,
monthly_window_start TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
-- 软删除友好唯一索引:同用户同平台只允许一条未删除记录
CREATE UNIQUE INDEX IF NOT EXISTS userplatformquota_user_id_platform_uq
ON user_platform_quotas (user_id, platform)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS userplatformquota_user_id
ON user_platform_quotas (user_id);