Files
msgexchange-v2/README.md
T
windyboy 5b7938ac4b docs(acm2-74): 补齐 FLOP 逐类语义、静态参考数据与数据结构
自洽与精简:

- specification 补第四种状态词 [我们自证]、验证映射补 INV-14 两行、去 CLM-7/CLM-9 的进度语、补编号空缺说明
- architecture/requirements/implementation 去除逐字复述(领域决策三写句、时间常数排序、C-25/C-26、INV-12/21/22)与参数值重复
- README 与新文档对齐:收报谓词改 ID>W、删不存在的 reference/ 包与 lua/、删 msgx.phase 与 MSGX_REDIS_URI、设计权威口径改 docs/、进度段改指 Plane

内容补齐:

- 新增 implementation.md「动态运行事件(FLOP)」:按 SIS 3.19–3.43 的 25 类逐类映射与空标签语义(含 CNCL 空标签为撤销等),补 RMS→AODB 方向拒绝、ROUT 只保留 4 条、VIPP 忽略等约束;厘清 legacy 29 类与 SIS 25 类的差集
- 新增 implementation.md「静态参考数据」章:13 类参考数据与资源状态的 RTYPE/RKEY、list 与增量合并语义、删除只由 DEL 表达、SLST/REMT/RSTA 机位与登机桥映射
- §11.3 数据结构改为标量分组表与集合明细表(元素键、条数上限、SIS 锚点)
- specification 新增 G-FLOP-DIRECTION / G-FLOP-UNMAPPED / G-REF-DATA;Q8 收窄为真实报文分布与 admin-api 清单
2026-09-14 07:34:17 +08:00

