feat: 卡流量改为日快照计量并统一停复机规则
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
卡流量计量(按名单灰度,默认 off): - 新增卡日快照与切换水位表(000241),按通道上游流量重置日换算自然月、重置日防旧值 - 已切换的卡按月对账产生增量,无生效中套餐只结算不发事件;第一次切换写水位 - 已切换卡读数有效即判定通道阈值,卡表本月用量用快照覆盖,日流量读快照 - 配置 JUNHONG_TRAFFIC_CALC_MODE/CARDS、JUNHONG_TRAFFIC_FLOW_SNAPSHOT_ENABLED 停复机规则(总开关 JUNHONG_STOP_RESUME_UNIFIED_RULE_ENABLED,默认关闭): - 复机不看停机原因,持通道阈值锁仍拒绝;暂停轮询的卡不自动停复机 - 通道新增实名管控 realname_control_enabled(000242,默认 0),开启后不区分行业卡与实名策略 - 实名管控从 0 改 1 需确认,修改并入通道更新审计 OpenSpec Change: rebuild-card-traffic-metering-and-stop-resume
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-10-20
|
||||
@@ -0,0 +1,80 @@
|
||||
## Context
|
||||
|
||||
完整推导、老卡管反编译依据与生产核实数据见 `docs/卡流量计算技术方案-参考老卡管.md`(第 2 版)。本文只记录实现层的关键决策。
|
||||
|
||||
现状:
|
||||
|
||||
- `internal/domain/cardobservation/traffic.go` 的 `ApplyTraffic` 用"读数 − `last_gateway_reading_mb`"算增量,读数下降只在重置日当天或前一天被当作清零,其余一律拒绝;`internal/application/cardobservation/traffic.go` 在同一事务里锁卡行、CAS 更新卡表、正增量写 V1 Outbox,读数被接受时才判定通道阈值(第 84 行)。
|
||||
- V1 消费者(`internal/infrastructure/cardobservation/event.go`)调 `DeductDataUsage`;没有生效中套餐时报"没有可用套餐"并由 Asynq 重试。
|
||||
- 停复机集中在 `internal/service/iot_card/stop_resume_service.go`:自动复机只认 `traffic_exhausted`、`no_package`、`not_realname`;实名门槛 `isRealnameOK` 放行行业卡、已实名卡和实际生效策略为 `none` 的卡。停复机判断只读套餐用量与状态,不读卡表用量字段。
|
||||
- 卡表 `current_month_usage_mb` 被资产详情、卡列表、设备导出直接读取。
|
||||
- 约束:套餐侧、V1 消费者、Gateway 与三个观测入口不改;自动化测试为 N/A,验证在维护者指定的测试环境进行;生产迁移由维护者手工执行。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 已切换的卡不再依赖卡表基线计量,冻结、读数为 0 重复计、二次销售多计、无套餐积压不再新增。
|
||||
- 切换可灰度、可退回,不重不漏;未切换的卡行为不变。
|
||||
- 停复机按"停机看套餐、流量、通道实名管控;复机看套餐、流量、实名,不看停因"的统一规则执行,由总开关控制上线时机。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 冻结卡历史少扣的补数据脚本(后期另立 Change,依赖本 Change 的切换水位)。
|
||||
- 积压"处理中"回执的处理(业务手动,处理前不得重放)。
|
||||
- 套餐扣减口径、加油包顺序、虚流量阈值、`DeductDataUsage` 及消费者的任何改动。
|
||||
- 卡级、设备级实名管控字段;按运营商扩展状态自动暂停轮询。
|
||||
- Gateway 按日期区间查询(电信读数为 0 的问题本期不解决)。
|
||||
|
||||
## Decisions
|
||||
|
||||
**D1 计量照搬老卡管日快照,而不是修补基线规则。** 基线是一个可被任意一次异常读数永久污染的单值状态;日快照取最大值做差,单次异常只影响当月,且可按快照复算。替代方案"放宽读数下降判定"仍依赖基线,无法根治二次销售与冻结。
|
||||
|
||||
**D2 增量按月对账(本月最大快照 − 本月已结算合计),不按天对账。** 按天对账遇到跨零点的迟到观测会重复扣;按月对账与观测先后无关,且已结算合计同时承载"发出的增量"、"无套餐丢弃的增量"和"切换时视为老算法已结算的部分"。
|
||||
|
||||
**D3 新逻辑放在 `ApplyTrafficObservation` 的已切换分支内,同一事务。** 卡行已在事务开头加锁,同卡观测天然串行,快照不另加行锁;快照、已结算、切换水位、Outbox 同事务提交。老 `ApplyTraffic` 照常计算并写卡表三列(`last_gateway_reading_mb` 仍是 CAS 条件,新代码只读),只是已切换卡不使用它的增量(第一次切换观测除外)。未切换卡在事务提交后用 `INSERT ... ON CONFLICT DO UPDATE SET month_used_mb = GREATEST(...)` 原子写快照,失败只告警。
|
||||
|
||||
**D4 切换水位表,而不是要求阶段 1 覆盖整月。** 平均每卡约 1.5 天才采一次,阶段 1 无法保证每张卡本月都有快照;水位让第一次切换观测沿用老增量并把此前部分记为已结算,同时为补数据提供截断点与冻结卡判定依据(切换后卡表本月计入仍由老逻辑维护,不能用来判定冻结卡)。退回时删除水位,再切回会重新执行。
|
||||
|
||||
**D5 无生效中套餐时在观测事务内只读判断并丢弃增量。** 与 `resolveActivePackages` 同口径(卡自身或当前绑定设备的 status=1 套餐),不改消费者;判断出错按有套餐处理,保持不丢量。
|
||||
|
||||
**D6 重置日在事务内按卡的 `carrier_id` 严格读取。** 入口传入的 `ResetDay` 在查询失败时已被兜底为 1,联通卡被当作 1 号重置会抬高自然月累计且按最大值规则收不回;失败时按卡表 `carrier_type` 兜底(`CUCC` 取 27,其余取 1)。
|
||||
|
||||
**D7 不新增"读数是否有效"标记。** Gateway 的 `FlexFloat` 已把空、null、无法解析转为 0,新逻辑对 0 与负数一律不写快照,结果相同,Gateway 与三个入口不改。
|
||||
|
||||
**D8 灰度单位为扣减载体,启动时展开为内存集合。** 设备整台切,避免同一设备套餐同时收到两种算法的增量;判定不查库,出错走老算法。切换、扩批、退回都要先停掉 API 与全部 Worker 再一起启动,避免新旧进程并存时老进程发的增量不计入已结算合计。
|
||||
|
||||
**D9 已切换卡的展示与通道阈值。** 卡表 `current_month_usage_mb` 用本月最大快照覆盖(写在同一条 `Updates` 里),三处读取方不改;通道阈值判定条件改为"读数大于 0 且本次未被防旧值处理",`EvaluateInTx` 只做达量写锁、无低读数复机,放开不会误复机。
|
||||
|
||||
**D10 停复机统一目标状态判断。** 新增一个判断函数供 `EvaluateAndAct` 开机分支、停机分支、`resumeSingleCard`、`resumeDeviceCards`、`ResumeCardIfStopped` 共用:先判断暂停轮询(卡或设备 `enable_polling = false`,与 `ShouldEnqueue` 同口径)→ 不动作;开机时命中无套餐、流量用完、通道实名管控且未实名即停;停机时满足有套餐、流量未用完、已实名或通道未管控即复机,删除 `isPollingStopReason` 限制,保留通道阈值持锁拒绝。设备复机改为取设备下全部停机卡。套餐判断沿用 `HasValidByCarrier` 与 `isTrafficExhausted` 现有口径。
|
||||
|
||||
**D11 实名管控为通道独立开关,`isRealnameOK` 是唯一实现点。** 总开关开启时:通道 `realname_control_enabled = 0` 返回满足,`= 1` 时以 `real_name_status` 判断,删除行业卡与资产实名策略分支;通道查询失败返回错误、本次不动作。停机、复机、设备复机、人工复机、保护期一致性检查(仅通道管控且未实名时跳过)都经过它。替代方案"复用卡/设备实名策略"会让购买流程与停复机继续耦合,且需要修数据。
|
||||
|
||||
**D12 通道阈值新周期恢复复用 D10 的复机条件(总开关开启时)。** 避免同一张卡在通道阈值路径与常规路径上复机条件不一致。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [停复机总开关打开时集中动作:外部停机、人工停机的卡被集中复机;开启实名管控通道的未实名卡(含行业卡)被集中停机] → 总开关默认关闭;打开前在管理端设定需要管控的通道并预演统计,业务确认后再开。
|
||||
- [人工停机不再长期有效,下一次评估满足条件即复机] → 需要长期停用的卡由人工暂停轮询;已在规格中明确。
|
||||
- [外部系统反复停卡,卡管反复复机] → 按原则不设上限;需要卡管停止管理时人工暂停轮询。
|
||||
- [第一次切换观测沿用老增量,若恰好撞上老算法缺陷(如重置窗口读到 0 后又读到真实值)会扣一次] → 每张卡最多一次,灰度第一批核对。
|
||||
- [事务 1 判断有生效中套餐、消费者扣减前前一条事件刚好扣完唯一套餐,事件仍会积压] → 概率低;灰度期监控"处理中"回执新增数,确有发生再评估消费者调整。
|
||||
- [重置日前最后一次采集到清零之间的用量丢失,采得越稀丢得越多;重置日当天未采到的卡不触发防旧值] → 与老卡管一致,轮询吞吐另行处理。
|
||||
- [月中修改通道重置日导致当月换算跳变] → 修改安排在运营商实际重置日前后并核对受影响卡。
|
||||
- [`ApplyTraffic` 为全部卡共用路径,改动出错会波及全部卡] → 新逻辑只在已切换分支,老分支不改;测试环境回归非灰度卡观测结果与改动前一致。
|
||||
- [卡换绑设备后第一次观测把整张卡周期读数算给设备套餐] → 与现状一致,列入已知限制。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 迁移:新增 `tb_card_flow_day`、`tb_card_flow_switch`,`tb_carrier` 增加 `realname_control_enabled smallint not null default 0`;成对 up/down,生产由维护者执行。
|
||||
2. 发版:计量模式 `off`、快照开关开、停复机总开关关;全部卡开始写快照,其余行为不变。
|
||||
3. 阶段 1 至少跑满一个完整自然日(最好跨过一次各运营商重置日)后进入灰度:名单 `device:15276`,先停后启全部进程。
|
||||
4. 扩批条件:灰度卡逐日增量 = 按快照复算;无误停误复;跨过一次各运营商清零;冻结卡恢复计量、二次销售不带入旧用量。之后扩批、全量;全量后下线 Redis 日流量缓冲与 02:00 落盘。
|
||||
5. 停复机:管理端设定需要实名管控的通道 → 预演 → 打开总开关并先停后启全部进程。
|
||||
6. 回滚:计量模式改回 `off` 或移出名单并删除对应卡的切换水位,先停后启;停复机总开关改回关闭。快照与水位表保留不影响老路径。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- "有套餐"的口径:本 Change 沿用现有口径(生效中或待生效都算有套餐);若业务要求只认生效中,需另行确认,会改变现有停机行为。
|
||||
- 套餐在扣减前刚好用完导致的积压,是否在灰度后调整消费者,待灰度监控结果再定。
|
||||
- 自动续费成功后的可靠复机(`asset-auto-renewal`「成功后的可靠复机」,实现为 `autoRenewalCardReady`)仍按"可轮询停因、非风险停机/销户"判断,本 Change 未改:总开关开启后,这条路径跳过的卡会在下一次套餐轮询评估时按新规则复机。是否让该路径也改用新复机条件,需另立 Change 修改 `asset-auto-renewal` 规格。
|
||||
@@ -0,0 +1,45 @@
|
||||
## Why
|
||||
|
||||
卡流量现在按"本次运营商读数 − 卡上基线(`last_gateway_reading_mb`)"计算增量。基线是跨套餐、跨用户的卡级状态,一旦被异常高读数抬高或重置日没采到就会一直错下去:卡被冻结(2026-10-12 统计约 23% 活跃卡 10 月基线未动,上限估计)、读数为 0 时整笔重复计、二次销售把上一个用户的用量算给新用户、无套餐期间的增量积压后扣到新套餐上。老卡管用"每卡每天一条本月累计快照、区间取最大值做差"多年稳定,本 Change 照搬它的计量方式。
|
||||
|
||||
停复机同时存在两个问题:外部停机后卡管不再复机(只认流量耗尽、无套餐、未实名三种停因),实名与停复机默认强绑定且耦合行业卡和资产实名策略,想放开只能修数据。依据为 `docs/卡流量计算技术方案-参考老卡管.md`(第 2 版)。
|
||||
|
||||
## What Changes
|
||||
|
||||
**卡流量计量(方案第 1~9 章)**
|
||||
|
||||
- 新增卡日快照:每卡每天一条"自然月累计",写入时按通道上游流量重置日换算成自然月;重置日当天读数超过上周期最大快照 0.9 倍按 0 记;快照只增不减;读数为 0 或无效不写。全部被采集的卡都写快照。
|
||||
- 已切换的卡:增量 = 本月最大快照 − 本月已结算合计(按月对账),照旧写 V1 流量事件交给现有扣减;卡没有生效中套餐时增量只记为已结算、不发事件。
|
||||
- 新增切换水位:卡第一次走新算法时,这一次沿用老算法增量,此前部分记为已结算,切换不重复扣、不依赖切换前是否已有快照。
|
||||
- 已切换的卡:读数有效且本次未被防旧值处理即判定通道阈值;卡表 `current_month_usage_mb` 用本月最大快照覆盖;日流量读快照。
|
||||
- 按扣减载体名单灰度(`off` / `gray` / `full`),设备整台切;切换、扩批、退回先停全部进程再一起启动,退回时删除水位。未切换的卡扣费、停复机、观测结果、展示与现在一致。
|
||||
- 不在本 Change:冻结卡历史少扣的补数据脚本(后期另立 Change)、积压"处理中"回执的处理(业务手动)。
|
||||
|
||||
**停复机规则与实名管控(方案第 10 章,总开关控制,默认关闭)**
|
||||
|
||||
- **BREAKING**(开关开启后)停机:卡开机且满足任一——没有套餐、流量用完、卡所属通道开启实名管控且卡未实名。
|
||||
- **BREAKING**(开关开启后)复机:卡停机且同时满足——有套餐、流量没用完、卡已实名或通道关闭实名管控;**不看停机原因**(外部停机、手动停机、设备手动停机都复机)。持有本周期通道阈值锁的卡不复机。
|
||||
- 新增通道配置 `realname_control_enabled`,默认 0(不管控),不复用通道现有实名字段;开启后不再区分行业卡,不看卡或设备实名策略。不迁移、不修改任何卡或设备数据。
|
||||
- 卡或所在设备暂停轮询时卡管不自动停复机;运营商异常状态(风险停机、机卡分离停机、已销户)由人工判断并暂停轮询,现有独立卡风险停机/已销户自动暂停轮询逻辑不变。
|
||||
- 通道阈值新周期解锁后的复机条件随新规则调整。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `card-traffic-metering`:卡日快照、自然月换算与重置日防旧值、按月对账增量、切换水位、按名单灰度、已切换卡的通道阈值判定、本月用量与日流量展示。
|
||||
- `card-stop-resume`:自动停复机条件、复机不看停机原因、通道实名管控配置、暂停轮询的卡不自动停复机、新规则总开关。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `polling-operations`:"停复机遵循实际生效实名策略"限定为停复机新规则总开关关闭时适用;开启后实名改由 `card-stop-resume` 的通道实名管控决定。
|
||||
- `carrier-channel-traffic-threshold`:新周期解锁后的自动复机条件在新规则开启时改为 `card-stop-resume` 的复机条件。
|
||||
|
||||
## Impact
|
||||
|
||||
- 数据库:新增 `tb_card_flow_day`、`tb_card_flow_switch`;`tb_carrier` 增加 `realname_control_enabled`。均为新的成对迁移,不改既有表结构以外的数据。
|
||||
- 代码:`internal/application/cardobservation/traffic.go`(已切换分支)、新增 `internal/domain/cardflow/`、快照与水位 Store;`internal/service/iot_card/stop_resume_service.go`、`iot_card_store.go`、`polling_protect_handler.go`;`internal/model/carrier.go`、`service/carrier` 与 DTO;`internal/application/carrierthreshold/` 周期恢复;日流量查询;`pkg/config`、`pkg/constants`。
|
||||
- 不改:套餐表与套餐服务、V1 消费者、激活/重置/改已用量/换货/退款入口、Gateway 与三个观测入口、外部停机仍记 `carrier_stopped` 的规则、购买与激活流程的实名策略。
|
||||
- 接口:通道创建、修改、详情增加 `realname_control_enabled`;重新生成接口文档。
|
||||
- 配置:`JUNHONG_TRAFFIC_CALC_MODE`、`JUNHONG_TRAFFIC_CALC_CARDS`、`JUNHONG_TRAFFIC_FLOW_SNAPSHOT_ENABLED`、`JUNHONG_STOP_RESUME_UNIFIED_RULE_ENABLED`;API 与全部 Worker 必须一致。
|
||||
- 运营:灰度第一批为设备 15276;打开停复机总开关前先在管理端设定需要实名管控的通道,并预演会集中复机、停机的卡。
|
||||
@@ -0,0 +1,80 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 停复机新规则总开关
|
||||
系统 SHALL 提供停复机新规则总开关 `JUNHONG_STOP_RESUME_UNIFIED_RULE_ENABLED`,默认关闭。关闭时自动停机、自动复机、设备复机、人工复机与保护期一致性检查 MUST 与本变更前完全一致,通道实名管控配置不参与判断。开启后按本能力其余要求执行。API 与全部 Worker 进程 MUST 使用一致的开关值。
|
||||
|
||||
#### Scenario: 总开关关闭
|
||||
- **WHEN** 总开关关闭,外部停机(停因 `carrier_stopped`)的卡有套餐且流量未用完
|
||||
- **THEN** 系统与变更前一致,不自动复机
|
||||
|
||||
#### Scenario: 总开关开启
|
||||
- **WHEN** 维护者开启总开关并重启全部进程
|
||||
- **THEN** 后续每次停复机评估按本能力的停机与复机条件执行
|
||||
|
||||
### Requirement: 自动停机条件
|
||||
总开关开启时,系统 SHALL 对开机的卡在满足任一条件时自动停机:卡(绑定设备时按设备)没有套餐;流量已用完;卡所属通道开启实名管控且卡未实名。停机原因按命中条件分别记为 `no_package`、`traffic_exhausted`、`not_realname`。无套餐与流量用完扩散到设备下全部开机卡,未实名只停该卡。系统 MUST NOT 因卡当前开机是由外部、人工或其他原因造成而改变判断。
|
||||
|
||||
#### Scenario: 套餐到期
|
||||
- **WHEN** 开机卡绑定的设备没有套餐
|
||||
- **THEN** 系统停机设备下全部开机卡,停因为 `no_package`
|
||||
|
||||
#### Scenario: 通道开启实名管控的未实名卡
|
||||
- **WHEN** 卡所属通道开启实名管控,卡未实名且开机
|
||||
- **THEN** 系统只停这张卡,停因为 `not_realname`
|
||||
|
||||
#### Scenario: 通道未开启实名管控的未实名卡
|
||||
- **WHEN** 卡所属通道未开启实名管控,卡未实名、有套餐、流量未用完且开机
|
||||
- **THEN** 系统不停机
|
||||
|
||||
### Requirement: 自动复机条件不看停机原因
|
||||
总开关开启时,系统 SHALL 对停机的卡在同时满足以下条件时自动复机:卡(绑定设备时按设备)有套餐;流量未用完;卡已实名或卡所属通道未开启实名管控。系统 MUST NOT 以停机原因决定是否复机:外部停机(`carrier_stopped`)、卡管人工停机(`manual`)、设备保护期停机(`protect_period`)、未实名、无套餐、流量耗尽的卡满足条件都复机。持有本周期通道阈值锁的卡 MUST 拒绝复机。设备复机时系统 SHALL 逐张判断设备下全部停机卡,不满足实名条件的卡跳过并记停因 `not_realname`,其他卡照常复机。外部反复停机时,系统每次评估均按上述条件复机,不设次数上限。停机原因只用于展示与审计。
|
||||
|
||||
#### Scenario: 外部停机后满足条件
|
||||
- **WHEN** 卡被外部停机后记为 `carrier_stopped`,有套餐、流量未用完、实名条件满足
|
||||
- **THEN** 下一次评估时系统自动复机并清空停因
|
||||
|
||||
#### Scenario: 人工停机后满足条件
|
||||
- **WHEN** 管理员手动停机的卡有套餐、流量未用完、实名条件满足
|
||||
- **THEN** 下一次评估时系统自动复机
|
||||
|
||||
#### Scenario: 开启实名管控的通道中未实名的停机卡
|
||||
- **WHEN** 卡所属通道开启实名管控,卡未实名、停机、有套餐
|
||||
- **THEN** 系统不复机;卡实名后下一次评估复机
|
||||
|
||||
#### Scenario: 持有通道阈值锁
|
||||
- **WHEN** 停机卡在本周期持有通道阈值锁,其他条件均满足
|
||||
- **THEN** 系统拒绝复机并保留锁
|
||||
|
||||
### Requirement: 通道实名管控配置、权限与审计
|
||||
系统 SHALL 在运营商通道上提供独立的实名管控开关 `realname_control_enabled`(0 不管控、1 管控),默认 0,MUST NOT 复用通道现有的实名链接类型等字段;存量通道全部为 0,不迁移、不修改任何卡或设备数据。开启时,通道下所有卡停复机只按卡是否已实名判断,MUST NOT 以行业卡身份或卡、设备上的实名策略放行;实名策略仍只用于购买与首次实名激活流程。仅超级管理员和平台用户 SHALL 在通道新建或编辑时配置该开关,非平台账号提交该字段 MUST 被拒绝;修改并入通道更新审计。从 0 改为 1 时,管理端 MUST 二次确认并提示该通道未实名的开机卡数。查询卡所属通道的实名管控失败时,系统本次不对该卡发起停复机并记录日志。人工复机同样按本要求判断实名。
|
||||
|
||||
#### Scenario: 默认不管控
|
||||
- **WHEN** 总开关开启,通道未修改实名管控,非行业卡未实名、卡实名策略为 `after_order`、有套餐且流量未用完
|
||||
- **THEN** 系统不因未实名停机,人工复机不因未实名被拒
|
||||
|
||||
#### Scenario: 开启后行业卡不再放行
|
||||
- **WHEN** 通道开启实名管控,行业卡未实名且开机
|
||||
- **THEN** 系统停机该卡,停因为 `not_realname`
|
||||
|
||||
#### Scenario: 越权修改实名管控
|
||||
- **WHEN** 非超级管理员、非平台用户提交通道实名管控字段
|
||||
- **THEN** 系统拒绝请求且不修改配置
|
||||
|
||||
#### Scenario: 查询通道失败
|
||||
- **WHEN** 停复机评估时卡所属通道的实名管控查询失败
|
||||
- **THEN** 系统本次不对该卡发起停复机命令并记录日志
|
||||
|
||||
### Requirement: 暂停轮询的卡不自动停复机
|
||||
总开关开启时,卡或其绑定设备暂停轮询的,系统 SHALL NOT 对该卡发起自动停机或自动复机,包括套餐激活、套餐重置、充值等非轮询触发的复机;人工停机与人工复机照常执行。运营商风险停机、机卡分离停机、已销户由人工判断并暂停轮询,系统 MUST NOT 新增按这些状态自动暂停轮询的处理;现有独立卡风险停机、已销户自动暂停轮询的处理保持不变。未暂停轮询的卡,不论运营商扩展状态如何,均按停机与复机条件处理,上游拒绝复机时按现有失败处理。
|
||||
|
||||
#### Scenario: 暂停轮询的卡充值后
|
||||
- **WHEN** 已被人工暂停轮询的停机卡充值并激活套餐
|
||||
- **THEN** 系统不自动复机;人工复机照常可用
|
||||
|
||||
#### Scenario: 恢复轮询后
|
||||
- **WHEN** 维护者为该卡恢复轮询
|
||||
- **THEN** 下一次评估起系统按停机与复机条件正常处理
|
||||
|
||||
#### Scenario: 设备卡出现机卡分离停机
|
||||
- **WHEN** 设备下的卡运营商扩展状态为机卡分离停机且未被暂停轮询
|
||||
- **THEN** 系统不自动暂停轮询,按停机与复机条件处理
|
||||
@@ -0,0 +1,117 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 卡日快照记录
|
||||
系统 SHALL 为每张被采集的卡按上海日期每天保存一条"本月自然月累计流量"快照,同时记录当天最后一次有效的运营商原始读数、当天已结算增量合计、当天是否触发重置日防旧值和有效观测次数。运营商读数查询失败、为空、为 null、无法解析、小于 0 或等于 0 时 MUST NOT 写入快照、MUST NOT 产生增量。同一卡同一天多次观测时,本月累计 MUST 取已有值与本次换算值中的较大者,不得变小。快照写入 MUST 为原子写入,轮询、人工刷新与系列观测并发写同一卡同一天时不得丢失较大值。快照永久保留。
|
||||
|
||||
#### Scenario: 同一天读到偏小的旧缓存
|
||||
- **WHEN** 某卡当天已有本月累计 500 MB 的快照,本次换算值为 480 MB
|
||||
- **THEN** 当天快照的本月累计保持 500 MB,不产生负增量
|
||||
|
||||
#### Scenario: 读数为 0 或无效
|
||||
- **WHEN** 运营商返回的已用流量为空、null、无法解析或为 0
|
||||
- **THEN** 系统不写快照、不产生增量
|
||||
|
||||
#### Scenario: 未切换卡快照写入失败
|
||||
- **WHEN** 未切换新算法的卡在观测事务提交后写快照失败或超时
|
||||
- **THEN** 系统只记录告警,本次观测结果、扣费与停复机不受影响,观测不重新入队
|
||||
|
||||
#### Scenario: 关闭快照写入总开关
|
||||
- **WHEN** 维护者把 `JUNHONG_TRAFFIC_FLOW_SNAPSHOT_ENABLED` 设为关闭并重启
|
||||
- **THEN** 未切换的卡停止写快照,其观测、扣费与停复机不受影响
|
||||
|
||||
### Requirement: 快照按通道重置日换算自然月
|
||||
系统 SHALL 按卡所属通道的上游流量重置日 `R`(1~28,上海时区 `R` 号 0 点清零)把运营商周期读数 `r` 换算为自然月累计 `m`:`R = 1` 时 `m = r`;`R > 1` 且今天日号 ≥ `R` 时 `m = r + 本月 1~R−1 号最大快照`;`R > 1` 且今天日号 < `R` 时 `m = r − (上月最大快照 − 上月 1~R−1 号最大快照)`,结果小于 0 按 0。重置日 MUST 在观测事务内按卡的通道严格读取,不得使用调用方预先计算的值;读取失败、为空或不在 1~28 时,运营商类型为联通(`CUCC`)的卡按 27、其余按 1 处理并记录日志。
|
||||
|
||||
#### Scenario: 联通卡跨重置日连续
|
||||
- **WHEN** 重置日为 27 的卡 26 号最大快照为 5000 MB,27 号清零后读到 100 MB
|
||||
- **THEN** 27 号快照的本月累计为 5100 MB,自然月累计连续
|
||||
|
||||
#### Scenario: 重置日查询失败的联通卡
|
||||
- **WHEN** 联通卡观测时通道重置日查询失败,调用方传入的重置日已被兜底为 1
|
||||
- **THEN** 系统按 27 号换算并记录日志
|
||||
|
||||
#### Scenario: 非常规重置日
|
||||
- **WHEN** 通道重置日为 15
|
||||
- **THEN** 系统以 15 号为界按同一规则换算,自然月累计连续
|
||||
|
||||
### Requirement: 重置日防旧值
|
||||
系统 SHALL 只在重置日当天判断旧值:`R = 1` 时读数超过上月最大快照的 0.9 倍(上月无快照时比较值为 0),或 `R > 1` 时本月 1~R−1 号最大快照大于 0 且读数超过其 0.9 倍,本次读数 MUST 按 0 参与换算,原始读数照常记录,并标记当天触发过防旧值。重置日次日起不再判断,读数照常写入。
|
||||
|
||||
#### Scenario: 重置日读到上周期旧值
|
||||
- **WHEN** 重置日为 1 的卡在 1 号读到超过上月最大快照 0.9 倍的读数
|
||||
- **THEN** 当天本月累计按 0 记、标记触发防旧值;次日读到的读数照常写入
|
||||
|
||||
#### Scenario: 重置日当天真实用量较大
|
||||
- **WHEN** 重置日当天真实用量超过上周期最大快照的 0.9 倍
|
||||
- **THEN** 当天按 0 记,次日如实写入,这部分用量随次日快照计入,不丢失
|
||||
|
||||
### Requirement: 已切换卡按月对账产生增量
|
||||
对已切换新算法且已有切换水位的卡,系统 SHALL 在观测事务内写入当天快照后计算增量 `Δ = 本月最大快照 − 本月各天已结算合计`。`Δ > 0` 且卡自身或卡当前绑定设备存在生效中(status=1)套餐时,系统写一条载荷与现有格式相同的 V1 流量增量事件并把 `Δ` 计入当天已结算;`Δ > 0` 但没有生效中套餐时 MUST NOT 写事件,只把 `Δ` 计入当天已结算;`Δ ≤ 0` 时不写事件。快照、已结算合计与事件 MUST 同事务提交或回滚。已切换的卡每次观测最多写一条 V1 事件,MUST NOT 再写按卡表基线计算的增量事件。生效中套餐查询出错时按有套餐处理。跨月时新月份已结算合计从 0 开始。
|
||||
|
||||
#### Scenario: 冻结卡切换后恢复计量
|
||||
- **WHEN** 卡表基线 72535 MB 而运营商读数 48808 MB 的卡切换后读数继续上涨
|
||||
- **THEN** 系统按快照计算出正增量并写 V1 事件,套餐已用量恢复增长
|
||||
|
||||
#### Scenario: 二次销售不带入上一个用户的用量
|
||||
- **WHEN** 卡在无生效中套餐期间被观测到本月累计 3020 MB,激活新套餐后读到 3050 MB
|
||||
- **THEN** 3020 MB 及之前的增量只计入已结算不写事件,新套餐只被扣 30 MB
|
||||
|
||||
#### Scenario: 迟到观测抬高昨天的快照
|
||||
- **WHEN** 今天已发出增量后,一次迟到观测把昨天的快照抬高
|
||||
- **THEN** 增量仍按本月最大快照减本月已结算合计计算,重叠部分不被扣两次
|
||||
|
||||
#### Scenario: 只有已用完或待生效套餐
|
||||
- **WHEN** 卡与绑定设备都没有生效中套餐,只有已用完或待生效套餐
|
||||
- **THEN** 增量只计入已结算,不写事件
|
||||
|
||||
### Requirement: 切换水位
|
||||
卡已在新算法名单中但没有切换水位时,系统 SHALL 把这次观测作为第一次切换观测:写入当天快照;本次增量沿用按卡表基线计算的结果,大于 0 且有生效中套餐时写 V1 事件,否则不写;把本月最大快照与本月已结算合计的差额计入当天已结算;同事务写入切换水位,记录切换时刻、本月最大快照、运营商读数、卡表基线、卡表本月计入、本次基线算法是否接受读数及其增量。退回老算法时维护者 MUST 删除对应卡的切换水位;再次切换时系统重新执行第一次切换观测。
|
||||
|
||||
#### Scenario: 切换时本月尚无快照
|
||||
- **WHEN** 正常计量的卡切换后的第一次观测发生在本月还没有任何快照时
|
||||
- **THEN** 系统只写按卡表基线计算的这一笔增量,不把整月累计当作增量写出
|
||||
|
||||
#### Scenario: 冻结卡第一次切换观测
|
||||
- **WHEN** 基线算法拒绝读数的冻结卡第一次切换观测
|
||||
- **THEN** 系统不写增量事件,切换水位记录读数未被接受及当时的运营商读数;下一次观测起按快照正常写增量
|
||||
|
||||
#### Scenario: 退回后同一天再切回
|
||||
- **WHEN** 卡退回老算法并删除切换水位后,同一天再次切换
|
||||
- **THEN** 系统重新写切换水位,退回期间老算法已扣的部分不被重复扣
|
||||
|
||||
### Requirement: 按扣减载体灰度切换
|
||||
系统 SHALL 支持 `off`、`gray`、`full` 三种计量模式与灰度名单。名单单位为扣减载体:`device:<id>` 在启动时展开为该设备当前绑定的全部卡,`iot_card:<id>` 指单卡套餐的卡;名单中的 `iot_card` 实际使用设备套餐时,系统在启动日志报错并跳过该项,不阻止进程启动。是否走新算法 MUST 用启动时载入的内存集合判断,判断出错一律走老算法。API 与全部 Worker 进程 MUST 使用一致的模式与名单。未切换的卡,卡表、V1 事件、扣减、停复机、观测结果与页面展示 MUST 与本变更前一致。
|
||||
|
||||
#### Scenario: 名单写设备
|
||||
- **WHEN** 灰度名单为 `device:15276`
|
||||
- **THEN** 该设备当前绑定的全部卡走新算法
|
||||
|
||||
#### Scenario: 名单中的单卡实际用设备套餐
|
||||
- **WHEN** 灰度名单写 `iot_card:X`,但该卡实际从绑定设备的套餐扣减
|
||||
- **THEN** 启动日志报错并跳过该项,进程正常启动,该卡仍走老算法
|
||||
|
||||
#### Scenario: 非灰度卡观测
|
||||
- **WHEN** 不在名单中的卡被观测一次
|
||||
- **THEN** 卡表、V1 事件、扣减与停复机结果与变更前完全一致
|
||||
|
||||
### Requirement: 已切换卡的通道阈值判定
|
||||
对已切换且已有切换水位的卡,系统 SHALL 在本次读数大于 0 且本次读数未被重置日防旧值按 0 处理时,用本次运营商读数做通道阈值判定,MUST NOT 以基线算法是否接受读数作为判定前提。第一次切换观测仍按基线算法的条件判定。未切换的卡保持原判定条件。
|
||||
|
||||
#### Scenario: 冻结卡切换后达量
|
||||
- **WHEN** 已切换的冻结卡读数达到通道阈值
|
||||
- **THEN** 系统写通道阈值停机锁并创建停机任务
|
||||
|
||||
#### Scenario: 重置日读到旧总量
|
||||
- **WHEN** 已切换卡在重置日读到上周期旧总量并触发防旧值
|
||||
- **THEN** 本次不做通道阈值判定;同一天之后的真实读数照常判定
|
||||
|
||||
### Requirement: 已切换卡的本月用量与日流量展示
|
||||
对已切换的卡,系统 SHALL 在观测事务内用本月最大快照覆盖卡表本月用量,使资产详情、卡列表与设备导出显示快照口径的本月用量;日流量查询 MUST 读取快照,某天用量为当天最大快照减本月此前最大快照,小于 0 按 0,本月第一条快照减数为 0。未切换的卡仍读原来源。
|
||||
|
||||
#### Scenario: 冻结卡切换后展示本月用量
|
||||
- **WHEN** 冻结卡切换后被观测
|
||||
- **THEN** 资产详情、卡列表与设备导出的本月用量等于本月最大快照,不再为 0
|
||||
|
||||
#### Scenario: 中间几天没采到
|
||||
- **WHEN** 已切换卡连续 3 天没有快照
|
||||
- **THEN** 这 3 天的用量并入之后第一个有快照的那天,不丢失
|
||||
@@ -0,0 +1,40 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: 通道阈值停机与周期恢复
|
||||
系统 SHALL 为每个已启用运营商通道按通道既有的上游流量重置日(与网关计数器清零同一事实,上海时区周期边界)判断运营商回传的每张卡当前周期累计流量,累计流量仅取网关累计读数换算,不使用本地用量统计或套餐真流量;每张卡独立判断,不扩散到设备维度,不进入既有停复机的设备扩散路径。达到或超过阈值时,系统为当前周期创建通道阈值停机锁并创建可靠停机任务;同一周期重复判定、并发或任务重放不得重复创建锁或重复发起停机。改阈值不生效于当前周期已持锁卡:当前周期维持拒绝复机,新周期按新阈值判断。
|
||||
|
||||
持锁卡在当前周期内 MUST 拒绝一切复机,包括自动复机、手动复机、保护期强制复机和机卡分离复机;拒绝时保留锁并记录拒绝事实。停机调用失败或结果未知时保留锁与任务状态,由本能力新增的恢复扫描处理:只查询运营商状态回填、确认成功后补写卡状态;自提交起超过约定窗口仍无法确认结果的,标记异常并转人工处理,不自动删除锁。本能力新增停因 `channel_threshold`,不参与既有自动复机判定,复机仅由周期处理发起。
|
||||
|
||||
新周期开始时,系统 SHALL 对仍持锁卡解除通道锁;仅存在有效主套餐、流量未耗尽、实名满足、不存在风险停机、销户或其他停机锁时创建自动复机任务,任一条件不满足时只解锁不调用运营商。其他停机锁指卡停机原因为非空且非通道阈值的其他停因,或网关扩展状态为风险停机、销户。停复机新规则总开关(`JUNHONG_STOP_RESUME_UNIFIED_RULE_ENABLED`)开启时,新周期解锁后的复机条件改为 `card-stop-resume` 的复机条件:有套餐、流量未用完、卡已实名或卡所属通道未开启实名管控,且卡与其绑定设备未暂停轮询;不再以其他停机原因或网关扩展状态阻止复机,条件不满足时只解锁不调用运营商。复机失败或结果未知同样由恢复扫描处理。卡更换运营商后,旧周期锁保留,新周期按新运营商的重置日计算。
|
||||
|
||||
#### Scenario: 达量后人工复机
|
||||
- **WHEN** 当前计费周期内持有通道阈值停机锁的卡请求复机
|
||||
- **THEN** 系统拒绝复机且保留该锁
|
||||
|
||||
#### Scenario: 新周期仍有其他停机锁
|
||||
- **WHEN** 新周期开始的持锁卡没有风险停机但存在其他停机锁
|
||||
- **THEN** 系统解除通道阈值锁但不调用运营商复机
|
||||
|
||||
#### Scenario: 达量后强制复机被拒
|
||||
- **WHEN** 当前计费周期内的持锁卡触发保护期强制复机或机卡分离复机
|
||||
- **THEN** 系统拒绝复机、保留该锁并记录拒绝事实
|
||||
|
||||
#### Scenario: 停机结果未知恢复确认
|
||||
- **WHEN** 通道阈值停机调用后结果未知,恢复扫描向运营商查询确认卡已停机
|
||||
- **THEN** 系统补写卡停机状态并将任务结果记为已确认
|
||||
|
||||
#### Scenario: 停机结果未知超期转人工
|
||||
- **WHEN** 通道阈值停机任务自提交起超过约定窗口仍无法确认结果
|
||||
- **THEN** 系统标记异常并留存安全失败原因转人工处理,不自动删除锁
|
||||
|
||||
#### Scenario: 换运营商后周期归属
|
||||
- **WHEN** 持锁卡更换运营商后到达新计费周期
|
||||
- **THEN** 旧周期锁保留,新周期按新运营商的上游流量重置日计算并处理
|
||||
|
||||
#### Scenario: 总开关开启后新周期存在其他停因
|
||||
- **WHEN** 停复机新规则总开关开启,新周期开始的持锁卡停因记录为人工停机,有套餐、流量未用完、实名条件满足且未暂停轮询
|
||||
- **THEN** 系统解除通道阈值锁并创建自动复机任务
|
||||
|
||||
#### Scenario: 总开关开启后新周期卡已暂停轮询
|
||||
- **WHEN** 停复机新规则总开关开启,新周期开始的持锁卡已被暂停轮询
|
||||
- **THEN** 系统解除通道阈值锁但不调用运营商复机
|
||||
@@ -0,0 +1,33 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: 停复机遵循实际生效实名策略
|
||||
|
||||
停复机新规则总开关(`JUNHONG_STOP_RESUME_UNIFIED_RULE_ENABLED`)关闭时,系统 SHALL 在自动停机、自动复机、设备批量复机和手动停复机的实名门槛中放行行业卡、已实名卡及实际生效策略为 `none` 的卡。独立卡或无有效设备绑定的卡使用卡策略,有有效设备绑定的非独立卡使用设备策略。系统 MUST 保留真实实名状态,不得以豁免伪造已实名事实。其他策略的未实名普通卡 MUST 保持实名限制;套餐、流量、风险、保护期及非轮询停机不自动复机等既有限制保持不变。总开关开启时,本要求不再适用,实名门槛改由 `card-stop-resume` 的通道实名管控决定,行业卡与卡、设备实名策略不参与停复机。
|
||||
|
||||
#### Scenario: 免实名独立卡有生效套餐
|
||||
- **WHEN** 未实名普通独立卡配置 `none`,存在生效套餐且流量未耗尽,当前网络在线
|
||||
- **THEN** 系统不因未实名向上游请求停机
|
||||
|
||||
#### Scenario: 免实名卡从轮询停机恢复
|
||||
- **WHEN** 上述卡当前因 `not_realname` 停机,满足其他自动复机条件
|
||||
- **THEN** 系统不因未实名阻止自动复机
|
||||
|
||||
#### Scenario: 设备策略优先
|
||||
- **WHEN** 未实名普通卡有效绑定设备,卡与设备的实名策略不同
|
||||
- **THEN** 系统以设备策略判定实名豁免,卡自身的 `none` 不得覆盖设备的实名要求
|
||||
|
||||
#### Scenario: 行业卡与已实名卡兼容
|
||||
- **WHEN** 行业卡未实名或普通卡已实名
|
||||
- **THEN** 系统保留已有实名门槛放行行为
|
||||
|
||||
#### Scenario: 无套餐和流量耗尽不豁免
|
||||
- **WHEN** 免实名卡没有生效套餐或流量已经耗尽
|
||||
- **THEN** 系统仍按对应业务原因执行停机判断
|
||||
|
||||
#### Scenario: 策略读取失败
|
||||
- **WHEN** 未实名普通卡的有效设备绑定或设备策略查询失败
|
||||
- **THEN** 系统报告错误且不对该卡发起本次停复机命令,不按卡策略回退放行
|
||||
|
||||
#### Scenario: 总开关开启后改按通道实名管控
|
||||
- **WHEN** 停复机新规则总开关开启,未实名普通卡的实名策略不是 `none`,卡所属通道未开启实名管控
|
||||
- **THEN** 系统不因未实名停机或阻止复机,按 `card-stop-resume` 的条件处理
|
||||
@@ -0,0 +1,59 @@
|
||||
## 1. 迁移与模型
|
||||
|
||||
- [x] 1.1 新增成对迁移 `000241`:建 `tb_card_flow_day`(`iot_card_id`、`flow_date`、`month_used_mb`、`vendor_used_mb`、`settled_mb`、`stale_guarded`、`obs_count`、时间戳,唯一键 `(iot_card_id, flow_date)`)与 `tb_card_flow_switch`(`iot_card_id` 唯一、`switched_at`、`month_used_mb`、`vendor_used_mb`、`old_baseline_mb`、`old_month_usage_mb`、`old_reading_accepted`、`old_increment_mb`、`created_at`);down 删除两表。
|
||||
- [x] 1.2 新增成对迁移 `000242`:`tb_carrier` 增加 `realname_control_enabled smallint not null default 0`;down 删除该列。
|
||||
- [x] 1.3 新增 `model.CardFlowDay`、`model.CardFlowSwitch`;`model.Carrier` 增加 `RealnameControlEnabled`。
|
||||
|
||||
## 2. 计量领域规则
|
||||
|
||||
- [x] 2.1 新增 `internal/domain/cardflow/`:按重置日 `R` 把读数换算为自然月累计(`R = 1`、`R > 1` 且日号 ≥ `R`、`R > 1` 且日号 < `R` 三种,小于 0 按 0)。
|
||||
- [x] 2.2 重置日防旧值:`R = 1` 比上月最大快照、`R > 1` 比本月 1~R−1 号最大快照(大于 0 才判断),超过 0.9 倍按 0;返回是否触发。
|
||||
- [x] 2.3 按月对账增量 `Δ = 本月最大 − 本月已结算合计`,以及每天用量(当天最大 − 本月此前最大,小于 0 按 0)。
|
||||
- [x] 2.4 重置日严格读取与兜底:按卡 `carrier_id` 查 `data_reset_day`,失败、为空或不在 1~28 时 `CUCC` 取 27、其余取 1 并记日志;不使用 `TrafficObservation.ResetDay`。
|
||||
|
||||
## 3. 快照与水位存储
|
||||
|
||||
- [x] 3.1 新增 `internal/store/postgres/card_flow_day_store.go`:`INSERT ... ON CONFLICT (iot_card_id, flow_date) DO UPDATE` 原子写入(本月累计取较大值);查询本月最大值、本月 1~R−1 号最大值、上月最大值与上月 1~R−1 号最大值、本月已结算合计;累加当天已结算。
|
||||
- [x] 3.2 新增 `internal/store/postgres/card_flow_switch_store.go`:按卡读取与写入切换水位。
|
||||
|
||||
## 4. 切换配置
|
||||
|
||||
- [x] 4.1 `pkg/config` 增加 `TrafficCalc` 配置段与 `defaults/config.yaml` 默认值(`mode: off`、名单为空、快照开关开),对应 `JUNHONG_TRAFFIC_CALC_MODE`、`JUNHONG_TRAFFIC_CALC_CARDS`、`JUNHONG_TRAFFIC_FLOW_SNAPSHOT_ENABLED`。
|
||||
- [x] 4.2 启动时把名单展开为内存卡集合:`device:<id>` 展开为当前绑定全部卡;`iot_card:<id>` 实际使用设备套餐(与 `resolveActivePackages` 同口径)时启动日志报错并跳过;`full` 为全部卡。API 与全部 Worker 共用同一实现。
|
||||
|
||||
## 5. 观测事务的已切换分支
|
||||
|
||||
- [x] 5.1 `internal/application/cardobservation/traffic.go`:读数 `> 0` 时按第 2 节规则写当天快照;已切换卡在事务 1 内写,未切换卡在事务 1 提交后写(失败只告警,受快照开关控制);判定已切换出错一律走老分支,老分支逻辑不改。
|
||||
- [x] 5.2 已切换且有水位的卡:按月对账计算 `Δ`;只读判断卡或当前绑定设备是否有 status=1 套餐(出错按有套餐);有套餐写 V1 事件并累加已结算,无套餐只累加已结算;不再写老增量的 V1 事件。
|
||||
- [x] 5.3 已切换但无水位的卡(第一次切换观测):写快照,按老增量与套餐判断决定是否写 V1,把本月最大与已结算合计的差额计入已结算,同事务写切换水位。
|
||||
- [x] 5.4 已切换卡的通道阈值判定:读数 `> 0` 且本次未被防旧值处理即调用 `EvaluateInTx`;第一次切换观测仍按老条件;未切换卡条件不变。
|
||||
- [x] 5.5 已切换卡在同一条卡表 `Updates` 里用本月最大快照覆盖 `current_month_usage_mb`;`last_gateway_reading_mb` 只读不写。
|
||||
|
||||
## 6. 日流量读侧
|
||||
|
||||
- [x] 6.1 日流量查询对已切换卡改读快照(每天用量按 2.3),未切换卡仍读原来源;全量切换后的 Redis 日流量缓冲与 02:00 落盘下线不在本节,按上线步骤另行处理。
|
||||
|
||||
## 7. 停复机新规则
|
||||
|
||||
- [x] 7.1 `pkg/config` 增加 `JUNHONG_STOP_RESUME_UNIFIED_RULE_ENABLED`(默认关闭);关闭时 `stop_resume_service.go` 全部现有路径保持不变。
|
||||
- [x] 7.2 新增目标状态判断:卡或绑定设备暂停轮询 → 不动作;开机时无套餐、流量用完、通道实名管控且未实名即停(停因与设备扩散规则不变);停机时有套餐、流量未用完、已实名或通道未管控即复,不看停因;持通道阈值锁拒绝复机。
|
||||
- [x] 7.3 `EvaluateAndAct` 两个分支、`resumeSingleCard`、`resumeDeviceCards`、`ResumeCardIfStopped` 在总开关开启时改用 7.2 判断;设备复机在总开关开启时复用 `iot_card_store.go` 现有的 `ListByDeviceIDAndNetworkStatus` 取设备下全部停机卡。
|
||||
- [x] 7.4 `isRealnameOK` 在总开关开启时改为按卡所属通道 `realname_control_enabled` 判断(0 满足、1 看 `real_name_status`),删除行业卡与卡/设备实名策略分支,通道查询失败返回错误;人工复机同步生效。
|
||||
- [x] 7.5 `internal/task/polling_protect_handler.go`:总开关开启时只在通道开启实名管控且卡未实名时跳过保护期检查。
|
||||
- [x] 7.6 `internal/application/carrierthreshold/` 新周期恢复:总开关开启时复机条件改用 7.2(不再以其他停因或网关扩展状态阻止),条件不满足只解锁。
|
||||
|
||||
## 8. 通道实名管控配置
|
||||
|
||||
- [x] 8.1 `service/carrier` 与通道 DTO:创建、修改、详情支持 `realname_control_enabled`,仅超级管理员与平台用户可提交,非平台账号提交被拒;修改并入通道更新审计。
|
||||
- [x] 8.2 通道修改从 0 改为 1 时返回或提供该通道未实名开机卡数,供管理端二次确认。
|
||||
- [x] 8.3 同步路由文档说明,运行 `go run cmd/gendocs/main.go` 重新生成接口文档。
|
||||
|
||||
## 9. 构建与测试环境验证
|
||||
|
||||
- [x] 9.1 对变更 Go 文件执行 `gofmt -w`,运行 `go build ./cmd/api ./cmd/worker`、`openspec validate rebuild-card-traffic-metering-and-stop-resume --strict`。
|
||||
- [ ] 9.2 按 ENG-TEST-001 在维护者指定的测试环境执行迁移 up/down/up,核对两张新表与 `tb_carrier` 新列默认值。
|
||||
- [ ] 9.3 计量模式 `off`:非灰度卡观测一次,卡表、V1 事件、扣减、停复机结果与改动前一致,且写入了快照;关闭快照开关后停写。
|
||||
- [ ] 9.4 灰度 `device:<测试设备>`:构造冻结卡(基线高于读数)、二次销售卡、本月无快照的正常卡、联通 27 号与 1 号重置的卡,逐次核对快照、已结算、水位、V1 事件与套餐已用量;退回删水位后同日再切回不重复扣。
|
||||
- [ ] 9.5 已切换冻结卡读数达阈值写通道停机锁;重置日防旧值触发时不判定;资产详情、卡列表、设备导出的本月用量等于本月最大快照;日流量读快照。
|
||||
- [ ] 9.6 停复机总开关关闭时行为与改动前一致;开启后核对:外部停机、人工停机、设备保护期停机的卡满足条件复机;暂停轮询的卡充值后不复机;通道开启实名管控时未实名卡(含行业卡)停机且不复机、实名后复机;通道未管控时未实名卡不停机、人工复机不被拒;持阈值锁拒绝复机;新周期解锁按新条件复机。
|
||||
- [ ] 9.7 通道实名管控字段的权限与审计:非平台账号提交被拒,平台账号修改写入通道更新审计。
|
||||
Reference in New Issue
Block a user