新增 000228 迁移:规则表 tb_package_traffic_alert_rule(每套餐商品至多一条,无软删除,package_id 非部分唯一约束)、达量预警快照表 tb_package_traffic_alert(以主套餐使用记录 + 阈值快照为唯一键, 触发时冻结用量、额度、比例、阈值、到期时间、归属与资产快照),并为 tb_package_usage 新增扫描 范围部分索引 idx_package_usage_alert_scope;down 在预警表存在数据时阻断回滚。 新增规则维护接口 GET/POST/PUT /api/admin/package-traffic-alert-rules(仅超级管理员与平台账号): 创建校验套餐存在且真流量额度大于零,阈值为 1%~100% 的两位小数;修改只影响后续扫描,不回填也 不改写既有预警快照;全部写操作记录操作者、前后值与时间。 新增每日 06:00(Asia/Shanghai)扫描任务 package:traffic:alert:scan,与套餐临期扫描共用 data_cleanup 队列:按资产汇总当前有效套餐的真流量,分子取使用记录真已用量、分母取使用记录真总量快照,命中 主套餐规则阈值时在同一事务创建预警与可靠通知事件;重复执行以唯一冲突视为已处理,不重复投递, 不建停机锁、不调用运营商。 新增预警列表、详情与异步导出 GET /api/admin/package-traffic-alerts、GET /api/admin/package-traffic-alerts/:id、 POST /api/admin/package-traffic-alerts/export,列表与详情一律读冻结快照;新增通知类型 package.traffic.alert 与受控目标 package_traffic_alert_detail,目标解析仅对超级管理员与平台账号 返回可跳转,越权与不存在统一按资源不可见处理。 同步 OpenAPI(cmd/gendocs、cmd/api/docs.go、pkg/openapi/handlers.go)、审计动作与资源注册、上下文 健康检查证据;归档变更并同步 package-traffic-alert 主 Spec。
7.8 KiB
7.8 KiB
Context
套餐商品 tb_package.real_data_mb 是可变配置值(后台可编辑)。套餐使用记录 tb_package_usage 以 data_usage_mb(真已用)与 data_limit_mb(真总量快照,购买时写入、全仓无更新路径)承载真实用量;既有 H5、后台资产详情、套餐历史、客户视图、代理开放接口与卡导出一律以使用记录快照展示真额度。现有通知以事件投递并按接收人隔离,后台通知无类型白名单,但新增通知类型必须先注册模板定义,否则渲染失败、通知写不进库。资产数据范围对超级管理员与平台用户为空操作。预警必须是套餐级观测,不能复用运营商通道阈值停机锁。
Goals / Non-Goals
Goals:
- 建立套餐真流量规则、预警事实、通知与可追溯导出。
Non-Goals:
- 不建停机锁、不调用运营商、不做停复机、不读取通道计费周期与通道累计流量。
Decisions
额度与用量口径
- 分子取
tb_package_usage.data_usage_mb(真已用),由卡网关读数增量经既有扣减链路写入。 - 分母取
tb_package_usage.data_limit_mb(真总量快照)。该字段与 H5、后台资产详情、套餐历史、客户视图、代理开放接口与卡导出的既有展示一致;使用记录快照不可变,历史可复现。 - 商品
real_data_mb仅作为规则启用时的配置合法性校验(必须大于零),不作为汇总分母。 - 禁止读取虚流量(
virtual_total_mb_snapshot/enable_virtual_data_snapshot)、展示量(display_gain_ratio_snapshot放大结果)、卡级累计(tb_iot_card.data_usage_mb)与运营商通道累计值(last_gateway_reading_mb、current_month_usage_mb)。
有效套餐集合与主套餐
- 按资产(
iot_card_id或device_id,二者互斥非零)汇总当前有效套餐使用记录,含加油包:status IN (1,2) AND refund_id IS NULL。 - 排除 0-待生效、3-已过期、4-已失效。
- 判定只依据
status,不得仅用expires_at判断过期(过期与失效由异步任务改状态,expires_at在生效中状态下可能已到期)。 - 主套餐(阈值来源)为
master_usage_id IS NULL;多条时按priority ASC, activated_at ASC, id ASC取第一条,与既有当前主套餐查询一致。 - 主套餐无有效规则、总额度不大于零或比例未达阈值时跳过。
汇总、去重与补建
- 唯一键为
(package_usage_id, threshold_percent_snapshot)。 - 降阈值后同一使用记录产生新阈值快照的预警属预期补建,不是重复;升阈值或停用不修改既有预警快照。
- 唯一冲突视为已处理,不重复投递通知。
- 实际消耗流量的使用记录所关联资产是权威归属;插拔卡同时展示卡与当前关联设备,不汇总多张卡。
规则维护
POST /package-traffic-alert-rules:仅超级管理员、平台用户;请求package_id、threshold_percent(大于等于 1、小于等于 100,允许小数)、enabled、remark(最多 500 字符)。套餐必须存在且real_data_mb > 0(配置合法性校验);同套餐已有规则返回“套餐已存在真流量预警规则”。PUT /package-traffic-alert-rules/:id:允许修改阈值、启停、备注;不修改已产生预警快照。停用后扫描不建新预警;启用或降低阈值后不主动回填,仅由下一次扫描按当前有效套餐判断。GET /package-traffic-alert-rules返回套餐、真流量总额度、阈值、启用状态、备注和更新时间。所有成功写操作记录操作者、前后值和时间。
扫描与幂等
- Worker 只读取当前有效套餐使用记录(见上集合),按资产聚合真已用量与真总量快照。
- 调度形态照抄既有
package_expiry_reminder:asynq.Scheduler以CRON_TZ=Asia/Shanghai注册,调度器仅在单例 Worker 角色创建。既有临期扫描不使用asynq.Unique,也无启动补偿;本项同样不新增手工触发扫描入口。 - 幂等由事实唯一键(
(package_usage_id, threshold_percent_snapshot))与 Outbox 幂等追加(OnConflict(event_id) DoNothing)保证。 - 事实与事件在同一事务写入:预警、通知事件与审计同事务提交;唯一冲突视为已处理,不重复投递通知。
- 通知失败进入既有可靠投递恢复,不能删除预警或重新计算快照。
通知
- 类别沿用
expiry,不新增类别;新增通知类型package.traffic.alert。 - 必须注册注册表
Definition,否则渲染失败、通知写不进库。 - 接收人新建「仅业务员」解析路径:
business_owner_account_id指向启用且user_type为平台的账号;不得复用返回「店铺 agent 账号 ∪ 业务员」的既有 resolver。 - 无有效业务员时只保存预警,不补发给未来业务员。
- 新增受控
ref_type并在通知目标定义中注册,指向预警详情,不返回 URL。 - 幂等键内嵌使用记录与阈值快照。
列表、详情与导出
GET /package-traffic-alerts:仅超级管理员、平台用户,先应用既有资产数据范围;支持套餐、店铺、业务员、资产/卡标识、阈值、触发时间和通知投递状态筛选、分页。返回冻结快照与通知结果,当前归属变化不得改写预警事实。GET /package-traffic-alerts/:id:同一数据范围校验后返回完整预警快照和通知投递历史;越权与不存在统一按既有资源不可见处理。POST /package-traffic-alerts/export:仅超级管理员、平台用户。复用既有异步导出任务机制(新增导出场景并复用导出任务创建服务),场景需在全部五处注册点落地(场景常量、DataSource、注册中心实例化、场景白名单、导出 DTOoneof两处);创建时冻结操作者、筛选、时间范围与可见资产范围。既有通用导出入口不做场景级角色校验,故本项以受控入口暴露该场景。- 数据范围使用导出侧的范围过滤(空范围拒绝),不得使用请求上下文版过滤(空范围语义相反)。
- 导出列:资产类型、资产标识、对应标识符、卡标识、设备类型、设备型号、套餐名称、真流量已用量、真流量额度、比例、阈值快照、到期时间、剩余天数、触发时间、店铺、业务员、用户组、通知投递结果;不含运营商通道列。
- 归属口径按 PRD §2.16 写死:导出中套餐、用量、总量、阈值与到期时间使用触发快照;店铺、业务员、用户组按导出执行时当前归属补充。预警行仍冻结店铺与业务员快照,供列表、详情与追溯;两者口径不同且不得混用。用户组不得写入店铺表,按既有实时推导。
数据范围与权限
- 列表、详情与导出仅超级管理员与平台用户。
- 先应用既有资产数据范围;当前对超管或平台无实际过滤,该要求保留为冻结语义与未来放开的前置。
- 越权与不存在统一按资源不可见处理。
- 导出范围在创建时冻结,执行期间归属变化不得扩大范围。
与通道阈值严格分离
- 不建停机锁、不调用运营商、不做停复机、不读取通道计费周期与通道累计流量,不触碰既有停复机服务与网关停机调用。
Risks / Trade-offs
- 流量数据延迟 → 下次扫描补建,不回写已冻结预警。
- 多卡设备 → 以使用记录资产归属聚合,不从当前设备反推流量。
- 扫描并发 → 唯一索引处理同一命中重复创建。
- 分母取快照 → 商品改价后重跑,比例与预警不因商品当前值变化;代价是商品价与预警分母可能不同,属预期。
Migration Plan
新增成对迁移和索引;隔离环境验证规则启停/降阈值、有效套餐汇总、去重、无业务员、权限导出和 up/down/up。