144 lines
10 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(机场上游报文处理中间件)
**系统角色**:消费 CIIMS/AODB 等上游经共享 MySQL 信箱(`CMINMSGS`)投递的 XML 报文,
解析处理后维护自有 PostgreSQL 航班当前态并向 Kafka / 出站信箱投递——**中间件**,非报文源系统。
现行设计依据是 [设计文档入口](docs/README.md) 的六份文档;早期方案 ACMA-8 / ACMA-6 只作历史记录,
不再作为设计或实现依据(自有 PostgreSQL 维护内部状态,共享 MySQL 仅作信箱边界)。
本仓库独立于 legacy `msgexchange-api`Java 8 / Spring Boot 1.5 / Maven)——
过渡期两套系统并存(影子对拍→切流→旧仓库冻结),legacy 维护不受本仓库影响。
> **JDK 口径实测修正**Micronaut 5.1 系构件要求 **JVM 25+**`./gradlew :dependencies` 实测
> core 系解析 **5.1.13**platform BOM **5.1.3**classpath 混用);计划原定 JDK 21 不可行;
> 工程已按 **JDK 25** 配置(工具链约束见 `AGENTS.md`)。
## 系统边界
| 方向 | 机制 | 说明 |
|---|---|---|
| **入站(主路径)** | JDBC 轮询共享 `CMINMSGS` | 上游经 CIIMS 等**外部系统**写信箱;本系统按轮询间隔读取水位之后的记录(`ID > W`,**不以处理标记为谓词**)→ 自有 PG 入队(`InboxPoller` |
| **入站(compat** | HTTP `POST /cminmsgs/send` | 手工注入/影子对拍;写信箱 + PG 入队,**非**生产主拓扑 |
| **处理** | 主泵 FIFO 管道 | 解码 → identity → Handler 决策 → PostgreSQL 航班当前态 |
| **出站** | Kafka + `COUTMSGS` | 向下游推送 msg/schd;请求类报文写出站信箱 |
与 SIS / legacy 一致:本系统**不**替代 CIIMS 落信,**不**生成原始 AODB 业务报文。
## 包结构(与 [architecture.md](docs/architecture.md)「模块职责」一致)
| 包 | 职责 |
|---|---|
| `ingress/` | 轮询共享信箱并持久化入队、兼容 HTTP 写入;不解析业务报文 |
| `processing/` | FIFO 调度、业务身份绑定与去重、领域决策与落库 |
| `delivery/` | 按目标保序投递、`schd` 聚合与失败重试 |
| `jobs/` | 回填补偿扫描、航班历史清理与留痕保留期清理 |
| `codec/` | SIS XML 解码(禁 DTD/外部实体),区分非法报文与可修复的解码失败 |
| `domain/` | 领域状态、事件与决策模型 |
| `config/` | 运行参数(`msgx.*` |
| `infra/` | 仓储(JDBC/stub)、外部适配器、重试、健康与指标 |
## 资源
- `docs/legacy/SIS_AODB_RMS-V0.1.md` + `docs/legacy/unisysaodbsis.xsd`**消息结构唯一事实源**
wire 契约冻结,自 legacy 仓库复制以自包含;codec 实装依据,ACM2-2/ACM2-3)。
- `src/main/resources/db/migration/V1__flight_state_baseline.sql`**自有 PostgreSQL**(唯一自有库)的航班状态与处理管道表结构;
共享 MySQLCMINMSGS/COUTMSGS)仅信箱 DML,不建表。
- `application.yml`:口令全部环境变量外置(零入库);`datasources.default`=自有 PG(默认关闭),
`mailbox.shared-mysql`=共享信箱;运行参数默认值一律以 [reference.md](docs/reference.md) 参数表为准。
## 实现进度
进度、缺口处置与排期在 Plane(ACM2);设计口径、偏差与可声明性见 [docs/specification.md](docs/specification.md)。本 README 不记录进度。
## 数据库初始化(ACM2-12 口径)
**自有 PostgreSQL**(唯一自有库):Flyway 执行 `src/main/resources/db/migration/V1__flight_state_baseline.sql`,建立
航班当前态、明细表、处理终态与 outbox 等表(PG 方言)。这是**单基线**:原 V2–V10 的净结构已
合并其中,全新库直接执行即可,无 legacy 前置。已按旧链(V1–V10)迁移过的库版本链与校验和都
对不上,必须重建 schema 或删除数据卷后重跑,禁止手工 `repair` 或改写 `flyway_schema_history`
**共享 MySQLcdairport,他人系统库)**:本系统**不建表/schema**,仅信箱 DML——上游外部写
`CMINMSGS`;本系统 JDBC 轮询读 + 处理回填;出站写 `COUTMSGS`(他人读取发送);表结构与
保留策略归库方管理。部署前需确认共享库 CMINMSGS 已存在(他人系统提供);本仓库不声明其 schema。
- **事务模型**:与共享库交互均为外部副作用(ACM2-12)——主路径=上游外部写信箱 →
JDBC 轮询发现新信 → 自有 PG 建 PENDING 入队(失败重扫补建);HTTP `/cminmsgs/send`
为 compat 写路径;处理成功回填 DATE_PROCESSED/STATUS 为最终一致。
- **航班状态**:写入自有 PostgreSQL;完整规则见 [implementation.md](docs/implementation.md)「航班域」。
- 影子对拍:自有 PG 开独立 schema;共享信箱为单信箱无法双写,影子输入=只读水位/回放口径。
## 本地开发依赖中间件栈(Podman / Docker ComposeACM2-13
仓库根目录提供兼容 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)。
- **Kafka**`apache/kafka:3.8.0` KRaft 单节点,端口 9092):listener `PLAINTEXT://localhost:9092``default.replication.factor=1`,已预配幂等生产者与 acks=all 所需的单节点参数。
### 快速启动
```bash
# 1. 复制环境变量示例(可按需修改口令与端口)
cp .env.example .env
# 2. 启动开发依赖栈(支持 docker compose 或 podman compose
docker compose up -d
# 3. 检查各服务健康状态(均为 healthy)
docker compose ps
```
### 环境变量与应用映射
| 环境变量 | 说明 | 示例默认值 | 应用配置映射(application.yml |
|---|---|---|---|
| `MSGX_MAILBOX_URL` | 共享信箱 MySQL JDBC URL | `jdbc:mysql://localhost:3306/cdairport?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4` | `mailbox.shared-mysql.url` |
| `MSGX_MAILBOX_USER` | 共享信箱 MySQL 用户名 | `msgx_dev` | `mailbox.shared-mysql.username` |
| `MSGX_MAILBOX_PASSWORD` | 共享信箱 MySQL 密码 | `msgx_dev_pass` | `mailbox.shared-mysql.password` |
| `MSGX_PG_URL` | 自有 PostgreSQL JDBC URL | `jdbc:postgresql://localhost:5432/msgx` | `datasources.default.url` |
| `MSGX_PG_USER` | 自有 PostgreSQL 用户名 | `msgx_dev` | `datasources.default.username` |
| `MSGX_PG_PASSWORD` | 自有 PostgreSQL 密码 | `msgx_dev_pass` | `datasources.default.password` |
| `MSGX_KAFKA_SERVERS` | Kafka bootstrap brokers | `localhost:9092` | `kafka.bootstrap.servers` |
| `MSGX_KAFKA_ACKS` | 生产确认级别 | `all` | `kafka.producers.default.acks` |
| `MSGX_KAFKA_IDEMPOTENCE` | 幂等生产者开关 | `true` | `kafka.producers.default.enable-idempotence` |
| `MSGX_KAFKA_MAX_IN_FLIGHT` | 单连接最大在途请求数 | `1` | `kafka.producers.default.max-in-flight-requests-per-connection` |
### 切流前 Kafka Broker 版本确认
生产契约以 [requirements.md](docs/requirements.md) `US-07``D3` 为准(三项生产者约束的取值见 [reference.md](docs/reference.md) 参数表),**严禁非幂等降级**。README 不提供生产降级环境变量组合。
旧系统 `msgexchange-api` 底层依赖 `kafka-clients:0.10.1.1`;现网 Broker 确切版本须在切流前实测确认:
1. **版本探测**:切流前通过本栈工具探测目标集群 API 能力:
```bash
docker exec msgx-dev-kafka /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server <TARGET_IP>:9092
```
2. **门禁判定**:若输出中 `InitProducerId(22)` 为 **可用** → 保持 `D3` 的高可靠默认。
3. **阻塞切流**:若 `InitProducerId(22)` 为 **UNSUPPORTED**Broker &lt; 0.11)→ **阻塞切流**,须升级 Broker 或经架构豁免(ACM2-1 基础设施升级门禁);降级参数仅可作为经批准的 runbook 附录,**不得**作为生产验收口径与 README 默认配置并存。
## 构建
```bash
./gradlew build # 需网络拉取依赖;内网环境见 gradle.properties 注释
./gradlew test # 纯逻辑单测(identity / schd 聚合 / 配置绑定 / 管道语义)
MICRONAUT_ENVIRONMENTS=dev ./gradlew run # dev stub 冒烟:内存 stub,无需 DB/Kafka/Eureka
```
> 注解处理:Kotlin 侧经 KSP`kotlin-ksp` + `micronaut-inject-kotlin`)生成 Micronaut
> BeanDefinition;若 build 产物缺少 `*$Definition` 类,先检查 KSP 是否生效。
> dev/shadow 冒烟装配:`msgx.stubs=true`(内存仓储/适配层,见 infra/stub+
> `msgx.pipeline.autostart=true`PipelineLifecycle 拉起专用线程);生产默认两者关闭。
## 文档
`docs/` 是唯一设计依据;从 [设计文档入口](docs/README.md) 开始阅读(职责、事实归属、ID 语法与引用纪律都在那里)。顶层 6 个文件:
- [architecture.md](docs/architecture.md):系统边界、模块职责、存储归属、总体流程与 `D1``D4` 决策。
- [requirements.md](docs/requirements.md):阶段范围与非目标、`US-xx` / `OPS-x` 验收目标、需求覆盖与依赖。
- [specification.md](docs/specification.md):术语、契约 `C-x`、前提 `PRE-x`、不变量 `INV-x`、声明边界 `CLM-x`、待确认 `Q`、已知偏差 `G`、验证映射。
- [implementation.md](docs/implementation.md):管道机制与航班域——数据模型、状态机、事务、投递、作业与恢复,航班权威模型与合并语义。
- [reference.md](docs/reference.md):参数 `PARAM:<key>`、指标与健康、模块与代码入口、错误分类。
- [legacy/](docs/legacy/):外部协议与旧系统基线(`SIS_AODB_RMS-V0.1.md` 为消息结构唯一事实源、`unisysaodbsis.xsd`、legacy 行为对拍基线、历史决策记录)。
实现进度与缺口处置在 Plane(ACM2)。运行规程在上线/切流前另立 `docs/runbooks/`,不进入顶层。