# msgexchange-v2 用户故事草案 > 依据 `architecture.md`、`design.md`、Plane ACM2-3/5/6/7/12/15~22 与 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": }`,失败返回 `{"is_success": false, "err_code": "", "err_msg": ""}`。 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:`,不创建业务事件。 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-14,Handler 不直接调用 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 版本 CAS(ADFT 航班存活,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` 超时为 60s,14 类 `RQRD` 超时默认为 30s。 4. 响应经 US-01/US-03 入站:优先以报文回显 `SEQN`(`echoSeqn`)精确匹配开放请求;无回显时降级为时序判定(仅接受 `DTTM >= SENT_AT` 的开放请求),并在完成时同 PG 事务标 `DONE`。 5. 超时或被替代的请求 EXPIRED;迟到响应(`DTTM < SENT_AT`)或无匹配响应严禁更新业务状态/快照,转 SKIPPED 并留审计。 6. **集成验收**:SCHD-RESP 遵循 US-06;14 类响应刷新 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`;保留期可配置为 1~7 天;不迁 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 积压为 0;MSG_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 属 A,US-15 DEFERRED;HST 禁写,自有 PG 归档定案 | | 3 | ACM2-19 | 增补信箱回填 | 提交后执行、持久化补偿、四终态回填、影子禁写定案 | | 4 | ACM2-21 | 消除循环依赖并补管道边界 | US-03 仅依赖 US-01,业务例外归 US-05 | | 5 | ACM2-15 | 增补 ignoreMsg | 规则、终态、回填和拼写确定 | | 6 | ACM2-18 | 补查询、机位、21 类数据 | US-12~14 与 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 超时 60s,RQRD 超时 30s;优先 SEQN 回显,无回显退化 DTTM 时序判定;迟到/无匹配禁更快照。 6. **【已定案·ACM2-22/23】Kafka 生产契约**:强制 `acks=all` 与 `idempotence=true`,分区键按 FLID(schd)/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 已用集合)。