All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m54s
- 重构 Worker 启动流程,引入 bootstrap 模块统一管理依赖注入 - 实现套餐流量重置服务(日/月/年周期重置) - 新增套餐激活排队、加油包绑定、囤货待实名激活逻辑 - 新增订单创建幂等性防重(Redis 业务键 + 分布式锁) - 更新 AGENTS.md/CLAUDE.md:新增注释规范、幂等性规范,移除测试要求 - 添加套餐系统升级完整文档(API文档、使用指南、功能总结、运维指南) - 归档 OpenSpec package-system-upgrade 变更,同步 specs 到主目录 - 新增 queue types 抽象和 Redis 常量定义
112 lines
6.3 KiB
SQL
112 lines
6.3 KiB
SQL
-- Package 表扩展:新增周期类型、流量重置周期、实名激活开关
|
||
ALTER TABLE tb_package
|
||
ADD COLUMN IF NOT EXISTS calendar_type VARCHAR(20) DEFAULT 'by_day',
|
||
ADD COLUMN IF NOT EXISTS duration_days INT,
|
||
ADD COLUMN IF NOT EXISTS data_reset_cycle VARCHAR(20) DEFAULT 'monthly',
|
||
ADD COLUMN IF NOT EXISTS enable_realname_activation BOOLEAN DEFAULT TRUE;
|
||
|
||
-- PackageUsage 表扩展:新增优先级、主套餐关联、独立有效期、实名激活等字段
|
||
-- 注:status 字段枚举值扩展为 0-4(0=待生效,1=生效中,2=已用完,3=已过期,4=已失效)
|
||
ALTER TABLE tb_package_usage
|
||
ADD COLUMN IF NOT EXISTS priority INT DEFAULT 1,
|
||
ADD COLUMN IF NOT EXISTS master_usage_id BIGINT,
|
||
ADD COLUMN IF NOT EXISTS has_independent_expiry BOOLEAN DEFAULT FALSE,
|
||
ADD COLUMN IF NOT EXISTS pending_realname_activation BOOLEAN DEFAULT FALSE,
|
||
ADD COLUMN IF NOT EXISTS data_reset_cycle VARCHAR(20),
|
||
ADD COLUMN IF NOT EXISTS last_reset_at TIMESTAMP,
|
||
ADD COLUMN IF NOT EXISTS next_reset_at TIMESTAMP;
|
||
|
||
-- IotCard 表扩展:新增首次实名时间、停复机相关字段
|
||
ALTER TABLE tb_iot_card
|
||
ADD COLUMN IF NOT EXISTS first_realname_at TIMESTAMP,
|
||
ADD COLUMN IF NOT EXISTS stopped_at TIMESTAMP,
|
||
ADD COLUMN IF NOT EXISTS resumed_at TIMESTAMP,
|
||
ADD COLUMN IF NOT EXISTS stop_reason VARCHAR(50);
|
||
|
||
-- Carrier 表扩展:新增计费日字段(联通27号,其他1号)
|
||
ALTER TABLE tb_carrier
|
||
ADD COLUMN IF NOT EXISTS billing_day INT DEFAULT 1;
|
||
|
||
-- 创建 PackageUsageDailyRecord 表:套餐流量日记录
|
||
CREATE TABLE IF NOT EXISTS tb_package_usage_daily_record (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
package_usage_id BIGINT NOT NULL,
|
||
date DATE NOT NULL,
|
||
daily_usage_mb INT DEFAULT 0,
|
||
cumulative_usage_mb BIGINT DEFAULT 0,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- 创建 CardDailyUsage 表:卡流量日记录(用于轮询系统)
|
||
CREATE TABLE IF NOT EXISTS tb_card_daily_usage (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
card_id BIGINT NOT NULL,
|
||
usage_date DATE NOT NULL,
|
||
total_data_usage BIGINT DEFAULT 0,
|
||
carrier_id BIGINT,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- 创建索引
|
||
-- PackageUsage 表索引
|
||
CREATE INDEX IF NOT EXISTS idx_package_usage_priority ON tb_package_usage(priority);
|
||
CREATE INDEX IF NOT EXISTS idx_package_usage_master_usage_id ON tb_package_usage(master_usage_id);
|
||
CREATE INDEX IF NOT EXISTS idx_package_usage_next_reset_at ON tb_package_usage(next_reset_at);
|
||
|
||
-- PackageUsageDailyRecord 表唯一索引(同一套餐同一天只有一条记录)
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_package_usage_daily_record_unique ON tb_package_usage_daily_record(package_usage_id, date);
|
||
CREATE INDEX IF NOT EXISTS idx_package_usage_daily_record_date ON tb_package_usage_daily_record(date);
|
||
|
||
-- CardDailyUsage 表唯一索引(同一卡同一天只有一条记录)
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_card_daily_usage_unique ON tb_card_daily_usage(card_id, usage_date);
|
||
CREATE INDEX IF NOT EXISTS idx_card_daily_usage_date ON tb_card_daily_usage(usage_date);
|
||
|
||
-- 数据初始化:设置运营商的 billing_day
|
||
-- 联通(假设 carrier_name 或 carrier_code 包含 "unicom" 或 "联通")
|
||
UPDATE tb_carrier
|
||
SET billing_day = 27
|
||
WHERE LOWER(carrier_name) LIKE '%unicom%' OR carrier_name LIKE '%联通%';
|
||
|
||
-- 其他运营商默认为 1 号(已通过 DEFAULT 设置)
|
||
|
||
-- 添加字段注释(PostgreSQL 语法)
|
||
-- Package 表字段注释
|
||
COMMENT ON COLUMN tb_package.calendar_type IS '套餐周期类型(natural_month=自然月,by_day=按天)';
|
||
COMMENT ON COLUMN tb_package.duration_days IS '套餐天数(calendar_type=by_day 时必填)';
|
||
COMMENT ON COLUMN tb_package.data_reset_cycle IS '流量重置周期(daily/monthly/yearly/none)';
|
||
COMMENT ON COLUMN tb_package.enable_realname_activation IS '是否启用实名激活(true=需实名后激活,false=立即激活)';
|
||
|
||
-- PackageUsage 表字段注释
|
||
COMMENT ON COLUMN tb_package_usage.priority IS '优先级(主套餐和加油包都按此字段排队,数字越小优先级越高)';
|
||
COMMENT ON COLUMN tb_package_usage.master_usage_id IS '主套餐使用记录ID(加油包关联主套餐,主套餐此字段为NULL)';
|
||
COMMENT ON COLUMN tb_package_usage.has_independent_expiry IS '加油包是否有独立有效期(true=有独立到期时间,false=跟随主套餐)';
|
||
COMMENT ON COLUMN tb_package_usage.pending_realname_activation IS '是否等待实名激活(true=待实名后激活,false=已激活或不需实名)';
|
||
COMMENT ON COLUMN tb_package_usage.data_reset_cycle IS '流量重置周期(从 Package 复制,用于历史记录)';
|
||
COMMENT ON COLUMN tb_package_usage.last_reset_at IS '最后一次流量重置时间';
|
||
COMMENT ON COLUMN tb_package_usage.next_reset_at IS '下次流量重置时间(用于定时任务查询)';
|
||
|
||
-- IotCard 表字段注释
|
||
COMMENT ON COLUMN tb_iot_card.first_realname_at IS '首次实名时间(用于触发首次实名激活)';
|
||
COMMENT ON COLUMN tb_iot_card.stopped_at IS '停机时间';
|
||
COMMENT ON COLUMN tb_iot_card.resumed_at IS '最近复机时间';
|
||
COMMENT ON COLUMN tb_iot_card.stop_reason IS '停机原因(traffic_exhausted=流量耗尽,manual=手动停机,arrears=欠费)';
|
||
|
||
-- Carrier 表字段注释
|
||
COMMENT ON COLUMN tb_carrier.billing_day IS '运营商计费日(用于流量查询接口的计费周期计算,联通=27,其他=1)';
|
||
|
||
-- PackageUsageDailyRecord 表和字段注释
|
||
COMMENT ON TABLE tb_package_usage_daily_record IS '套餐流量日记录';
|
||
COMMENT ON COLUMN tb_package_usage_daily_record.package_usage_id IS '套餐使用记录ID';
|
||
COMMENT ON COLUMN tb_package_usage_daily_record.date IS '日期';
|
||
COMMENT ON COLUMN tb_package_usage_daily_record.daily_usage_mb IS '当日流量使用量(MB)';
|
||
COMMENT ON COLUMN tb_package_usage_daily_record.cumulative_usage_mb IS '截止当日的累计流量(MB)';
|
||
|
||
-- CardDailyUsage 表和字段注释
|
||
COMMENT ON TABLE tb_card_daily_usage IS '卡流量日记录';
|
||
COMMENT ON COLUMN tb_card_daily_usage.card_id IS '卡ID(可能是 iot_card_id 或 device_id)';
|
||
COMMENT ON COLUMN tb_card_daily_usage.usage_date IS '日期';
|
||
COMMENT ON COLUMN tb_card_daily_usage.total_data_usage IS '上游返回的累计流量(MB)';
|
||
COMMENT ON COLUMN tb_card_daily_usage.carrier_id IS '运营商ID';
|