Files
msgexchange-v2/docs/user-stories.md
T

273 lines
18 KiB
Markdown
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.
# msgexchange-v2 用户故事草案
> 依据 `architecture.md`、`design.md`、Plane ACM2-3/5/6/7/12/1522 与 legacy 基线整理。
> 本文描述目标能力和明确保留的兼容行为,不代表当前代码已完成。
## 1. 约定
- “信箱已落信”“PG 已入队”“业务处理成功”“共享信箱已回填”“下游已投递”是不同事实。
- `KEEP` 表示兼容现役;`FIX` 表示修复 legacy 缺陷;`DEFERRED` 表示不属于阶段 A。
- 依赖只表示前置能力,不形成循环;待决策内容不得伪装成验收标准。
## 2. 阶段 A 用户故事
### US-01 可靠采集共享信箱报文
**作为** 平台运维人员,**我希望** 持续采集 `CMINMSGS` 未处理报文,**以便** 上游无需改变投递方式。
**验收标准**
1. 按配置周期、ID 升序和有限批次采集 `DATE_PROCESSED IS NULL`;这里只采集入队,不代表业务已处理。
2. 快路径使用持久化高水位增量扫描;另以受控周期补偿重扫“未处理且 PG 无状态”的记录。水位只在本批入队确认后推进。
3. 每个 ID 在 PG 至多一个 `PROC_STATE(PENDING)`;重复发现不重复入队。
4. PG 不可用时不改共享信箱标记;恢复后补偿重扫能补建遗漏状态。
5. 单条异常和数据库故障可观察,轮询线程不得静默退出。
**依赖**:共享库读权限、字段与索引契约。
**实现差距**:当前 `InboxPoller` 固定 `afterId=0` 全量扫描,无持久化水位和独立补偿频控。
### US-02 通过兼容接口注入报文
**作为** 联调人员,**我希望** 通过 `POST /cminmsgs/send` 注入 XML,**以便** 执行回放和对拍。
**验收标准**
1. 信箱落信后返回 `CMINMSGS_ID`,响应不得暗示 PG 已入队或业务已处理。
2. 落信成功但 PG 入队失败时,由 US-01 最终补建。
3. Content-Type 支持 `text/xml``application/xml``text/plain`(默认按 UTF-8 解码);空报文、超大报文(> 10MB)及畸形 XML 返回规范错误。
4. 响应结构逐字兼容 legacy `ResponseDto`:成功返回 `{"is_success": true, "body": <CMINMSGS_ID>}`,失败返回 `{"is_success": false, "err_code": "<code>", "err_msg": "<detail>"}`
5. 生产默认沿用现役内网互信免密姿态(网关限定内部 IP 网段与审计);外露或跨网络时启用 Header 认证。
**依赖**US-01。
### US-03 严格按序且幂等地执行处理管道
**作为** 航班数据消费者,**我希望** 报文严格按信箱顺序处理,**以便** 重试不会造成倒序状态。
**验收标准**
1. 选择最小未完成 ID`PENDING``FAILED` 都占队头,退避期间后续消息不得越过。
2. identity 首绑为 `SNDR|TYPE|STYP|SEQN`;冲突转 `SKIPPED` 并记录原 ID。
3. `MALFORMED` 直接 DEAD`CODEC_ERROR/UNSUPPORTED/INFRA` 退避;attempts 或 HOL deadline 耗尽后转 `DEAD(EXHAUSTED)`
4. PUMP_JOB 不与消息形成统一全序,只在无队头或队头尚在退避窗口时执行;不得让已到期消息饥饿。
5. Redis 先应用;`MSG_EVENT``PROC_STATE→SUCCEEDED` 在同一 PG 事务提交。
6. Redis 已写、PG 未提交的窗口可幂等重放。
**依赖**US-01。
**既有基线定案**:生产幂等键默认采用 `SNDR|TYPE|STYP|SEQN``include-day-boundary=false` 禁开,防止跨日重放漏判;HOL deadline 起算时间统一固化为 `PROC_STATE.CREATED_AT`(稳定入队时间戳),消除重试刷新 `updatedAt` 导致的超时不可达缺陷。
### US-04 忽略非业务报文(KEEP
**作为** 运维人员,**我希望** 已确认无需处理的报文被明确忽略,**以便** 不产生 DLQ 噪声。
**验收标准**
1. 解码 META 后、查 Handler 前,大小写不敏感匹配 `TYPE-STYP``TYPE-*`
2. 基线为 `LDM-*``REGN-*``RSTA-*``EROR-*`;统一采用 `EROR`,消除 test 的 `ERROR` 漂移。
3. 命中后进入 `SKIPPED`,记录 `ignored:<rule>`,不创建业务事件。
4. 按 US-09 的规则回填共享信箱,并保留审计计数。
**依赖**US-03、US-09。
### US-05 应用 ADFT 与 29 类 FLOP 报文
**作为** OMMS 业务,**我希望** 正确应用增量报文,**以便** Redis 动态符合 wire 契约。
**验收标准**
1. `SCHD-ADFT` 和 29 个 FLOP 子类型均有纯函数 Handler;未知类型进入 `FAILED(UNSUPPORTED)`
2. 每类覆盖输入、Redis 变化、msg、schd、处理终态五面断言。
3. 航班不存在按 legacy KEEP 语义结束且不重试:以 `SUCCEEDED` 终态结束,按 US-09 回填共享信箱 `DATE_PROCESSED = now()`, `STATUS = 'SUCCESS'`,防止死循环。
4. 共享航班默认不直接发通知,而是更新并通知主航班;FDEL 例外定案:删除共享航班时更新主航班 MAFL 列表并发出主航班通知;若删除主航班则删除其及所有子共享关联并发出删除通知;目标航班不存在时幂等成功退出。
5. ADFT/FDEL 使用值相等比较,主/共享关系作为一次原子 Redis 变更持久化(FIX)。
6. PSDT 依赖 US-14Handler 不直接调用 admin-api。
**依赖**US-03、US-14、SIS/XSD 与 KEEP/FIX 矩阵。
### US-06 导入 RESP/DNLD 日计划快照
**作为** 航班计划使用方,**我希望** RESP 与 DNLD 共用快照流程,**以便** 主动下载和请求应答获得相同终态。
| 报文 | SnapshotFlow | REQ_TRACK | Kafka msg | 迟到/无匹配处理 |
|---|---|---|---|---|
| `SCHD-DNLD` | 是 | 不更新 | 成功后通知 | 不适用(广播/全量) |
| `SCHD-RESP` | 是 | 匹配开放 RQFD 后 DONE | 成功后通知 | 严禁更快照,转 SKIPPED 并审计 |
| `SCHD-ADFT` | 否,走 US-05 | 不更新 | 按增量规则 | 增量应用 |
**验收标准**
1. RESP/DNLD 共用 staging 流式整包校验和 SnapshotFlow,不作为普通 FLOP 增量 Handler 重复实现。
2. 主泵执行先后严格服从 I2(happens-before):主泵线程先执行 Redis Lua 完成写新代、旧代差集删除及 generation 版本 CASADFT 航班存活,FIX);Redis 执行成功后进入自有 PG 本地事务。
3. 自有 PG 本地事务原子性:同一 PG 事务内原子提交 `PROC_STATE → SUCCEEDED`、匹配开放请求的 `REQ_TRACK → DONE`(记录 completed_at 与 resp_cminmsgs_id)及 `MSG_EVENT` 出站通知。
4. 整包失败保留旧快照;相同报文重放(CAS 版本一致)幂等,不重复增代或差删。
5. 迟到(`dttm < req.sentAt`)或无匹配/过期(`EXPIRED`RESP **严禁更新快照**,转入 `PROC_STATE → SKIPPED` 并记录审计与告警,防止历史快照时光倒流覆盖新状态(对齐 G12)。
6. 覆盖首次/连续发布、DNLD→ADFT→DNLD′、RESP 匹配和崩溃窗口。
**依赖**US-03、US-08、Redis gen 协议。
### US-07 可靠、有序地投递 Kafka
**作为** Kafka 消费者,**我希望** 状态可见后有序投递,**以便** 通知不指向旧状态。
**验收标准**
1. `KAFKA:msg` 按 EVENT_ID FIFO,确认后才标 SENT。
2. `KAFKA:schd` 按周期和上限领取;同一 FLID 仅发批内最新事件。
3. 失败保持队头并退避;耗尽后 DEAD,不静默丢弃。
4. 事件包含稳定去重标识,分区键和重复投递有契约测试:`KAFKA:msg``SNDR` 作为分区键;`KAFKA:schd` 严格以 `FLID` 为分区键,确保单航班有序。
5. 生产环境对接 Kafka 2.8+ / 3.x+,生产者强制 `acks=all``enable.idempotence=true``max.in.flight.requests.per.connection=1`,严禁非幂等降级;投递失败退避重试,达上限转 `DEAD(DLQ)` 告警,绝不静默丢弃。
**依赖**US-03、现网 Kafka Broker API 版本确认(切流前 `kafka-broker-api-versions.sh` 探测 `InitProducerId(22)`;未确认前不得标 US-07 实施完成)。
### US-08 发起并跟踪 15 类 AODB 请求
**作为** 业务或运维人员,**我希望** 发起请求并跟踪生命周期,**以便** 区分登记、落信、等待、完成和超时。
**验收标准**
1. 支持 14 类 RQRD 参考请求和 1 类 RQFD-NONE 日计划请求。
2. REQ_TRACK 先登记;COUTMSGS 落信后才关联 ID 并标 SENT,落信不等于对方已发送。
3. 逐类超时与并发规则定案:同类请求并发严格为 1(新请求注册时强制同类未决请求转 `EXPIRED`);`RQFD-NONE` 超时为 60s14 类 `RQRD` 超时默认为 30s。
4. 响应经 US-01/US-03 入站:优先以报文回显 `SEQN``echoSeqn`)精确匹配开放请求;无回显时降级为时序判定(仅接受 `DTTM >= SENT_AT` 的开放请求),并在完成时同 PG 事务标 `DONE`
5. 超时或被替代的请求 EXPIRED;迟到响应(`DTTM < SENT_AT`)或无匹配响应严禁更新业务状态/快照,转 SKIPPED 并留审计。
6. **集成验收**SCHD-RESP 遵循 US-0614 类响应刷新 REF_MASTER,不与 admin-api 21 类混同。
**依赖**US-01、US-03、COUTMSGS 适配器及逐类超时参数。
### US-09 补偿回填共享信箱
**作为** 上游和运维人员,**我希望** PG 终态最终反映到共享信箱,**以便** 未处理积压语义准确。
**验收标准**
1. **解耦与异步执行**:主泵 PG 事务(更新 `PROC_STATE` 终态 + 插入 `MSG_EVENT`)内写入持久化回填意图;PG 事务提交后异步触发共享信箱回填,严禁内联同步阻塞等待共享库;回填失败绝不回滚 PG 终态。
2. **持久化补偿**:未完成或失败的回填由后台补偿任务按指数退避重试;暴露待回填积压量与最老年龄指标,持续失败触发告警。回填 SQL 具备幂等性(`UPDATE CMINMSGS SET DATE_PROCESSED = :now, STATUS = :status ... WHERE CMINMSGS_ID = :id`)。
3. **各终态回填规则矩阵**(单值锁定;库方/legacy 实测前为占位,见 §7-9):
- `SUCCEEDED`**必须回填**`DATE_PROCESSED = now()`, `STATUS = 'SUCCESS'`,补齐 META 子系统列)。
- `ignore SKIPPED`(规则忽略):**必须回填**`DATE_PROCESSED = now()`, `STATUS = 'SKIPPED'`),防止上游视作未处理积压持续重扫。
- `duplicate SKIPPED`(身份键重复):**必须回填**`DATE_PROCESSED = now()`, `STATUS = 'DUPLICATE'`),确认去重终结。
- `DEAD`(毒丸/耗尽/MALFORMED):**必须回填**`DATE_PROCESSED = now()`, `STATUS = 'DEAD'`),避免共享信箱长期未处理告警或双跑旧系统死循环。运维人工重放基于自有 PG 驱动,不依赖信箱重置。
- 非终态(`PENDING``FAILED`):**绝对禁止回填**,保持 `DATE_PROCESSED IS NULL`
4. **影子与双跑隔离**:影子实例绝对禁止回填共享信箱;与 legacy 双跑时严格保持单系统持有标记写权。
5. 查询和日志分别展示 PG 终态与信箱回填状态。
**依赖**:US-03、共享库更新权限、共享库 STATUS 值域确认(库方/legacy 对拍)。
### US-10 运维重放与故障处置
**作为** 运维人员,**我希望** 查询并安全重放失败项,**以便** 修复故障而不破坏顺序。
**验收标准**
1. 可按记录、错误类和时间查询 attempts、错误及 traceId。
2.`CODEC_ERROR/UNSUPPORTED/INFRA/EXHAUSTED` 可重放;请求含 MALFORMED 时静默跳过该记录,并返回逐项结果。
3. 重放清零 attempts/nextAttemptAt,保留错误审计,仍服从 FIFO。
4. DEAD、持续回填失败、队列年龄越界产生告警;操作记录操作者、原因、范围和结果。
**依赖**US-03、鉴权与审计。
### US-11 归档终态入站报文
**作为** 平台运维人员,**我希望** 定期归档终态报文,**以便** 控制信箱规模且不丢未完成工作。
**验收标准**
1. 默认处理接收时间早于 **1 天**的 `SUCCEEDED/SKIPPED/DEAD`;保留期可配置为 17 天;不迁 PENDING/FAILED。
2. **共享库零建表与 DML 最小化定案**:严禁向共享 MySQL 写入 `CMINMSGS_HST`,共享库严格限定为信箱两表(CMINMSGS 读/回填,COUTMSGS 写入);共享 MySQL 自身历史清理交由库方自身 DBA 策略。
3. **归档迁入自有 PG**:在自有 PostgreSQL 设计 `PROC_STATE_HST`(及 `MSG_EVENT_HST`)承载历史归档数据。
4. 重复执行幂等并记录计数;迁移失败时 fail-closed,不删除源记录。
**阶段**A。
### US-12 查询实时航班
**作为** 授权调用方,**我希望** 查询实时航班,**以便** 获得与 Redis 权威态一致的数据。
**验收标准**
1. KEEP `GET /all/flights`:返回 Redis 当前航班并过滤 `MAID != NULL` 的共享航班。
2. 固定响应、空结果、排序、分页/大小上限和一致性时点。
3. 影子只查询影子 key;接口具备认证、限流和审计。
### US-13 刷新 21 类参考主数据
**作为** 业务组件,**我希望** 从 admin-api 刷新 21 类数据到 REF_MASTER,**以便** 使用可审计的本地主数据。
**验收标准**
1. 采用 ACM2-5 清单;admin-api 拉取与 US-08 的 AODB 请求是两个入口。
2.`(RTYPE,RKEY)` 幂等 upsert,记录 SOURCE、刷新时间和批次审计。
3. 单类失败不发布半批,不破坏上个可用版本;影子默认不主动刷新生产数据。
### US-14 提供机位与登机桥数据
**作为** PSDT 处理逻辑,**我希望** 获得机位和登机桥映射,**以便** 正确计算 `abdg`
**验收标准**
1. 保留 ORMS_STAND 与 ORMS_STAND_AIRBRIDGE,和新增 21 类分开统计。
2. 通过适配器拉取并缓存;Handler 不直接 HTTP。
3. 近机位生成登机桥,远机位或清空时 `abdg` 为空;多桥规则由 golden 固定。
4. admin-api 不可用时使用最后可用版本或明确失败,不写不完整缓存。
## 3. 延后故事
### US-15 历史航班清场(DEFERRED
**作为** 平台运维人员,**我希望** 历史写成功后移出实时态,**以便** 控制 Redis 规模且不丢历史。
1. 全系统统一固定基准时区为 `Asia/Shanghai`CST, UTC+8)。
2. 阶段归属与 ES 边界定案:`HISTORY_SWEEP` 延后为阶段 B 能力(DEFERRED),阶段 A 永续以 Redis 作为航班动态权威,完全不接入 ES;不作为阶段 A 切流门禁。
3. 五条判史规则与 ES 写入留在阶段 B 启用前完成 100% golden 对拍;逐条隔离坏数据;仅历史写成功的 FLID 可由主泵删除。
4. 与快照保持单写者串行并记录计数。
## 4. 上线 Epic
### EPIC-OPS 安全运行、影子验证与切流
该范围不能作为一个故事验收,拆为:
1. **OPS-1 单写者与 fail-fast**:第二写实例拒启;生产缺依赖或管道未启用时失败并说明原因。
2. **OPS-2 可观测性**:健康、队列、最老年龄、投递延迟、回填滞后、DEAD 和一致性均有指标/告警。
3. **OPS-3 影子隔离**:独立 PG、Redis 前缀、topic、服务名;禁用真实出站和回填。
4. **OPS-4 切流回滚**:影子连续稳定对拍不少于 7 天;未解释业务字段差异严格为 0;DLQ 积压为 0MSG_EVENT 最老滞留 < 5s;切流后设立 48 小时观察期,24 小时内支持按 Runbook 平滑一键回滚。
依赖按实际进入上线范围的阶段 A 故事计算,不包含 US-15。
## 5. Legacy HTTP 工具面
| 端点 | 决定 | 目标口径 |
|---|---|---|
| `POST /cminmsgs/send` | KEEP | US-02 |
| `POST /schd/sync` | KEEP,修正 | 24 小时制、非空/区间校验;只承诺 RQFD 落 COUTMSGS |
| `GET /all/flights` | KEEP | US-12 |
| `POST /kafka/topics/{name}/msgs` | 不进生产 | 若开发仍需,另建工具并限制 topic allowlist |
| `GET /flights/migrate` | 不做 | legacy 一次性 ES 迁移工具 |
## 6. 详细文档 TODO
| 顺序 | Plane | 文档动作 | 完成条件 |
|---|---|---|---|
| 1 | ACM2-16 | 固定 RESP/DNLD/ADFT 路由 | US-06、design、ACM2-6 一致,迟到/无匹配禁更快照定案 |
| 2 | ACM2-17 | 拆归档与清场并标阶段 | US-11 属 AUS-15 DEFERREDHST 禁写,自有 PG 归档定案 |
| 3 | ACM2-19 | 增补信箱回填 | 提交后执行、持久化补偿、四终态回填、影子禁写定案 |
| 4 | ACM2-21 | 消除循环依赖并补管道边界 | US-03 仅依赖 US-01,业务例外归 US-05 |
| 5 | ACM2-15 | 增补 ignoreMsg | 规则、终态、回填和拼写确定 |
| 6 | ACM2-18 | 补查询、机位、21 类数据 | US-1214 与 US-08 分界明确 |
| 7 | ACM2-20 | 声明 HTTP 工具去留 | 五端点均有决定 |
| 8 | ACM2-22 | 吸收评审剩余项 | 水位、依赖、Broker、deadline 一致 |
| 9 | — | 同步 architecture/design/README | 权威口径、索引与阶段表一致 |
## 7. 开放问题定案结论汇总
1. **【已定案·ACM2-17】归档存储目标**:共享库 CMINMSGS_HST 严禁写入,共享库严格限定信箱两表;归档目标确认为自有 PG `PROC_STATE_HST`
2. **【已定案·ACM2-21】SEQN 重置与时钟锚点**:生产默认保持 `include-day-boundary=false`HOL deadline 锚点固化为 `PROC_STATE.CREATED_AT`(稳定入队时间戳)。
3. **【已定案·ACM2-20/25】compat 接口契约**:支持 text/xml、application/xml 与 text/plain;逐字兼容 legacy `ResponseDto`(成功 `is_success`+`body`;失败 `is_success`+`err_code`+`err_msg`,不用 `msg`);生产保持内网信任姿态。
4. **【已定案·ACM2-21】航班不存在与 FDEL**:航班不存在按 KEEP 正常结束且回填信箱;FDEL 共享航班更新主航班 MAFL 并通知,主航班删除清空关联。
5. **【已定案·ACM2-16/18】15 类请求生命周期**:同类并发严格为 1;RQFD 超时 60sRQRD 超时 30s;优先 SEQN 回显,无回显退化 DTTM 时序判定;迟到/无匹配禁更快照。
6. **【已定案·ACM2-22/23】Kafka 生产契约**:强制 `acks=all``idempotence=true`,分区键按 FLIDschd)/SNDR(msg)固化;严禁非幂等降级;现网 Broker API 版本未确认前 US-07 不得标实施完成;README 不提供生产降级 env。
7. **【已定案·ACM2-17】时区与判史边界**:统一 `Asia/Shanghai` 时区;HISTORY_SWEEP 延后至阶段 B,阶段 A 不依赖 ES,Redis 永续动态权威。
8. **【已定案·ACM2-22】对拍与回滚阈值**:影子对拍至少 7 天;业务差异 0 容忍;DLQ 积压为 0;切流后 48 小时保驾、24 小时可平滑回滚。
9. **【已定案·ACM2-26】信箱回填 STATUS 值域**`SUCCEEDED``SUCCESS`ignore `SKIPPED``SKIPPED`duplicate `SKIPPED``DUPLICATE``DEAD``DEAD`(库方/legacy 实测前为占位;若库方禁新值则仅用 legacy 已用集合)。