diff --git a/README.md b/README.md index 84d4848..25579c1 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ 仓库根目录提供兼容 Podman Compose 与 Docker Compose 的开发中间件栈 `compose.yaml`,包含: - **共享信箱 MySQL**(`mysql:8.4` LTS,端口 3306,库 `cdairport`):容器启动时自动执行 `deploy/dev/mysql-init/01-mailbox.sql` 创建本地联调所需的 `CMINMSGS`、`CMINMSGS_HST`、`COUTMSGS` 模拟表。 - **自有 PostgreSQL**(`postgres:17-alpine`,端口 5432,库 `msgx`):容器提供干净数据库,应用启动时由 Flyway(`src/main/resources/db/migration/V1__flight_state_baseline.sql`)自动建自有表。 -- **Valkey**(`valkey/valkey:8-alpine`,端口 6379):本地兼容服务;应用不依赖它(`application.yml` 无对应配置键,航班状态权威在自有 PG)。 +- **Valkey**(`valkey/valkey:8-alpine`,端口 6379):本地兼容服务;应用不依赖它(`application.yml` 无对应配置键,航班状态权威在自有 PG)。Redis 航班快照与 `GET /all/flights` 是目标设计(`G-REDIS-PROJECTION`),当前实现不写入也不读取。 - **Kafka**(`apache/kafka:3.8.0` KRaft 单节点,端口 9092):listener `PLAINTEXT://localhost:9092`,`default.replication.factor=1`,已预配幂等生产者与 acks=all 所需的单节点参数。 ### 快速启动 diff --git a/docs/README.md b/docs/README.md index 4f1f9fe..9edf846 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,6 +51,8 @@ - 同一行登记多个 ID(如验证映射的 `INV-3`、`INV-10`)是引用行,不构成定义。 其他位置一律是引用。 - 编号稳定:条款被取代时标 `[作废 by C-y]` 并保留原文;不静默改写,不重编号。 +- 编号不含字母后缀:同一个编号只有一条定义(不要在编号后接 `a`/`b` 这类字母),要拆分条款就新开一个编号。 + 交付前存在悬空引用时,允许一次性归一化到已定义编号——全仓引用同步改写、条款语义不变;语义被取代时仍按上一条标记。 - **引用只用稳定 ID**,不用章节号:写 `US-03` AC1、`C-8`、`PARAM:msgx.pipeline.claim-batch`,或「见 implementation.md『收报』」这类文件名 + 小节名指针。章节号随增删章节腐烂,指针失效后必然被改写为复述。 - 指针之后**不再复述**被指内容。若两处需要同一段话,说明它放错了位置。 - 外部 SIS 证据统一写 `SIS:
`(如 `SIS:3.16-note-4`),解析到 [legacy/SIS_AODB_RMS-V0.1.md](legacy/SIS_AODB_RMS-V0.1.md) 的章节;它不属于本项目规范 ID,不参与唯一定义检查。 diff --git a/docs/architecture.md b/docs/architecture.md index 4ec3e26..ba7d7df 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -70,7 +70,7 @@ delivery 投递 jobs 作业:回填 / 出站重试 / 历史清理 / |---|---|---| | 自有 PostgreSQL | 消息处理状态、回填意图、待发事件、出站请求状态、航班当前态、未映射字段与静态参考数据 | 航班当前态的唯一权威;本地事务只覆盖此库(`INV-5`)。 | | Redis | 航班查询投影 | 由本系统根据 PG 当前态维护;不存处理状态(`INV-11`)。 | -| 共享 MySQL | 入站与出站信箱 | 外部邮箱边界;不改表结构,出站交付止于落信(`C-2`、`C-4`)。 | +| 共享 MySQL | 入站与出站信箱 | 外部邮箱边界;不改表结构,入站行只写回处理标记、不删除,出站交付止于落信(`C-1`、`C-2`、`C-4`)。 | | Elasticsearch | 已结束航班的历史 | 历史写入成功后才删除实时航班(`D1`)。 | 跨存储步骤不能并入 PG 事务,由持久意图与幂等重试衔接;具体分段见「主流程」。 diff --git a/docs/contracts/interface-contract.md b/docs/contracts/interface-contract.md index 632ca88..f0203b5 100644 --- a/docs/contracts/interface-contract.md +++ b/docs/contracts/interface-contract.md @@ -40,7 +40,7 @@ AODB 经 CIIMS adapter 把 XML 报文写入 `CMINMSGS`,格式以架构指定 | 主题 | 已确定的消息语义 | 尚需确定 | |---|---|---| -| `msg` | 单条航班变更通知;航班动态与删除处理完成后投递;发送失败自动重试,一直失败的记录保留可查并告警(`US-08`);同一 `FLID` 的变更保序,对外按至少一次投递(`CLM-3`,单分区)。删除通知的来源有三处:`FDEL` 删除(`US-06`)、日计划快照缺席删除(`US-07`)、历史清理在物理删除前必要时登记(架构 `D1`)。 | Kafka value 的字段与类型、变更和删除的区分方式(`Q5`)、编码方式。 | +| `msg` | 单条航班变更通知;航班动态与删除处理完成后投递;发送失败自动重试,一直失败的记录保留可查并告警(`US-08`);同一 `FLID` 的变更保序,对外按至少一次投递(`CLM-3`,单分区)。删除通知的来源有三处:`FDEL` 删除(`US-06`)、日计划快照覆盖范围内缺席删除(`US-07`)、历史清理在物理删除前必要时登记(架构 `D1`)。 | Kafka value 的字段与类型、变更和删除的区分方式(`Q5`)、编码方式。 | | `schd` | 定时批量发送最新航班状态;两次 tick 之间积累的航班组成 `SCHD.FLTR` 数组 JSON,整批作为单条 record 发出(沿用旧系统,`Q1`);空字段不输出,字段与类型见 [XSD](../legacy/unisysaodbsis.xsd) 的 `FLTR`;没有变化不发;删除航班不进入本主题,由 `msg` 发一条删除通知;发送失败自动重试,对外按至少一次投递(`US-08`)。 | 消费方按数组格式解析的确认(`Q1`)。 | 旧系统线索(来源:旧项目用户故事「前端通知」「动态类(FLOP-*)处理」): @@ -59,10 +59,10 @@ AODB 经 CIIMS adapter 把 XML 报文写入 `CMINMSGS`,格式以架构指定 | 表 | 本系统的操作 | 需要对接方提供的物理契约 | |---|---|---| -| `CMINMSGS` | 按信箱编号升序、分批读取未处理的报文,扫描与回写用同一处理时间列(`CMINMSGS_DATE_PROCESSED`,`Q8`);兼容 HTTP 入口写入 XML 原文;处理完成后写入处理完成时刻,只填空值、不覆盖已有值;写回失败由后台任务重试,一直写不上的记录保留在案并告警(`US-01`、`US-02`、`US-10`)。信箱编号即入库行号,单调递增、不复用、不回退(`Q7`)。 | 表 DDL、信箱编号与报文原文字段、处理时间列的类型与可空性及写入样例(处理标记即该处理时间列,见 [specification.md](../specification.md)「术语」的处理标记;回填只填空值)、写入必需列、原文保留期和索引。 | +| `CMINMSGS` | 按信箱编号升序、分批读取未处理的报文,扫描与回写用同一处理时间列(`CMINMSGS_DATE_PROCESSED`,`Q8`);兼容 HTTP 入口写入 XML 原文;处理完成后写入处理完成时刻,只填空值、不覆盖已有值;写回失败由后台任务重试,一直写不上的记录保留在案并告警(`US-01`、`US-02`、`US-10`)。信箱编号即入库行号,单调递增、不复用、不回退(`Q7`)。 | 表 DDL、信箱编号与报文原文字段、处理时间列的类型与可空性及写入样例(处理标记即该处理时间列,见 [specification.md](../specification.md)「术语」的处理标记;回填只填空值)、状态列 `CMINMSGS_STATUS` 的取值集与写权限(`Q8` 未确认)、写入必需列、原文保留期与清除协议(`C-1`)和索引。 | | `COUTMSGS` | 写入 `RQRD` 参考数据请求与 `RQFD` 日计划请求;CIIMS adapter 消费。交付承诺止于请求落信;写入结果不明时记录并告警,不直接重发(架构「主流程」)。 | 表 DDL、请求原文字段、写入必需列、编号生成方式、重复落信的识别规则。 | -共享 MySQL 归 CIIMS adapter 方所有;本系统不建表、不改表结构,也不写共享历史表。已回填且超过保留期的入站行由本系统清理(`C-1`)。外部表的物理字段必须以对接方提供的现行 DDL 与读写样例核对,不能由本文件推造。 +共享 MySQL 归 CIIMS adapter 方所有;本系统不建表、不改表结构,也不写共享历史表。入站行只写回处理标记,原文保留与清除由库方负责(`C-1`)。外部表的物理字段必须以对接方提供的现行 DDL 与读写样例核对,不能由本文件推造。 旧项目用户故事「数据表列清单」提供以下**旧系统实体映射列名**,不是现场 DDL、可空性或写权限的证明: @@ -80,7 +80,7 @@ AODB 经 CIIMS adapter 把 XML 报文写入 `CMINMSGS`,格式以架构指定 旧系统线索(来源:旧项目用户故事「Redis key 汇总」「术语与数据语义」「动态航班转历史」): - 投影是 hash `flightInfo`:field 为 `FLID`,value 为完整 `SCHD.FLTR` 对象的带类型 JSON,不设过期;Redis 里没有名为 `schd` 的 key,`schd` 只是 Kafka 主题。 -- 写入路径:日计划下载(`DNLD`/`RESP`)整体写入当天航班,单条变更(`ADFT`、`FLOP`)只写对应的一条,转历史时按 `FLID` 逐条移除。整体写入不删除本次映射中缺席的航班,与 `US-07` AC5 相反,新版按 `US-07` AC5 刷新。 +- 写入路径:日计划下载(`DNLD`/`RESP`)整体写入当天航班,单条变更(`ADFT`、`FLOP`)只写对应的一条,转历史时按 `FLID` 逐条移除。整体写入不删除本次映射中缺席的航班,与 `US-07` AC5 相反,新版按 `US-07` AC5 在覆盖范围内刷新。 - 写入前生成主航班的共享航班列表 `MAFL`(`G-MAFL`),是否为网页客户端所需仍未定(`Q6`);登机桥字段 `abdg` 本版不提供——旧系统拼它的数据源是机位与登机桥映射缓存,已列入需求「范围与非目标」不交付。 ### 自有 PostgreSQL:内部存储与 admin-api 只读 diff --git a/docs/implementation.md b/docs/implementation.md index 4115d47..8ebf6f2 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -79,7 +79,7 @@ msgexchange-v2 怎么处理报文:记录模型、状态机、事务边界、 写回延迟期间扫描量会涨,须观测积压([reference.md](reference.md) 指标)。 -信箱 ID 单调不复用(`INV-1`)。`POST /cminmsgs/send` 与 adapter 同路径(`C-7`)。单活动实例(`OPS-1`);多实例靠主键幂等,仍须单实例排他。 +信箱 ID 单调不复用(`INV-1`);较小编号晚提交时最坏只是被发现得晚(下轮扫描仍会读到),不会丢,但它不会排在已经处理完的较大编号之前。`POST /cminmsgs/send` 与 adapter 同路径(`C-7`)。单活动实例(`OPS-1`);多实例靠主键幂等,仍须单实例排他。 ## 5. 主泵调度与单条处理 @@ -189,7 +189,7 @@ LIMIT PARAM:msgx.pipeline.backfill-batch 1. 已成功 → 幂等,只追加留痕。 2. 整包校验失败 → `DEAD(PROTOCOL)`,不写半包(`INV-4`)。 -3. 分批写:跨运营日整包失败;快照缺席航班标删、发删除事件、删 Redis(`INV-7`)。每批同事务写变更 + 事件(`INV-3`)。 +3. 分批写:跨运营日整包失败;**覆盖范围内**快照缺席航班标删、发删除事件、删 Redis,范围外的不受影响(`INV-7`)。每批同事务写变更 + 事件(`INV-3`)。 4. 整包成功 → `SUCCEEDED` + 回填意图;留痕在事务外。 字段语义见「航班域」。`RESP` 须匹配开放请求,否则不更新(`G-RESP-GUARD`)。 @@ -266,14 +266,14 @@ PENDING → SENT → DONE `JobRunner` 周期跑写回扫描、历史清理、留痕清理;不挡主泵 FIFO。历史清理跳过处理中的航班(`US-14` AC4)。 -清除须终局证据(航班 `US-14`/`D1`;信箱 `C-1`)。证据不明 → 删 0 条。写回失败记录在信箱删前可查(`US-10` AC2)。 +清除须终局证据(航班 `US-14`/`D1`;共享信箱的清除属库方职责,见 `C-1`)。证据不明 → 删 0 条。写回失败记录在其覆盖的信箱行被清除前可查(`US-10` AC2)。 **逐对象**(保留期见 [reference.md](reference.md)) | 对象 | 终局判据 | 归档目标 | 清除证据 | 执行方 | 偏差 | |---|---|---|---|---|---| -| 共享信箱 `CMINMSGS` 原文 | 回填了结(`BACKFILL_AT` 非空)且超保留期(约 1 个月,`C-1`) | — | 回填已了结 + 超保留期;放弃行无 `BACKFILL_AT`,不删 | 我们 | — | -| `FLIGHT_SCHD` + 资源明细 | 判史规则 | 历史存储 | 历史写入确认 + 版本复查 | 我们 | — | +| 共享信箱 `CMINMSGS` 原文 | 写回完成(`BACKFILL_AT` 非空) | — | 待确认(`Q9`) | 库方 | 清除协议未确认(`C-1`) | +| `FLIGHT_SCHD` + 资源明细 | `US-14` AC2 的已结束条件 | 历史存储 | 历史写入确认 + 版本复查 | 我们 | — | | 航班历史存储 | 保留期 | — | — | 我们 | `G-FLIGHT-HIST-RETENTION` | | `SCHD_SNAP_LOG` | 保留期 | 无(本地可重建) | 无 | 我们 | — | | `MSG_EVENT` 已发送行 | `SENT` | 无 | 无 | 我们 | — | @@ -286,7 +286,7 @@ PENDING → SENT → DONE ## 10. 容量假设 -单机场、单实例;日消息千~万级;单条 ≤ 10⁴ 字节;延迟秒级可接受。不引入多实例/分布式锁/分区表。参数依据见 [reference.md](reference.md)(`CLM-6`)。 +单机场、单实例;日消息千~万级;单条报文按 CIIMS 支持的 10 MB 上限、不分片设计(`SIS:3.16`),读取、解码与回归样例都以该上限为准;延迟秒级可接受。不引入多实例/分布式锁/分区表。参数依据见 [reference.md](reference.md)(`CLM-6`)。 ## 11. 航班域:数据模型与合并 @@ -353,7 +353,7 @@ PG 是航班数据源(`INV-5`);Redis 从 PG 同步,处理完成前写入 ### 12.1 SCHD -整包校验通过后分批写入;快照缺席标删(`INV-7`)。未带字段清空(`C-6`)。成功航班推进 `STATE_VERSION` 并写 `schd`+`msg` 事件。重复由 `PROC_STATE` 控制;校验失败整包不写(`INV-4`)。 +整包校验通过后分批写入;**覆盖范围内**快照缺席标删,范围外的不受影响(`INV-7`)。未带字段清空(`C-6`)。成功航班推进 `STATE_VERSION` 并写 `schd`+`msg` 事件。重复由 `PROC_STATE` 控制;校验失败整包不写(`INV-4`)。 ### 12.2 动态运行事件(FLOP) @@ -395,7 +395,7 @@ PG 是航班数据源(`INV-5`);Redis 从 PG 同步,处理完成前写入 ### 12.3 删除与重建 -FDEL:`ACTIVE→DELETED`,写 tombstone。物理删除仅历史清理成功后(`US-14`、`D1`)。快照缺席也标删(`INV-7`)。 +FDEL:`ACTIVE→DELETED`,写 tombstone。物理删除仅历史清理成功后(`US-14`、`D1`)。覆盖范围内快照缺席也标删(`INV-7`)。 ADFT:Set-only(`US-04` AC2),未带字段不清。有 `SODT` 则算 `OPERATION_DAY`。 @@ -407,7 +407,7 @@ ADFT:Set-only(`US-04` AC2),未带字段不清。有 `SODT` 则算 `OPERA ### 12.5 生命周期 -运营日过去 ≠ 航班结束。历史清理:保留期 + 终态证据 → 先写 ES 再删;失败删 0 行(`D1`)。 +运营日过去 ≠ 航班结束。历史清理候选按 `US-14` AC2 的五类已结束条件选取;先写 ES 再删,失败删 0 行(`D1`)。当前配置的判据与窗口尚未对齐该验收,见 [reference.md](reference.md) 依据列标「与需求冲突」的四项。 ## 13. 静态参考数据 diff --git a/docs/requirements.md b/docs/requirements.md index 4bd0ec2..867f05c 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -90,7 +90,7 @@ ### US-07 导入日计划(DNLD / RESP) -**目标**:日计划是 AODB 当前时刻的完整航班列表:AODB 主动下发(DNLD)或本系统请求后应答(RESP),收到后分批同步本地数据;整包成功时本地航班当前态与快照一致——请求日计划就是主动与 AODB 全量同步一次。 +**目标**:日计划是 AODB 在某个时间范围内的完整航班列表:AODB 主动下发(DNLD)或本系统请求后应答(RESP),收到后分批同步本地数据;整包成功时本地航班当前态与快照一致——请求日计划就是主动与 AODB 全量同步一次。覆盖范围由报文自身给出:`DNLD` 覆盖下发时刻起的约 48 小时,`RESP` 覆盖请求的日期区间(`SIS:3.16`)。 | 报文 | 说明 | |---|---| @@ -99,11 +99,11 @@ **验收标准** -1. 报文整体校验(声明的航班数、航班标识等)通过才处理;校验失败整包拒绝,本地数据不变。 -2. 报文里的航班逐条写入或更新;快照里没有的航班,在本地标记已删除,并登记待发删除消息。 +1. 报文整体校验(声明的航班数、航班标识、覆盖范围等)通过才处理;校验失败整包拒绝,本地数据不变。 +2. 报文里的航班逐条写入或更新;**覆盖范围内**快照里没有的航班,在本地标记已删除,并登记待发删除消息。覆盖范围外的航班不受本报文影响:前一日延误航班不在 `DNLD` 窗口内,不因缺席被判为已删除。 3. 以 AODB 下发的数据为准:日计划里某航班没携带的字段,视为 AODB 已删除该值,本地同步清掉。 4. 航班量大,分批写入数据库,每批一个事务;处理失败不标记已处理,下轮整包重新处理。 -5. 按快照结果刷新 Redis:报文里的航班写入,缺席的航班移除。 +5. 按快照结果刷新 Redis:报文里的航班写入,**覆盖范围内**缺席的航班移除,覆盖范围外的投影保留。 ### US-08 通知网页客户端(Kafka) diff --git a/docs/specification.md b/docs/specification.md index a4d3817..6fbb5f8 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -41,7 +41,7 @@ ### 2.1 共享信箱(库方) -- **C-1** 删除已处理完毕的入站行(`CMINMSGS`):处理标记已写入,且超过保留期(可配置,默认约 1 个月)。未处理完或未写回处理时间的行不删。 +- **C-1** 本系统不删除入站行(`CMINMSGS`):处理完成后只写回处理标记,原文保留与清除由库方负责,保留期不早于该行的写回完成时刻。`(待确认 Q9)` - **C-2** 共享 MySQL 不改表结构;本系统只读写 `CMINMSGS` 与 `COUTMSGS`。 ### 2.2 上游(AODB / SIS) @@ -86,7 +86,7 @@ - **INV-5** 航班当前数据以自有 PG 为准。 - **INV-6** `FLID` 全局唯一。 -- **INV-7** 日计划:快照里没有的航班打删除标记、记删除事件、从 Redis 删掉;快照没带的字段本地清掉(`US-07` AC2/AC3)。 +- **INV-7** 日计划:**覆盖范围内**快照里没有的航班打删除标记、记删除事件、从 Redis 删掉;覆盖范围外的航班不受本报文影响;快照没带的字段本地清掉(`US-07` AC2/AC3)。 - **INV-8** 已打删除标记的航班必须从 Redis 删掉;删掉才算这条消息处理完成(`US-06` AC1)。 - **INV-9** 日计划可以分批写 PG,但整份 PG 写完且 Redis 按快照刷完才算完成;失败则全部重来(`US-07` AC4/AC5)。 @@ -100,7 +100,7 @@ | 编号 | 承诺 | 依赖 | 现在能否作出 | 限制或原因 | |---|---|---|---|---| | CLM-1 | 同一条消息重复处理不会重复生效 | `US-03` | 不能 | 各类报文细则未写完(`G-FLOP-IDEMPOTENT`) | -| CLM-2 | 按信箱编号从小到大处理 | `US-03` AC1 | 能 | — | +| CLM-2 | 按信箱编号从小到大处理 | `US-03` AC1 | 能 | 只对已发现的待处理消息成立:较小编号晚提交时,它排在已经处理完的较大编号之后(implementation.md「收报」) | | CLM-3 | 主题 `msg` 上,同一 `FLID` 内按发送顺序排列 | `US-08` AC2、`C-9` | 能 | `msg` 单分区;至少一次投递时可能重复(`D2`) | | CLM-4 | 出站请求写入 `COUTMSGS` | `C-4` | 能 | 只保证写入信箱,不保证 AODB 收到 | | CLM-5 | 消息在固定时间内处理完 | — | 不能 | 需求未定时限 | @@ -121,7 +121,7 @@ | Q6 | 待对方 | 网页客户端怎么读 Redis 快照 | 见 `C-11`;`MAFL` 是否提供未定 | | Q7 | 已定 | 信箱编号只增不减、不重用 | `INV-1`、`CLM-2`、`US-01` AC3 | | Q8 | 已定 | 入站处理时间列名 `CMINMSGS_DATE_PROCESSED` | 术语「处理标记」、`US-10` | -| Q9 | 已定 | 入站行删除条件与保留期 | `C-1` | +| Q9 | 待对方 | 入站行删除条件与保留期 | 本系统只写回处理标记、不删除;清除协议与保留期待库方确认(`C-1`) | | Q10 | 已定 | `SEQN` 重置与身份规则 | `C-3` | | Q11 | 已定 | 日计划没带字段是否删除 | `C-6` | | Q12 | 已定 | 主航班与共享航班删除联动 | `US-06` AC2 | @@ -180,7 +180,7 @@ | INV-4 | `US-07` AC1 | 校验失败后 PG 航班数据不变 | | INV-5 | 架构「数据归属与一致性」 | 航班数据只写入自有 PG | | INV-6 | implementation.md「数据模型」 | `FLID` 唯一 | -| INV-7 | `US-07` AC2/AC3 | 快照缺席航班标删并从 Redis 删;未带字段清空 | +| INV-7 | `US-07` AC2/AC3 | 覆盖范围内快照缺席航班标删并从 Redis 删,范围外不动;未带字段清空 | | INV-8 | `US-06` AC1 | 标删后从 Redis 删;失败下轮重做 | | INV-9 | `US-07` AC4/AC5 | 分批失败全部重来(`G-SCHD-SNAPSHOT` 做完前不可验);PG 整份写完后再刷 Redis | | INV-11 | `US-12` AC1/AC2 | 返回全部非共享航班且与 Redis 一致;Redis 故障返回错误 | diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ee26544..1dbfdcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -78,7 +78,7 @@ flyway: # 处理回填;出站写 COUTMSGS;不建表/schema,ACM2-12)。驱动/依赖与信箱适配层 # (CminmsgMailbox/OutboxMailbox)随 U05 批次引入。 mailbox: - processed-value: PROCESSED # 处理标记写入值(C-5/Q8:值集与写权限以库方契约为准) + processed-value: PROCESSED # 回填写入 CMINMSGS_STATUS 的取值(Q8:取值集与写权限以库方契约为准) shared-mysql: enabled: false url: ${MSGX_MAILBOX_URL}