feat(套餐真流量预警): AUG26-004 真流量预警规则、达量扫描通知与导出

新增 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。
This commit is contained in:
2026-09-16 17:05:55 +08:00
parent ef4d3696d4
commit d5bcda94fe
46 changed files with 3679 additions and 100 deletions

View File

@@ -546,6 +546,16 @@ const (
AuditActionPhoneAssetUnbindImportTaskCreated = "phone_asset_unbind_import_task.create"
// AuditActionPhoneAssetUnbindImportTaskCompleted 表示 CSV 解绑导入任务完成。
AuditActionPhoneAssetUnbindImportTaskCompleted = "phone_asset_unbind_import_task.complete"
// AuditActionPackageTrafficAlertRuleCreated 表示创建套餐真流量预警规则。
AuditActionPackageTrafficAlertRuleCreated = "package_traffic_alert_rule.create"
// AuditActionPackageTrafficAlertRuleUpdated 表示修改套餐真流量预警规则阈值或备注。
AuditActionPackageTrafficAlertRuleUpdated = "package_traffic_alert_rule.update"
// AuditActionPackageTrafficAlertRuleEnabled 表示启用套餐真流量预警规则。
AuditActionPackageTrafficAlertRuleEnabled = "package_traffic_alert_rule.enable"
// AuditActionPackageTrafficAlertRuleDisabled 表示停用套餐真流量预警规则。
AuditActionPackageTrafficAlertRuleDisabled = "package_traffic_alert_rule.disable"
// AuditActionPackageTrafficAlertTriggered 表示扫描命中阈值时创建套餐真流量达量预警事实。
AuditActionPackageTrafficAlertTriggered = "package_traffic_alert.trigger"
// AuditActionNotificationDelivered 表示 Outbox 消费后实际生成站内通知。
AuditActionNotificationDelivered = "notification.deliver"
// AuditActionNotificationRead 表示单条通知首次标记已读。
@@ -703,6 +713,10 @@ const (
AuditResourcePhoneAssetAssociation = "phone_asset_association"
// AuditResourcePhoneAssetUnbindImportTask 表示手机号—资产 CSV 解绑导入任务资源。
AuditResourcePhoneAssetUnbindImportTask = "phone_asset_unbind_import_task"
// AuditResourcePackageTrafficAlertRule 表示套餐真流量预警规则资源。
AuditResourcePackageTrafficAlertRule = "package_traffic_alert_rule"
// AuditResourcePackageTrafficAlert 表示套餐真流量达量预警事实资源。
AuditResourcePackageTrafficAlert = "package_traffic_alert"
// AuditResourceNotification 表示站内通知资源。
AuditResourceNotification = "notification"
// AuditResourceNotificationReadBatch 表示通知批量已读资源。
@@ -845,6 +859,10 @@ const (
AuditResourceRoleBusinessUserGroupTarget = "business_user_group_target"
// AuditResourceRoleShopBusinessOwnerBatch 表示店铺负责人批量交接的批次根资源。
AuditResourceRoleShopBusinessOwnerBatch = "shop_business_owner_batch"
// AuditResourceRolePackageTrafficAlertRuleTarget 表示套餐真流量预警规则资源。
AuditResourceRolePackageTrafficAlertRuleTarget = "package_traffic_alert_rule_target"
// AuditResourceRolePackageTrafficAlertTarget 表示套餐真流量达量预警事实资源。
AuditResourceRolePackageTrafficAlertTarget = "package_traffic_alert_target"
// AuditResourceRoleRetentionMonth 表示留存清理目标自然月。
AuditResourceRoleRetentionMonth = "retention_month"
// AuditResourceRoleNotificationTarget 表示本次写操作的通知资源。

View File

@@ -96,6 +96,7 @@ const (
TaskTypeAgentRechargeRecovery = "agent_recharge:payment:recovery" // 代理在线充值支付恢复与查单
TaskTypeRefundChannelRecovery = "refund:channel:recovery" // 渠道原路退款结果恢复与查询
TaskTypeRefundCommissionRecovery = "refund:commission:recovery" // 退款佣金回溯后处理补偿
TaskTypePackageTrafficAlertScan = "package:traffic:alert:scan" // 每日套餐真流量达量预警扫描
// 运营商通道流量阈值任务类型(由 Asynq Scheduler 调度)
TaskTypeCarrierThresholdCycle = "carrier_threshold:cycle" // 通道阈值周期处理:跨期解锁与条件复机
@@ -311,6 +312,9 @@ func QueueForTaskType(taskType string) string {
return QueueDataCleanup
case TaskTypePackageExpiryReminder:
return QueueDataCleanup
case TaskTypePackageTrafficAlertScan:
// 与套餐临期扫描同队列:轻量只读扫描,复用既有已监听队列,不新增队列与权重。
return QueueDataCleanup
case TaskTypeDailyTrafficFlush:
return QueueDailyTrafficFlush
case TaskTypeAuditDailyArchive, TaskTypeIntegrationDailyArchive, TaskTypeAuditDailyRetention:
@@ -386,6 +390,8 @@ const (
ExportTaskSceneExchange = "exchange"
// ExportTaskSceneCommissionRecord 表示佣金明细导出场景,原佣金与回溯明细各占一行。
ExportTaskSceneCommissionRecord = "commission_record"
// ExportTaskScenePackageTrafficAlert 表示套餐真流量达量预警导出场景,一行对应一条预警记录。
ExportTaskScenePackageTrafficAlert = "package_traffic_alert"
)
// 导出文件格式常量

View File

@@ -46,6 +46,8 @@ const (
NotificationTypeH5PopupRiskExchange = "h5.popup.risk_exchange"
// NotificationTypeH5PopupOperation 表示 H5 运营弹窗投放。
NotificationTypeH5PopupOperation = "h5.popup.operation"
// NotificationTypePackageTrafficAlert 表示套餐真流量达量预警。
NotificationTypePackageTrafficAlert = "package.traffic.alert"
// NotificationRefTypeSystemConfig 表示系统配置资源引用。
NotificationRefTypeSystemConfig = "system_config"
@@ -71,6 +73,8 @@ const (
NotificationRefTypeShopFund = "shop_fund"
// NotificationRefTypeCardSync 表示卡同步外部集成资源引用。
NotificationRefTypeCardSync = "card_sync"
// NotificationRefTypePackageTrafficAlert 表示套餐真流量达量预警详情资源引用。
NotificationRefTypePackageTrafficAlert = "package_traffic_alert"
// NotificationTargetTypeRefundDetail 表示退款详情前端目标。
NotificationTargetTypeRefundDetail = "refund_detail"
@@ -90,6 +94,8 @@ const (
NotificationTargetTypeIntegrationLog = "integration_log"
// NotificationTargetTypeSystemConfig 表示受控系统配置前端目标。
NotificationTargetTypeSystemConfig = "system_config"
// NotificationTargetTypePackageTrafficAlertDetail 表示套餐真流量达量预警详情前端目标。
NotificationTargetTypePackageTrafficAlertDetail = "package_traffic_alert_detail"
// OutboxEventTypeAdminDirectNotification 表示向明确后台账号投递通知的稳定事件类型。
OutboxEventTypeAdminDirectNotification = "notification.admin.direct.requested"

View File

@@ -0,0 +1,86 @@
package constants
// 套餐真流量达量预警的通知投递结果常量。
//
// 该结果不落库为独立列,而是由「预警行的可靠通知事件 + tb_outbox_event 状态 + tb_notification 事实」
// 交叉推导因此枚举值一旦发布不得调整含义。1~4 表示已写入通知事件后的四种结果,
// 5 表示触发时店铺没有有效业务员,预警只保存事实不产生通知,也不在未来补发。
const (
// PackageTrafficAlertNotifyNotified 表示通知事件已生成站内通知,接收人可读。
PackageTrafficAlertNotifyNotified = 1
// PackageTrafficAlertNotifyPending 表示通知事件已写入但尚未完成投递。
PackageTrafficAlertNotifyPending = 2
// PackageTrafficAlertNotifyFailed 表示通知事件投递达到最终失败或等待人工重放。
PackageTrafficAlertNotifyFailed = 3
// PackageTrafficAlertNotifyRecipientGone 表示事件已投递但接收人已失效,未生成站内通知。
PackageTrafficAlertNotifyRecipientGone = 4
// PackageTrafficAlertNotifyNoBusinessOwner 表示触发时店铺无有效业务员,只保存预警。
PackageTrafficAlertNotifyNoBusinessOwner = 5
)
// GetPackageTrafficAlertNotifyStatusName 返回通知投递结果的中文名称。
func GetPackageTrafficAlertNotifyStatusName(status int) string {
switch status {
case PackageTrafficAlertNotifyNotified:
return "已通知"
case PackageTrafficAlertNotifyPending:
return "待投递"
case PackageTrafficAlertNotifyFailed:
return "投递失败"
case PackageTrafficAlertNotifyRecipientGone:
return "未通知(接收人已失效)"
case PackageTrafficAlertNotifyNoBusinessOwner:
return "未通知(无有效业务员)"
default:
return "未知"
}
}
// IsValidPackageTrafficAlertNotifyStatus 判断通知投递结果枚举是否受支持。
func IsValidPackageTrafficAlertNotifyStatus(status int) bool {
switch status {
case PackageTrafficAlertNotifyNotified,
PackageTrafficAlertNotifyPending,
PackageTrafficAlertNotifyFailed,
PackageTrafficAlertNotifyRecipientGone,
PackageTrafficAlertNotifyNoBusinessOwner:
return true
default:
return false
}
}
// ResolvePackageTrafficAlertNotifyStatus 由通知事件、Outbox 状态与站内通知事实推导投递结果。
// 判断顺序必须与读侧列表、详情与导出保持完全一致,因此该口径只在此处实现一次。
// - hasEvent=false触发时无有效业务员只保存预警
// - hasNotification=true通知已生成接收人可读
// - Outbox 为最终失败/已投递但无通知/其余未终结状态,分别对应失败、接收人已失效与待投递。
func ResolvePackageTrafficAlertNotifyStatus(hasEvent bool, outboxStatus *int, hasNotification bool) int {
if !hasEvent {
return PackageTrafficAlertNotifyNoBusinessOwner
}
if hasNotification {
return PackageTrafficAlertNotifyNotified
}
if outboxStatus == nil {
return PackageTrafficAlertNotifyPending
}
switch *outboxStatus {
case OutboxStatusFailed:
return PackageTrafficAlertNotifyFailed
case OutboxStatusDelivered:
// 事件已投递却没有生成通知:接收人在投递期已失效;本能力不允许改投他人。
return PackageTrafficAlertNotifyRecipientGone
default:
return PackageTrafficAlertNotifyPending
}
}
// PackageTrafficAlertRuleMaxRemarkLength 是预警规则备注的最大长度。
const PackageTrafficAlertRuleMaxRemarkLength = 500
// PackageTrafficAlertScanAggregateType 与 Outbox 事件的聚合类型,标识事件由达量扫描产生。
const PackageTrafficAlertScanAggregateType = "package_traffic_alert"
// PackageTrafficAlertEventIDPrefix 是可靠通知事件ID前缀pta:<package_usage_id>:<阈值万分比>。
const PackageTrafficAlertEventIDPrefix = "pta"