diff --git a/docs/README.md b/docs/README.md index f9b95cb..cd00a1c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,7 +34,7 @@ | 退避 / `claim-batch` / 回填期限等取值 | reference.md「参数」 | 其余文档只引 `PARAM:` | | 消费权排他、ID 不复位、报文不可变、时钟、单实例 | specification.md「前提」 | 其他文档只引 `PRE-x` | | 航班身份、合并语义、`STATE_VERSION`、`OPERATION_DAY` | implementation.md「航班域」 | 其余文档只引域规则与 `INV-x` | -| 航班动态逐类语义与空标签规则(FLOP) | implementation.md「动态运行事件」 | specification.md 记 `Q8` 与 `G-*`;requirements.md 写验收口径 | +| 航班动态逐类语义与空标签规则(FLOP) | implementation.md「动态运行事件」 | specification.md 记 `Q3` 与 `G-*`;requirements.md 写验收口径 | | SIS 消息中的参考数据类别、结构与资源状态 | implementation.md「静态参考数据」 | requirements.md 写取数与刷新验收;admin-api 只从处理后的业务数据库读取 | | 对外术语(落信 / 入站 / 库方 / 处理标记) | specification.md「术语」 | — | | 管道内部术语(队头 / 终态 / 待标记 / 回填意图) | implementation.md「术语与持久化记录」 | — | diff --git a/docs/architecture.md b/docs/architecture.md index b052e04..d21843a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -16,7 +16,7 @@ msgexchange-v2 是 OMMS H5 查询系统的消息网关,替换旧版 `msgexchan - **权威**:航班当前态的权威是自有 PostgreSQL(`FLIGHT_SCHD`、资源明细表、`FLIGHT_ROUTE_POINT`);信箱、Redis、Kafka、展示视图都不是(`INV-11b`)。 - **航班历史**:已结束航班先写入 Elasticsearch 历史库,成功后才从实时数据删除(`US-14`;`D1`)。 -测试环境用 PostgreSQL;生产环境用 PostgreSQL 还是 Oracle 11g 尚未确定,Oracle 适配验证通过前不作支持承诺(生产库选型见 `Q1`)。 +测试环境用 PostgreSQL;生产环境用 PostgreSQL 还是 Oracle 11g 尚未确定,Oracle 适配验证通过前不作支持承诺(生产库选型见 `Q14`)。 ## 2. 总体架构 diff --git a/docs/contracts/interface-contract.md b/docs/contracts/interface-contract.md index 16b0ed9..4e5cdcb 100644 --- a/docs/contracts/interface-contract.md +++ b/docs/contracts/interface-contract.md @@ -11,8 +11,8 @@ | 接口 | 请求契约 | 成功响应契约 | 失败契约 | 尚需确定 | |---|---|---|---|---| | `POST /cminmsgs/send` | 请求体是 XML 原文;接受 `text/xml`、`application/xml`、`text/plain`,默认 UTF-8;仅限内网,网络层限制来源。 | 报文写入 `CMINMSGS` 后返回信箱编号;写入的报文与上游投递走同一条处理路径、效果一致;该响应只证明已落信,不证明业务处理或下游投递(`US-02`)。 | 空报文、超大小上限、非法 XML 不落信并返回错误;写信失败不返回编号;XML 解析禁用外部实体和外部资源访问。 | 大小上限、请求编码与 `Content-Type` 的精确处理规则、HTTP 状态码、成功/失败响应体字段及样例。 | -| `POST /schd/sync` | 触发一次 `RQFD` 日计划请求;请求字段尚未定义,登记与落信规则见「在途与作废」。 | 响应内容尚未定义;无论表示登记还是落信,都不代表 AODB 已收到。 | 错误响应尚未定义。 | 请求字段与时间格式、成功响应表示已登记还是已落信(`Q17`)、状态码、响应字段及样例。 | -| `GET /all/flights` | 无已定义的请求字段;从 Redis 投影读取当前全部动态航班,不含共享航班,与网页客户端同源(`US-12`)。 | 返回查询到的全部航班,不分页;JSON 由消息文档中的 XML 结构转换而来(`Q24`)。 | Redis 异常时返回错误,不能返回空列表伪装成功。 | 状态码和错误响应样例;外层包装是否沿用旧 `ResponseDto`。 | +| `POST /schd/sync` | 触发一次 `RQFD` 日计划请求;请求字段尚未定义,登记与落信规则见「在途与作废」。 | 响应内容尚未定义;无论表示登记还是落信,都不代表 AODB 已收到。 | 错误响应尚未定义。 | 请求字段与时间格式、成功响应表示已登记还是已落信(`Q16`)、状态码、响应字段及样例。 | +| `GET /all/flights` | 无已定义的请求字段;从 Redis 投影读取当前全部动态航班,不含共享航班,与网页客户端同源(`US-12`)。 | 返回查询到的全部航班,不分页;JSON 由消息文档中的 XML 结构转换而来(`Q21`)。 | Redis 异常时返回错误,不能返回空列表伪装成功。 | 状态码和错误响应样例;外层包装是否沿用旧 `ResponseDto`。 | 旧系统线索(来源:旧项目用户故事「HTTP 接口清单」「日计划请求」): @@ -43,8 +43,8 @@ AODB 经 CIIMS adapter 把 XML 报文写入 `CMINMSGS`,格式以架构指定 | 主题 | 已确定的消息语义 | 尚需确定 | |---|---|---| -| `msg` | 单条航班变更通知;航班动态与删除处理完成后投递;发送失败自动重试,一直失败的记录保留可查并告警(`US-08`);同一 `FLID` 的变更保序,对外按至少一次投递。删除通知的来源有三处:`FDEL` 删除(`US-06`)、日计划快照缺席删除(`US-07`)、历史清理在物理删除前必要时登记(架构 `D1`)。 | Kafka key、value 的字段与类型、变更和删除的区分方式、版本与去重标识(`Q19`;可用依据是航班当前态的版本规则,见 `FLIGHT_SCHD` 行)、编码方式、分区规则、消费者处理重复和乱序的规则。 | -| `schd` | 定时批量发送最新航班状态;发送失败自动重试;对外按至少一次投递。 | “批量”对应的 Kafka record 粒度、key/value 字段与类型、删除航班的表达方式、批次边界、编码方式、消费者去重规则。 | +| `msg` | 单条航班变更通知;航班动态与删除处理完成后投递;发送失败自动重试,一直失败的记录保留可查并告警(`US-08`);同一 `FLID` 的变更保序,对外按至少一次投递。删除通知的来源有三处:`FDEL` 删除(`US-06`)、日计划快照缺席删除(`US-07`)、历史清理在物理删除前必要时登记(架构 `D1`)。 | Kafka value 的字段与类型、变更和删除的区分方式、版本与去重标识(`Q5`;可用依据是航班当前态的版本规则,见 `FLIGHT_SCHD` 行)、编码方式、分区规则、消费者处理重复和乱序的规则。 | +| `schd` | 定时批量发送最新航班状态;发送失败自动重试;对外按至少一次投递。 | “批量”对应的 Kafka record 粒度、value 字段与类型、删除航班的表达方式、批次边界、编码方式、消费者去重规则。 | 旧系统线索(来源:旧项目用户故事「前端通知」「动态类(FLOP-*)处理」): @@ -78,9 +78,14 @@ AODB 经 CIIMS adapter 把 XML 报文写入 `CMINMSGS`,格式以架构指定 | 存储 | 承载内容 | 边界 | 尚需确定 | |---|---|---|---| -| Redis | 航班查询投影 | 只作查询,不是权威,也不存处理状态;只由本系统写入和移除,网页客户端与 `GET /all/flights` 读同一份,内容来自自有 PostgreSQL 的航班当前态;写投影成功、删除时移除成功,才算对应消息处理完成(架构「数据归属与一致性」;`US-05`、`US-06`)。 | key 与 value 结构及序列化方式、网页客户端读取约定(`Q20`)、每次处理后刷新哪些航班。 | +| Redis | 航班查询投影 | 只作查询,不是权威,也不存处理状态;只由本系统写入和移除,网页客户端与 `GET /all/flights` 读同一份,内容来自自有 PostgreSQL 的航班当前态;写投影成功、删除时移除成功,才算对应消息处理完成(架构「数据归属与一致性」;`US-05`、`US-06`)。 | 网页客户端读取约定(`Q6`)。 | -旧系统线索:投影是 Redis hash `flightInfo`,field 为 `FLID`、value 为 `SCHD.FLTR` 的带类型 JSON(旧项目用户故事「Redis key 汇总」「术语与数据语义」)。 +旧系统线索(来源:旧项目用户故事「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 刷新。 +- 写入前生成主航班的共享航班列表 `MAFL`(`G-MAFL`)并拼出登机桥字段 `abdg`,两者是否为网页客户端所需仍未定(`Q6`)。 +- 旧系统 Redis 另有两条机位基础数据缓存,都由本系统调用 admin-api 填充、过期 3600 秒:`orms_stand`(field 为机位代码,value 为 `OrmsStand` 对象的带类型 JSON);`orms_stand_airbridge`(field 为机位代码,value 为登机桥代码数组的 JSON 字符串,不是对象)。这两条是旧系统按计划机位拼 `abdg` 的数据来源,本版不交付(需求「范围与非目标」)。 ### 自有 PostgreSQL:内部存储与 admin-api 只读 @@ -135,7 +140,7 @@ AODB 经 CIIMS adapter 把 XML 报文写入 `CMINMSGS`,格式以架构指定 2. 运营航班显示界面的 `msg`、`schd` 消费样例和字段要求,特别是变更、删除、重复投递的处理方式。 3. CIIMS adapter 方提供的 `CMINMSGS`、`COUTMSGS` 现行 DDL、读写样例和写权限说明,核对旧系统实体映射列名,并确认信箱编号单调递增、不复用、不回退。 4. 13 类参考数据与资源状态的编号规则,以及自有 PostgreSQL 的迁移 DDL。 -5. Redis 投影的 key 与 value 结构、序列化方式及网页客户端读取约定。 +5. 网页客户端读取 Redis 投影的约定,含它需要哪些字段(`Q6`)。 6. AODB 应答与 `EROR` 样例,含请求与应答的对应字段、超时判定依据。 7. Elasticsearch 历史索引映射、文档样例、逐条或批量写入响应、索引保留期与容量上限,以及写入结果不明时的对账规则。 diff --git a/docs/legacy/flight-apis.md b/docs/legacy/flight-apis.md new file mode 100644 index 0000000..cf15597 --- /dev/null +++ b/docs/legacy/flight-apis.md @@ -0,0 +1,406 @@ +# 航班及相关接口说明 + +本文整理 admin-api 中与航班有关的接口:数据从哪来、路径与参数、返回字段、码表含义。 + +本服务是**只读数据层**。不生产航班动态,不保存实时航班。实时推送、保障流程、报文收发与解析落库由 AODB / 消息中间件负责。 + +判定数据源:Controller 注入的 DAO 在 `domain.secondary` 包 → **Oracle**;历史航班走 ES;字典走 MySQL。双数据源原理见 [datasource.md](datasource.md)。 + +--- + +## 1. 数据从哪来 + +| 能力 | 接口 | 数据源 | 不可用时 | +|---|---|---|---| +| 航班季度计划 | `/schedule/flightSchdSeasons`、`/schedule/flightSchdSeason/years` | **Oracle** `FIMS_FLIGHTSCHD_SEASON` / `FIMS_MIDAIRPORTS_SEASON` | 500 | +| 航班基础数据 | `/basicdata/sysFlightStatus` 等 4 个 | **Oracle** | 500 | +| 配套基础数据 | `/basicdata/sysAirlines` 等 | **Oracle** | 500 | +| 历史航班检索 | `POST /hitFlightData/list` | Elasticsearch 别名 `flight_hts` | 500 | +| 航班动态导出 | `POST /fltrs/toExcel` | 前端回传,不查库 | 返回 JSON 错误 | +| 航班相关字典 | `GET /dictionary/datadicItems/{groupCode}` | MySQL | 500 | + +这些接口都不读 `user` 头,可匿名访问,必须经网关暴露。 + +统一响应(Excel 导出除外): + +```json +{ "is_success": true, "err_code": 1, "err_msg": "成功", "body": {} } +``` + +成功 `err_code=1`。联调:`http://localhost:8080/doc.html`,标签为「历史航班数据」「航班季度计划」「航班动态」「基础数据」。 + +--- + +## 2. 从 Oracle 获取的接口 + +Secondary 数据源,当前业务只读。Oracle 不可用时本节全部 500。 + +### 2.1 航班季度计划 + +Controller:`schedule/FlightSchdSeasonController`。 + +#### `GET /schedule/flightSchdSeasons` + +按可选年份查询季度计划,经停站一并返回。 + +| 查询参数 | 格式 | 说明 | +|---|---|---| +| `startDate` | 年份,如 `2018` | 过滤 `START_DATE` 落在该年 `01-01 00:00:00 ~ 12-31 23:59:59`。不传则全量。 | + +`body` 为 `FimsFlightschdSeasonDto[]`: + +| 字段 | 含义 | +|---|---| +| `seasonflightId` | 季度计划航班 ID | +| `flightNumber` | 航班号,如 `3U8692` | +| `airlineId` / `subAirlineId` | 承运 / 二级承运航司 ID | +| `aircraftTypeCode` | 机型代码 | +| `arriOrDept` | `A` 到达 / `D` 出发 | +| `startAirport` / `endAirport` | 航线起点 / 终点(IATA) | +| `arrivalTime` / `departureTime` | `hhmm` | +| `startDate` / `endDate` | 计划有效起止日期 | +| `operationDays` | 运营日 `1234567`;非运营日用 `-`,如周三、五休息为 `12-4-67` | +| `flightTask` | 航班任务,见 [§5.1](#51-航班任务-flighttask) | +| `flightTypeCode` | 航班类别,见 [§5.2](#52-航班类别-flighttypecode) | +| `routeType` | `I` 国际 / `D` 国内 / `M` 混合 | +| `flyingDistance` / `flyingTime` | 距离(千米)/ 时间(分钟) | +| `internationalCode` | 航班国际代码 | +| `seasonName` | 季度名称,如 `2012XIAQIU` | +| `seasonRecId` | 季度定义表记录 ID | +| `remarks` | 备注 | +| `fimsMidairportsSeasons` | 经停站列表,按 `orderno` 升序 | + +经停站 `FimsMidairportsSeason`: + +| 字段 | 含义 | +|---|---| +| `midairportsRecId` | 经停记录 ID | +| `seasonflightId` | 所属季度计划航班 ID | +| `airportId` | 经停机场 ID | +| `arrivalTime` / `departureTime` | 本站到离 `hhmm` | +| `orderno` | 航段顺序 | + +表:`FIMS_FLIGHTSCHD_SEASON`(主)+ `FIMS_MIDAIRPORTS_SEASON`(`SEASONFLIGHT_ID` 关联,`FetchType.EAGER`)。 + +#### `GET /schedule/flightSchdSeason/years` + +返回季度计划中出现过的年份集合,原生 SQL 按 `START_DATE` 的年份降序。 + +`body` 示例:`["2026", "2025", "2024"]`。 + +--- + +### 2.2 航班基础数据 + +全部 `GET`、全量、无分页。Controller 直接注入 DAO,无 Service 层。 + +#### `GET /basicdata/sysFlightStatus` + +航班外部状态代码,对应历史航班 `EXSC` / `FTSS`。表 `SYS_FLIGHT_STATUS`。 + +| 字段 | 含义 | +|---|---| +| `sttc` | 状态代码,如 `EARR` | +| `abns` | 英文描述,如 `Estimated Arrive` | +| `stdc` | 中文描述,如 `预计到达` | +| `sttd` | 是否异常:`Y` / `N` | + +#### `GET /basicdata/sysFlightTypes` + +航班类型代码。表 `SYS_FLIGHT_TYPE`。 + +| 字段 | 含义 | +|---|---| +| `flightTypeCode` | 类型代码 | +| `flightTypeCaaCode` | CAA 代码 | +| `flightTypeName` / `flightTypeNameCn` | 描述 / 中文描述 | +| `cTag` | 是否商务航班 | +| `vipTag` | 是否 VIP 航班 | +| `operate` | `1` 使用 / `0` 删除 | + +#### `GET /basicdata/sysFlightAgents` + +航班代理单位,对应历史航班 `FHAG` / `MHAG`。表 `SYS_FLIGHTAGENT`。 + +| 字段 | 含义 | +|---|---| +| `flightAgentId` | 代理 ID | +| `flightAgentName` | 中文名称 | +| `oGId` | 机构标识 | + +#### `GET /basicdata/flmsFlightStatusDefinition` + +延误 / 异常状态定义,对应历史航班 `DELY.CODE`。表 `FIMS_FLIGHTSTATUS_DEFINITION`。 + +| 字段 | 含义 | +|---|---| +| `flifhtStatusDefRecId` | 记录 ID(字段名沿用历史拼写) | +| `flightStatus` | 明细状态,如气象延误、旅客延误 | +| `flightStatusType` | 类别,见下表 | +| `flightStatusDesc` | 描述 | +| `dcod` / `dcdn` | 延误代码 / 数字代号 | +| `ddes` / `ddsc` | 英文 / 中文延误描述 | +| `enableFlag` | `Enabled` / `Disabled` | +| `operate` | `1` 使用 / `0` 删除 | + +`flightStatusType`: + +| 值 | 含义 | +|---|---| +| `null` | 正常 | +| `DELY` | 延误 | +| `CNCL` | 取消 | +| `FDIV` | 备降 | +| `MERG` | 合并 | +| `GRTN` | 地返 | +| `OTHR` | 其他 | + +--- + +### 2.3 航班配套基础数据(同样 Oracle) + +历史航班 / 动态表上的航司、机场、机型、机位、登机口等,靠这些接口解码。全部 `GET`、全量、无分页。 + +| 接口 | Oracle 表 | 说明 | +|---|---|---| +| `/basicdata/sysAirlines` | `SYS_AIRLINE` | 航空公司 | +| `/basicdata/sysAirlineGroup` | `SYS_AIRLINEGROUP` | 航空集团 | +| `/basicdata/sysAirports` | `SYS_AIRPORT` | 机场 | +| `/basicdata/sysAirportGroups` | `SYS_AIRPORTGROUP` | 机场集团 | +| `/basicdata/sysCitys` | `SYS_CITY` | 城市 | +| `/basicdata/sysCountry` | `SYS_COUNTRY` | 国家 | +| `/basicdata/ormsTerminals` | `ORMS_TERMINAL` | 航站楼 | +| `/basicdata/ormsTerminalareas` | `ORMS_TERMINALAREA` | 航站楼区域 | +| `/basicdata/ormsStands` | `ORMS_STAND` | 机位 | +| `/basicdata/ormsStandTypes` | `ORMS_STANDTYPE` | 机位类型 | +| `/basicdata/ormsStands/{standCode}/airbridgeCode` | `ORMS_STAND_AIRBRIDGE` | 指定机位的廊桥号 | +| `/basicdata/ormsGates` | `ORMS_GATE` | 登机口 | +| `/basicdata/ormsChuts` | `ORMS_CHUT` | 行李滑槽 | +| `/basicdata/ormsCheckindesks` | `ORMS_CHECKINDESK` | 值机柜台 | +| `/basicdata/checkinGroups` | `ORMS_CHECKIN_GROUP` | 值机岛 | +| `/basicdata/ormsCarousels` | `ORMS_CAROUSEL` | 行李转盘 | +| `/basicdata/sysAircrafttypes` | `SYS_AIRCRAFTTYPE` | 机型 | +| `/basicdata/sysAircrafts` | `SYS_AIRCRAFT` | 机号 | +| `/basicdata/sysAircrafttypesGroup` | `SYS_AIRCRAFTTYPEGROUP` | 机型分组 | + +--- + +## 3. 不是 Oracle 的航班接口 + +### 3.1 历史航班检索 — Elasticsearch + +`POST /hitFlightData/list` + +路径是 `hit` 不是 `hist`。查 ES 别名 `flight_hts`(指向索引 `flight_hts2`),不查数据库。Controller:`history/HistoryFlightDataController`。 + +请求体 `HistoryFilghtConditionDto`: + +| 字段 | 格式 | 说明 | +|---|---|---| +| `hstFLightTime` | `yyyy-mm-dd` | 查哪一天;**不传则默认昨天** `00:00:00 ~ 23:59:59` | +| `startSODT` | `yyyy-mm-dd HH:mm` | 计划时间下界,可单独传 | +| `endSODT` | `yyyy-mm-dd HH:mm` | 计划时间上界,可单独传 | +| `MVIN` | `A` / `D` | `A` 到达,`D` 离港;不传则进出港都查 | + +查询逻辑: + +1. 先按 `hstFLightTime`(或昨天)做 `SODT` range。 +2. 若再传 `startSODT` / `endSODT`,再叠一条 `SODT` range(AND)。 +3. 时间经 `DateUtils.swichTimeToEn_ddMMMyyHHmm` 转成 ES 存的 `ddMMMyyHHmm` 再查。 +4. 按 `SODT` 升序,条数上限 `elasticsearch.maxSize`(各环境 10000)。 +5. 映射为 `SCHD.FLTR`,**丢掉共享航班**(`MAID != null`)。 + +请求示例: + +```json +{ + "hstFLightTime": "2026-09-16", + "MVIN": "A", + "startSODT": "2026-09-16 08:00", + "endSODT": "2026-09-16 12:00" +} +``` + +`body` 为 `SCHD.FLTR[]`,字段见 [§6](#6-历史航班-schdfltr-字段)。 + +查不到数据时核对:`flight_hts` 别名是否存在、当天是否已同步、`SODT` 是否为 `ddMMMyyHHmm`。索引与 mapping 需手工创建,脚本在 `src/main/resources/es/`。 + +### 3.2 航班动态导出 Excel — 前端回传 + +`POST /fltrs/toExcel` + +不查库。前端把当前页列定义和行数据回传,服务端按 `columns` 顺序用 Apache POI 拼 xlsx,直接写 `HttpServletResponse`。成功是文件流,失败才是 JSON。无条数上限,超大导出可能内存与超时。Controller:`fltrs/FltrController`。 + +```json +{ + "columns": [ + { "key": "FLNO", "name": "航班号" }, + { "key": "SODT", "name": "计划到达/出发" } + ], + "data": [ + { "FLNO": "3U8692", "SODT": "16SEP260820" } + ] +} +``` + +`key` 对应行对象字段名,`name` 是表头。工作表名:`航班动态`。 + +### 3.3 字典 — MySQL + +`GET /dictionary/datadicItems/{groupCode}` + +| groupCode | 用途 | 初始化情况 | +|---|---|---| +| `FLIGHT_TASK` | 季度计划 `flightTask` | 分组有,**无初始化项** | +| `FLIGHT_TYPE` | 季度计划 `flightTypeCode` | 分组有,**无初始化项** | +| `ROUTE_TYPE` | 航线类别 | 仅 `D` 国内、`I` 国际(没有 `M`) | + +`FLIGHT_TASK` / `FLIGHT_TYPE` 的码值以 Oracle 字段注释为准,见第 5 节。`ROUTE_TYPE` 在季度计划里还有 `M` 混合,字典初始化未包含。 + +返回字段:`dataitemCode`、`dataitemName`、`dataitemDesc`。 + +--- + +## 4. 接口总表 + +| 方法 | 路径 | 数据源 | 说明 | +|---|---|---|---| +| `GET` | `/schedule/flightSchdSeasons` | Oracle | 季度计划列表 | +| `GET` | `/schedule/flightSchdSeason/years` | Oracle | 季度计划年份 | +| `GET` | `/basicdata/sysFlightStatus` | Oracle | 外部状态码 | +| `GET` | `/basicdata/sysFlightTypes` | Oracle | 航班类型 | +| `GET` | `/basicdata/sysFlightAgents` | Oracle | 代理单位 | +| `GET` | `/basicdata/flmsFlightStatusDefinition` | Oracle | 延误/异常码 | +| `GET` | `/basicdata/sysAirlines` 等 | Oracle | 配套基础数据,见 [§2.3](#23-航班配套基础数据同样-oracle) | +| `POST` | `/hitFlightData/list` | Elasticsearch | 历史航班 | +| `POST` | `/fltrs/toExcel` | 无 | 导出 Excel | +| `GET` | `/dictionary/datadicItems/{groupCode}` | MySQL | 字典 | + +--- + +## 5. 码表 + +### 5.1 航班任务 `flightTask` + +来源:`FIMS_FLIGHTSCHD_SEASON.FLIGHT_TASK` 字段注释。 + +| 码 | 含义 | +|---|---| +| `S` | 正班 | +| `N` | 包机 | +| `E` | 急救 | +| `B` | 专机 | +| `G` | 通用 | +| `J` | 加班 | +| `M` | 军用 | +| `Q` | 补班 | +| `X` | 其他 | +| `A` | 计划外 | + +### 5.2 航班类别 `flightTypeCode` + +来源:`FIMS_FLIGHTSCHD_SEASON.FLIGHT_TYPE_CODE` 字段注释。 + +| 码 | 含义 | +|---|---| +| `P` | 客机 | +| `F` | 货机 | +| `B` | 专机 | +| `O` | 公务机 | +| `M` | 军机 | +| `X` | 其他 | + +### 5.3 进出港 / 航线类别 + +| 字段 | 码 | 含义 | +|---|---|---| +| `arriOrDept` / `MVIN` | `A` | 到达 | +| `arriOrDept` / `MVIN` | `D` | 离港 | +| `routeType` / `FLIN` | `D` | 国内 | +| `routeType` / `FLIN` | `I` | 国际 | +| `routeType` / `FLIN` | `M` | 混合 | +| `FLIN` | `R` | 地区(仅历史航班) | + +--- + +## 6. 历史航班 `SCHD.FLTR` 字段 + +完整释义:`src/main/resources/es/v0.0.1_20181213_hisPlaneDataDesc.json`。Java 模型:`entity/msg/SCHD.FLTR`(JAXB 生成,勿手改)。 + +### 身份与计划 + +| 码 | 含义 | 码 | 含义 | +|---|---|---|---| +| `FLID` | 航班 ID | `FLNO` | 航班号 | +| `ALCD` | 航司代码 | `ALSC` | 子公司代码 | +| `MVIN` | `A` 到达 / `D` 离港 | `SODT` | 计划时间 | +| `FLTY` | 航班类型 | `FLIN` | 航线类别 | +| `ACFT` | 机型 | `RENO` | 机号 / 尾号 | +| `TRML` | 航站楼 | `STND` | 当前机位 | +| `MAXP` | 最大载客数 | `PAXC` | 旅客总数 | + +### 时间与状态 + +| 码 | 含义 | 码 | 含义 | +|---|---|---|---| +| `ESTT` | 预计时间 | `ACTT` | 实际时间 | +| `PADT` | 前站起飞 | `NAAT` | 前站降落 | +| `FTSS` | 运营状态 | `EXSC` / `EXSR` | 外部状态码 / 备注 | +| `CNCL` | 取消时间 | `BOTM` | 登机开始 | +| `LACL` | 最后通知 | `FINT` | 最终时间 | +| `APPT` | 批准离港时间 | `EGSR` / `EGST` | 引擎发动请求 / 时间 | + +### 共享 / 衔接 + +| 码 | 含义 | +|---|---| +| `CSOP` / `CSFT` / `MAID` | 共享主航班承运人 / 航班号 / AODB ID(`MAID` 非空会被历史查询丢掉) | +| `TAOP` / `TAFL` / `TAID` | 后接飞承运人 / 航班号 / ID | + +### 嵌套资源(数组) + +| 码 | 内容 | +|---|---| +| `ROUT` / `ERUT` | 航线:`APCD` 机场、`SCAT`/`SCDT` 计划到离、`RTNO` 顺序 | +| `GTDT` | 登机门:`GATE`、计划/实际开关门 | +| `CKDT` | 值机柜台:`CHKC`、计划/实际开关 | +| `PSDT` | 计划机位:`PSST`、占用起止 | +| `CHDT` | 离港行李滑槽 | +| `CLDT` | 到港行李转盘:`BELT`、首末件行李 | +| `CHOT` | 轮挡:`CHID`=`OFF` 上 / `ON` 下 | +| `ABTM` | 靠桥/撤桥:`ABOP`=`A` 链接 / `B` 断开 | +| `DELY` | 延误:`CODE`、开始时间、时长 | +| `FDIV` / `FRET` | 转场/备降原因 | +| `VIPF` | VIP 明细 | +| `SRVT` | 服务明细 | + +### 前端派生列 + +UI 默认列(`adminapi_uisettings_default.userSettingCol`)里还有 ES 原文没有的字段,由前端从嵌套结构拆出: + +| 码 | 含义 | +|---|---| +| `FLDT` | 航班日期 | +| `ARSF` | 到港共享航班 | +| `DESF` | 离港共享航班 | +| `AOTM_A` / `AOTM_D` | 靠桥 / 撤桥时间 | +| `CHTM_ON` / `CHTM_OFF` | 上轮挡 / 下轮挡 | + +--- + +## 7. 职责边界与注意点 + +| 本服务做 | 本服务不做 | +|---|---| +| 季度计划只读(Oracle) | 日计划实时推送(告警码 `SCHD-DNLD` 由其它系统发) | +| 历史航班检索(ES) | 保障流程、报文收发落库 | +| 前端已有数据导出 Excel | 写航班、改机位/登机口 | + +注意: + +- 基础数据无分页,数据量增长后需改造。 +- 历史检索路径拼写为 `/hitFlightData/list`。 +- `startSODT`/`endSODT` 与 `hstFLightTime` 是 AND,不是替换。 +- 共享航班(`MAID != null`)在历史查询中被过滤。 +- Excel 导出无服务端上限。 +- `entity/msg` 约 130 个类由 XSD 经 JAXB 生成,报文结构变更须改 Schema 后重新生成。 diff --git a/docs/reference.md b/docs/reference.md index ee0c1f3..cfb922d 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -41,7 +41,7 @@ | `msgx.schd.flush-limit` | `500` | 假定 | 聚合批上限 | | `msgx.operation-day.zone` | `Asia/Shanghai` | 现役 | 运营日推导时区;配置值非法时启动失败,不使用代码字面量回退 | | `msgx.operation-day.cutoff-hour` | `0` | **假定(占位)** | 切日边界;待业务确认 | -| `msgx.identity.include-day-boundary` | `false` | 安全默认 | 身份是否加日期边界;影响去重语义,不能当调优项切换(`Q11`) | +| `msgx.identity.include-day-boundary` | `false` | 安全默认 | 身份是否加日期边界;影响去重语义,不能当调优项切换(`Q10`) | | `msgx.health.backlog-cache-ttl-ms` | `30000` | 假定 | 积压快照缓存窗口;`0` = 不缓存;`/health` 与 `/metrics` 共用同一快照 | | `msgx.history.history-store-enabled` | `false` | 安全默认 | 历史存储门控;关闭时历史清理删 0 条 | | `msgx.history.cancelled-hours` | `1` | 假定 | 历史清理的取消态判据窗口 | @@ -54,7 +54,7 @@ | 参数组 | 默认 | 依据 | 说明 | |---|---|---|---| -| `mailbox.processed-value` | `PROCESSED` | 契约(`C-5`/`Q7`) | 处理标记写入值;仅限库方认可值集 | +| `mailbox.processed-value` | `PROCESSED` | 契约(`C-5`/`Q8`) | 处理标记写入值;仅限库方认可值集 | | `mailbox.shared-mysql.enabled` | `false` | 安全默认 | 真实信箱接线门控 | | `mailbox.shared-mysql.connect-timeout-ms` | `3000` | 假定 | 有界外部调用;Connector/J 默认无限等待,必须显式;同组 `socket-timeout-ms=30000` | | `mailbox.shared-mysql.pool-connection-timeout-ms` | `5000` | 假定 | 池级连接超时;同组 `pool-validation-timeout-ms=3000` | @@ -82,7 +82,7 @@ | `msgx.pipeline.job.ticks.total` | 作业 tick 完成次数 | 不增长 → 作业停摆 | | `msgx.pipeline.job.failures.total` | 作业 tick 抛错次数 | 增长 → 扫描/历史作业异常 | | `msgx.pipeline.job.last_sweep_selected` | 上一轮回填扫描选中的待办条数(扫描积压) | 持续顶到批次上限 → 扫描吃不消 | -| `msgx.pipeline.codec.srvt_seen.total` | 入站记录中出现 `SRVT` 段的条数(`G-SRVT-VIPF`) | > 0 → 真实流量确有该段,按真实报文定案 `Q13` | +| `msgx.pipeline.codec.srvt_seen.total` | 入站记录中出现 `SRVT` 段的条数(`G-SRVT-VIPF`) | > 0 → 真实流量确有该段,按真实报文定案 `Q11` | | `msgx.pipeline.codec.vipf_seen.total` | 入站记录中出现 `VIPF` 段的条数(`G-SRVT-VIPF`) | 同上 | | `msgx.pipeline.processing.ignored.total` | 命中 `US-04` 忽略清单的报文条数 | 增长是正常流量;归零反而需确认配置是否丢失 | diff --git a/docs/requirements.md b/docs/requirements.md index 11f9ba9..99936bc 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -24,6 +24,14 @@ - 已结束的航班写入 Elasticsearch 历史库后从实时数据删除。 - 不生成航班/业务数据类报文,不替代 CIIMS/AODB,不提供 AODB 主数据编辑能力。 - 不调用 admin-api,不从 admin-api 拉取、补全或合并任何数据。 +- 不在 Redis 缓存机位基础数据与登机桥映射:旧系统的 `orms_stand`、`orms_stand_airbridge` 靠调用 admin-api 填充,本版不交付(`C-10`)。 + +**查询侧(admin-api)的数据面**:admin-api 是只读数据层,不生产航班动态,也不保存实时航班;它的季度计划与基础数据都从本系统的数据库读,其中季度计划的供数方待定(specification.md 的 `Q25`)。基础数据的数据集为: + +- 航班基础数据:外部状态码、航班类型、代理单位、延误异常定义。 +- 配套基础数据:航司、航空集团、机场、机场集团、城市、国家、航站楼、航站楼区域、机位、机位类型、机位廊桥、登机口、行李滑槽、值机柜台、值机岛、行李转盘、机型、机号、机型分组。 + +其余能力不由本系统提供:航班动态 Excel 导出、字典;历史航班检索读 Elasticsearch 别名 `flight_hts`,索引名与字段映射待定(specification.md 的 `Q23`)。接口清单见 [legacy/flight-apis.md](legacy/flight-apis.md)。 ## 2. 用户故事 @@ -155,6 +163,7 @@ 1. 从 Redis 读取,与网页客户端查询同源。 2. Redis 异常时报错,不返回空列表假装正常。 +3. 投影长期保留、不设过期时间,只在航班被删除或转入历史时移除。 ### US-13 同步静态参考数据 diff --git a/docs/specification.md b/docs/specification.md index 7f5a76c..8447380 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -42,21 +42,21 @@ ### 2.2 上游(AODB / SIS) - **C-3** 业务身份由 `SNDR`、`TYPE`、`STYP`、`SEQN` 四字段组合;`SEQN` 自增,极少重置(消息服务器重启),重置后不会与旧消息冲突。 -- **C-4** 出站请求写入 `COUTMSGS`;交付承诺止于落信。编码:`SNDR=OMMS`;`SEQN` 本系统自建序列;`DTTM` 北京时间 `YYYYMMDDHHMMSS`;`RQRD` 子类型以 SIS 为准共 14 类;`RQFD` 为 `STYP=NONE`,全量同步不带 `STDB`/`STDE` 等筛选(`Q25`)。 +- **C-4** 出站请求写入 `COUTMSGS`;交付承诺止于落信。编码:`SNDR=OMMS`;`SEQN` 本系统自建序列;`DTTM` 北京时间 `YYYYMMDDHHMMSS`;`RQRD` 子类型以 SIS 为准共 14 类;`RQFD` 为 `STYP=NONE`,全量同步不带 `STDB`/`STDE` 等筛选(`Q13`)。 - **C-5** 航班删除为标记删除,主航班与共享航班各自独立标记。 - **C-6** 日计划快照里没有携带的字段视为 AODB 已删除该值,本地同步清除(`US-07` AC3)。 ### 2.3 HTTP 入口 -- **C-7** `POST /cminmsgs/send`:把 XML 写进入站信箱,与 adapter 投递走同一套处理。成功返回消息编号(仅表示已入库、未处理);失败不返回编号。支持 `text/xml`、`application/xml`、`text/plain`(UTF-8);空、超长、格式错的不写;解析不拉外部资源。内网,访问由网络配置控制。仅内部联调;长度上限与失败响应实现时自定(`Q3`)。 +- **C-7** `POST /cminmsgs/send`:把 XML 写进入站信箱,与 adapter 投递走同一套处理。成功返回消息编号(仅表示已入库、未处理);失败不返回编号。支持 `text/xml`、`application/xml`、`text/plain`(UTF-8);空、超长、格式错的不写;解析不拉外部资源。内网,访问由网络配置控制。仅内部联调;长度上限与失败响应实现时自定(`Q15`)。 - **C-8** `POST /schd/sync`:向出站表写入一条日计划请求。 - 待确认:请求参数、HTTP 响应(`Q17`)。 + 待确认:请求参数、HTTP 响应(`Q16`)。 ### 2.4 下游(admin-api、网页客户端与运营航班显示界面) -- **C-9** 航班变更发到 Kafka 主题 `msg`(单条)和 `schd`(批量)。同一条可能发多次。 +- **C-9** 航班变更发到 Kafka 主题 `msg`(单条)和 `schd`(批量);`schd` 每条为运营航班 JSON;不设消息键。同一条可能发多次。 - **C-10** 静态参考数据写入本系统数据库,供 admin-api 只读;本系统不调用 admin-api。 -- **C-11** 航班投影写入 Redis,供读取全体动态航班;`GET /all/flights` 与网页客户端读同一份;返回 JSON 由消息文档中的 XML 结构转换而来(`Q20`、`Q24`)。 +- **C-11** 航班投影写入 Redis,供读取全体动态航班;`GET /all/flights` 与网页客户端读同一份;返回 JSON 由消息文档中的 XML 结构转换而来(`Q6`、`Q21`)。 ## 3. 前提 @@ -104,7 +104,14 @@ ### 6.1 待对方确认 -(无) +| 编号 | 事项 | 当前假定 | 影响 | +|---|---|---|---| +| Q1 | `schd` 的 value 字段与类型、删除航班的表达方式、批次边界、消费者去重规则 | 每条 record 为一条运营航班 JSON(`C-9`);批次边界按定时窗口 | 消费方读取契约无法定稿 | +| Q2 | 请求与应答按时间匹配时的时钟偏斜容忍判据 | 比较前统一时区与单位(implementation.md「上游请求与静态数据」) | 容忍判据未定前,降级匹配不得描述为精确关联 | +| Q3 | 现场会发但 SIS 未定义的子类型(靠桥、延误等)的报文形态与逐类终态 | 按现有处理逻辑延续,不得因 SIS 未记载就丢掉(`US-05` AC1) | 逐类终态与幂等规则未定(`G-FLOP-SEMANTICS`) | +| Q4 | 上游重发时是否可能改发正文 | 报文不可变,绑定身份后不比对内容(implementation.md「消息、身份与决策」) | 改发正文的重发会被判为重复并跳过 | +| Q5 | `msg` 的版本与去重标识是否直接采用航班当前态的版本号 | 可用依据是航班当前态的版本规则(implementation.md「航班域:权威模型与合并写入语义」) | 消费方去重规则未定(与 `Q1` 衔接) | +| Q6 | 网页客户端读取 Redis 投影的约定 | 沿用旧系统的 hash `flightInfo`:field 为 `FLID`,value 为完整航班对象的带类型 JSON,不设过期;写入与移除时机见 `INV-7`、`INV-8`、`INV-10`;派生字段 `MAFL`、`abdg` 是否随投影提供仍未定;只作查询、不是权威;与 `GET /all/flights` 同一份(`C-11`;接口契约「Redis:航班查询投影」) | 消费方读取契约无法定稿 | 答复就地更新结论,并按 [README.md](README.md)「维护清单」落到对应条款。 @@ -112,17 +119,13 @@ | 编号 | 事项 | 结论 | |---|---|---| -| Q2 | 信箱编号的单调、不复用、不回退 | 已定案:编号即入库行号,单调递增、不复用、不回退;按编号升序处理即按到达顺序(`US-01` AC3、`CLM-2`) | -| Q4 | `schd` 载荷 | 已定案:`schd` 每条为运营航班 JSON(`C-9`、`US-08`) | -| Q7 | 入站处理时间列 | 已定案:与旧系统相同,列名为 `CMINMSGS_DATE_PROCESSED`;空为未处理,回填写入完成时刻(`US-10`) | -| Q8 | 现场有、文档没有的报文 | 已定案:仍须想办法处理,不得因 SIS 未记载就丢掉(`US-05` AC1);具体形态与落库规则随对拍补齐 | +| Q7 | 信箱编号的单调、不复用、不回退 | 已定案:编号即入库行号,单调递增、不复用、不回退;按编号升序处理即按到达顺序(`US-01` AC3、`CLM-2`) | +| Q8 | 入站处理时间列 | 已定案:与旧系统相同,列名为 `CMINMSGS_DATE_PROCESSED`;空为未处理,回填写入完成时刻(`US-10`) | | Q9 | 入站信箱行(MySQL `CMINMSGS`)清除 | 已定案:本系统回填后自清(`C-1`);保留期可配置,按约 1 个月 | -| Q11 | 上游 `SEQN` 的重置周期与身份是否加日期边界 | 已定案:`SEQN` 自增,极少重置,重置后不与旧消息冲突,不加日期边界(`C-3`) | -| Q13 | 日计划未携带字段的删除语义 | 见 `C-6` | -| Q14 | 主/共享删除顺序 | 已定案:标记删除,各自独立(`C-5`) | -| Q20 | Redis 投影用途 | 已定案:供读取全体动态航班;与 `GET /all/flights`、网页客户端同一份(`C-11`、`US-12`) | -| Q24 | `GET /all/flights` 返回体结构 | 已定案:JSON 由消息文档中的 XML 结构转换而来;读 Redis、返回全体动态航班、不分页(`C-11`、`US-12`) | -| Q25 | `RQRD` / `RQFD` 编码字段 | 已定案:`SNDR=OMMS`;`SEQN` 本系统自建序列;`DTTM` 为北京时间 `YYYYMMDDHHMMSS`(SIS META);`RQRD` 子类型以 SIS 为准共 14 类(含 `RSTA`,其可选 `RTYP`);`RQFD` 的 `STYP=NONE`,`STDB`/`STDE` 等筛选可选,全量同步不带筛选(SIS:无参数则返回当天全部,对齐 `US-07`)(`C-4`) | +| Q10 | 上游 `SEQN` 的重置周期与身份是否加日期边界 | 已定案:`SEQN` 自增,极少重置,重置后不与旧消息冲突,不加日期边界(`C-3`) | +| Q11 | 日计划未携带字段的删除语义 | 见 `C-6` | +| Q12 | 主/共享删除顺序 | 已定案:标记删除,各自独立(`C-5`) | +| Q13 | `RQRD` / `RQFD` 编码字段 | 已定案:`SNDR=OMMS`;`SEQN` 本系统自建序列;`DTTM` 为北京时间 `YYYYMMDDHHMMSS`(SIS META);`RQRD` 子类型以 SIS 为准共 14 类(含 `RSTA`,其可选 `RTYP`);`RQFD` 的 `STYP=NONE`,`STDB`/`STDE` 等筛选可选,全量同步不带筛选(SIS:无参数则返回当天全部,对齐 `US-07`)(`C-4`) | ### 6.3 本系统与需求方待决 @@ -130,16 +133,18 @@ | 编号 | 事项 | 当前假定 | 影响 | |---|---|---|---| -| Q1 | 生产库选型 | 自有 PG 是唯一权威;生产环境用 PostgreSQL 还是 Oracle 11g 不能从三份依据确定,Oracle 适配验证通过前不作支持承诺 | 生产部署验收 | -| Q3 | `POST /cminmsgs/send` 的长度上限与失败响应 | 仅内部联调、无外部引用;成功返回编号等行为见 `C-7`;上限与失败格式现阶段不定,实现时在代码里自定 | 不阻塞对外契约 | -| Q17 | `POST /schd/sync` 的请求字段与时间格式、成功响应表示已登记还是已落信、状态码与错误响应 | 交付承诺止于落信(`C-4`);旧系统线索为 `{startDate, endDate}` 与 12 小时制时间(接口契约「HTTP」) | 响应契约无法定稿(`C-8`) | -| Q18 | 人工发起 `RQRD` 的方式 | `US-09` 要求人工发起,HTTP 接口清单没有对应入口 | 参考数据请求无法人工触发 | -| Q21 | 回退时在途消息(已提交业务变更、未到处理完成)的处置 | 回填了结后切换(`OPS-4`);在途消息无跨系统幂等保障 | 回退演练的验收口径(`OPS-4`) | -| Q22 | 是否在自有 PG 留存入站原文副本,及原文提前清除时已登记消息的处置 | 不留存,原文只从信箱读取 | 提前清除的消息不可恢复,处置未定 | -| Q23 | 日计划中运营日冲突的处置 | 未定 | 冲突场景无法验收 | -| Q26 | `REF_MASTER` 的物理列、唯一键、空值存储与写入后可见时点 | 记录用类别码加识别标签识别(接口契约「静态参考数据类别与编号来源」) | admin-api 读取契约无法定稿(`C-10`) | -| Q27 | Elasticsearch 历史索引、文档 ID、字段映射、成功判据、保留期与容量上限、写入结果不明的对账与幂等策略 | 历史写入确认成功才删实时数据(`D1`、`US-14` AC3) | 历史链路无法验收(`US-14`;`G-FLIGHT-HIST-RETENTION`) | -| Q28 | `REQ_TRACK` 已结案记录的保留期取值 | 到期清理没有可依据的窗口(`G-REQ-TRACK-RETENTION`) | 请求历史清理无法实现(`US-09`) | +| Q14 | 生产库选型 | 自有 PG 是唯一权威;生产环境用 PostgreSQL 还是 Oracle 11g 不能从三份依据确定,Oracle 适配验证通过前不作支持承诺 | 生产部署验收 | +| Q15 | `POST /cminmsgs/send` 的长度上限与失败响应 | 仅内部联调、无外部引用;成功返回编号等行为见 `C-7`;上限与失败格式现阶段不定,实现时在代码里自定 | 不阻塞对外契约 | +| Q16 | `POST /schd/sync` 的请求字段与时间格式、成功响应表示已登记还是已落信、状态码与错误响应 | 交付承诺止于落信(`C-4`);旧系统线索为 `{startDate, endDate}` 与 12 小时制时间(接口契约「HTTP」) | 响应契约无法定稿(`C-8`) | +| Q17 | 人工发起 `RQRD` 的方式 | `US-09` 要求人工发起,HTTP 接口清单没有对应入口 | 参考数据请求无法人工触发 | +| Q18 | 回退时在途消息(已提交业务变更、未到处理完成)的处置 | 回填了结后切换(`OPS-4`);在途消息无跨系统幂等保障 | 回退演练的验收口径(`OPS-4`) | +| Q19 | 是否在自有 PG 留存入站原文副本,及原文提前清除时已登记消息的处置 | 不留存,原文只从信箱读取 | 提前清除的消息不可恢复,处置未定 | +| Q20 | 日计划中运营日冲突的处置 | 未定 | 冲突场景无法验收 | +| Q21 | `GET /all/flights` 的状态码、错误响应样例、外层包装是否沿用旧 `ResponseDto` | 返回体是消息文档中的 XML 结构转换出的 JSON;读 Redis、返回全体动态航班、不分页(`C-11`) | 查询契约无法定稿 | +| Q22 | `REF_MASTER` 的物理列、唯一键、空值存储与写入后可见时点 | 记录用类别码加识别标签识别(接口契约「静态参考数据类别与编号来源」) | admin-api 读取契约无法定稿(`C-10`) | +| Q23 | Elasticsearch 历史索引、文档 ID、字段映射、成功判据、保留期与容量上限、写入结果不明的对账与幂等策略 | 历史写入确认成功才删实时数据(`D1`、`US-14` AC3) | 历史链路无法验收(`US-14`;`G-FLIGHT-HIST-RETENTION`) | +| Q24 | `REQ_TRACK` 已结案记录的保留期取值 | 到期清理没有可依据的窗口(`G-REQ-TRACK-RETENTION`) | 请求历史清理无法实现(`US-09`) | +| Q25 | 季度计划的数据来源与归属:admin-api 从本系统库读季度计划,而 SIS 只有日计划事件(`SIS:3.16`、`SIS:3.17`、`SIS:4.7`) | 应由 AODB 下发,报文形态待确认;旧系统读 Oracle 的 `FIMS_FLIGHTSCHD_SEASON` | admin-api 的季度计划查询没有供数方 | ## 7. 当前已知偏差 @@ -149,8 +154,8 @@ |---|---|---| | `G-REQ-TRACK` | 出站请求没有跟踪:登记、编码、超时与应答匹配都没有实现 | `US-09` | | `G-REQ-OPEN-UNIQUE` | 同一报文类型同时最多一条已落信、未结案请求的限制没有实现;待发送登记不算占用该名额 | `US-09` | -| `G-REQ-TRACK-RETENTION` | `REQ_TRACK` 已结案记录的保留期取值未定,到期清理作业没有可依据的窗口(取值待 `Q28`) | `US-09` | -| `G-FLIGHT-HIST-RETENTION` | 历史存储的保留期与容量上限未定(取值待 `Q27`) | `US-14`;实时数据删除后历史是唯一副本 | +| `G-REQ-TRACK-RETENTION` | `REQ_TRACK` 已结案记录的保留期取值未定,到期清理作业没有可依据的窗口(取值待 `Q24`) | `US-09` | +| `G-FLIGHT-HIST-RETENTION` | 历史存储的保留期与容量上限未定(取值待 `Q23`) | `US-14`;实时数据删除后历史是唯一副本 | | `G-FLOP-IDEMPOTENT` | 逐类幂等规则未补齐 | `US-03`;`CLM-1` | | `G-FLOP-SEMANTICS` | `STYP` 没有白名单,`ROUT` 未限制 4 条,运行状态落点与已删除航班的处理与 `US-05` 不符 | `US-05` | | `G-FLOP-UNMAPPED` | [XSD](legacy/unisysaodbsis.xsd)「FLOP 元素」里有些字段没有解码或映射错了,会被静默丢掉 | `US-05` | @@ -181,7 +186,7 @@ | US-14 AC4 | `US-14` AC4 | 历史清理跳过正在被消息处理的航班 | | INV-4 | `US-07` AC1 | 校验失败后本地数据与版本不变 | | INV-9 | `US-07` AC4/AC5 | 分批失败后整包重处理收敛到同一目标(`G-SCHD-SNAPSHOT` 闭合前无法验证);Redis 在整包写入完成后按快照刷新,成功即与快照一致 | -| CLM-1 | `US-03` | 同一消息不产生两次效果;逐子类型规则与幂等矩阵在 `Q8`、`G-FLOP-IDEMPOTENT`、`G-FLOP-SEMANTICS` 闭合前无法验证 | +| CLM-1 | `US-03` | 同一消息不产生两次效果;逐子类型规则与幂等矩阵在 `Q3`、`G-FLOP-IDEMPOTENT`、`G-FLOP-SEMANTICS` 闭合前无法验证 | | INV-8 | `US-06` AC1 | 航班标记删除后从投影移除;移除失败时下轮重做 | | US-14、D1 | `US-14` AC3 | 历史写入成功才删实时数据;删除事件在实时数据删除前登记(`D1`) | | US-06 AC2 | `US-06` AC2 | 删共享联动主航班;删主航班级联删共享 | @@ -193,6 +198,6 @@ | CLM-4 | `US-09` AC1~AC3 | 出站请求写入 `COUTMSGS` | | CLM-5(不承诺完成时限) | — | 需求未定完成时限;现场一般为即时处理 | | CLM-6(容量) | — | 现场量级暂无;有数据后再估 | -| OPS-4 | `OPS-4` | 回退演练:回填了结后切回,旧系统不重处理已产生业务效果的消息;在途窗口处置见 `Q21` | +| OPS-4 | `OPS-4` | 回退演练:回填了结后切回,旧系统不重处理已产生业务效果的消息;在途窗口处置见 `Q18` | | CLM-7 | `OPS-1` | 配置错误启动失败测试可验收 | | PRE-1(测试隔离) | `OPS-3` | 测试环境配置核对:独立的数据库、Redis 与 Kafka 主题,不连接生产信箱 | diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/codec/JacksonXmlCodec.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/codec/JacksonXmlCodec.kt index edee6bc..fb86627 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/codec/JacksonXmlCodec.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/codec/JacksonXmlCodec.kt @@ -85,7 +85,7 @@ class JacksonXmlCodec : XmlCodec { /** * 子类型分派必须是**白名单**:未知的 SCHD 子类型不能静默当成全量日计划(DNLD)—— * 那会让一条本该"暂不支持、等人工处置"的报文走最重的整包合并写入路径。 - * 空 STYP 按 legacy 约定视为 DNLD(该约定待与 SIS 逐类对拍确认,见 Q8)。 + * 空 STYP 按 legacy 约定视为 DNLD(该约定待与 SIS 逐类对拍确认,见 Q3)。 */ private fun kindOf(type: String, styp: String): MsgKind = when (type) { "SCHD" -> when (styp) { diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisMessageBody.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisMessageBody.kt index 71dde51..45bca6f 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisMessageBody.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisMessageBody.kt @@ -23,7 +23,7 @@ data class ScheduleBody( * 只保留在 wire/domain、尚未映射到持久化明细的集合键(`[G-SRVT-VIPF]`)。 * * 它们不参与合并、不进快照、不落库;保留的目的是不让入站事实在解码层被静默抹平,并让真实 - * 流量里的出现情况可观测——决定"缺席是否等于删除"的 `Q13` 需要真实报文才能定案。 + * 流量里的出现情况可观测——决定"缺席是否等于删除"的 `Q11` 需要真实报文才能定案。 */ private val UNPERSISTED_COLLECTION_KEYS: Set = setOf("SRVT", "VIPF") @@ -132,7 +132,7 @@ data class FlightRecordXml( @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ROUT") val rout: List = emptyList(), @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ERUT") val erut: List = emptyList(), // SRVT/VIPF 用可空表达"段是否出现":null = 未出现;出现即为列表(空元素得到一行空行)。 - // 两者都不落明细表、不参与合并,清空语义待 `Q13`(`[G-SRVT-VIPF]`)。 + // 两者都不落明细表、不参与合并,清空语义待 `Q11`(`[G-SRVT-VIPF]`)。 @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "SRVT") val srvt: List? = null, @param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "VIPF") val vipf: List? = null, ) diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisWireMapper.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisWireMapper.kt index 8b9650c..5d6513e 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisWireMapper.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/codec/SisWireMapper.kt @@ -38,7 +38,7 @@ internal object SisWireMapper { * `filterValues` 去掉的正是"缺席",避免整包凭空清空本地明细(合并语义见 docs/implementation.md「SCHD 日计划」)。 * * `SRVT`/`VIPF` 尚未有明细表(`[G-SRVT-VIPF]`):只用"键是否存在"表达段是否出现,保留原始 - * 内容与顺序,不参与合并、不判断清空语义(`Q13`)——出现(哪怕为空)与缺席不再被抹平。 + * 内容与顺序,不参与合并、不判断清空语义(`Q11`)——出现(哪怕为空)与缺席不再被抹平。 */ private fun FlightRecordXml.collections(): Map>> { val mapped = linkedMapOf( diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineCounters.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineCounters.kt index d58873c..5ba7c23 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineCounters.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineCounters.kt @@ -21,7 +21,7 @@ class PipelineCounters { * 入站记录里出现 `SRVT`/`VIPF` 段的条数(`[G-SRVT-VIPF]`)。 * * 这两个集合目前只保留在 wire/domain,不落明细表、不参与合并;计数是"真实报文有没 - * 有在用"的唯一取证渠道(清空语义 `Q13` 需要真实样例才能定案)。> 0 表示确有流量携带该段。 + * 有在用"的唯一取证渠道(清空语义 `Q11` 需要真实样例才能定案)。> 0 表示确有流量携带该段。 */ fun unpersistedCollectionSeenAdd(hits: Map) { hits["SRVT"]?.let { srvtSeen.addAndGet(it.toLong()) } diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineMetrics.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineMetrics.kt index c5b05c5..1612c40 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineMetrics.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/infra/metrics/PipelineMetrics.kt @@ -94,7 +94,7 @@ class PipelineMetrics( .strongReference(true) .register(registry) - // SRVT/VIPF 尚未落明细表([G-SRVT-VIPF]):计数替代静默丢弃,为 Q13 提供真实流量证据。 + // SRVT/VIPF 尚未落明细表([G-SRVT-VIPF]):计数替代静默丢弃,为 Q11 提供真实流量证据。 Gauge.builder("msgx.pipeline.codec.srvt_seen.total", counters) { it.srvtSeenCount().toDouble() } .strongReference(true) .register(registry) diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/infra/persistence/jdbc/JdbcCminmsgInboxRepository.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/infra/persistence/jdbc/JdbcCminmsgInboxRepository.kt index a8cb460..450d020 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/infra/persistence/jdbc/JdbcCminmsgInboxRepository.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/infra/persistence/jdbc/JdbcCminmsgInboxRepository.kt @@ -37,10 +37,10 @@ class JdbcCminmsgInboxRepository( } } catch (e: IllegalStateException) { // 只调整适配代码、不碰共享 Schema:把"取不到 generated key"变成可诊断错误, - // 指出这是共享信箱 ID 生成方式的前提(C-14、Q7)。 + // 指出这是共享信箱 ID 生成方式的前提(C-14、Q8)。 throw IllegalStateException( "shared mailbox insert returned no generated CMINMSGS_ID; " + - "the CMINMSGS_ID column must be DB-generated (C-14, Q7)", + "the CMINMSGS_ID column must be DB-generated (C-14, Q8)", e, ) } diff --git a/src/main/kotlin/com/gzzn/omms/msgexchange/processing/Pump.kt b/src/main/kotlin/com/gzzn/omms/msgexchange/processing/Pump.kt index 718fd14..569495f 100644 --- a/src/main/kotlin/com/gzzn/omms/msgexchange/processing/Pump.kt +++ b/src/main/kotlin/com/gzzn/omms/msgexchange/processing/Pump.kt @@ -190,7 +190,7 @@ class MessageProcessor( } } - // [G-SRVT-VIPF]:SRVT/VIPF 段只保留在解码载荷里,尚未落明细表(清空语义待 Q13)。 + // [G-SRVT-VIPF]:SRVT/VIPF 段只保留在解码载荷里,尚未落明细表(清空语义待 Q11)。 // 计数 + 告警替代此前的静默丢弃;出现即证明真实报文携带该段,可作为定案依据。 val unpersisted = unpersistedCollectionHits(decoded.body) if (unpersisted.isNotEmpty()) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5d6c86a..ee26544 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -18,7 +18,7 @@ msgx: max-attempts: 5 # 处理/投递同值 backoff-ms: [1000, 2000, 4000, 8000] # 指数退避;档位数必须 = max-attempts - 1(启动自检) backoff-cap-ms: 60000 - max-commit-delay: 5m # 空洞老化:W+1 空洞超过该时延判定为永久(Q2 最大提交时延) + max-commit-delay: 5m # 空洞老化:W+1 空洞超过该时延判定为永久(Q7 最大提交时延) overdue-backfill: 30d # 超期补写期限 R:仅须 R ≤ R_keep;判据比较本地 ENQUEUED_AT(implementation.md「回填」) backfill-batch: 100 # 回填扫描单批条数 backfill-max-attempts: 100 # 单行重试的告警阈值;放弃判据是 R 超期,不是次数(implementation.md「回填」) @@ -78,7 +78,7 @@ flyway: # 处理回填;出站写 COUTMSGS;不建表/schema,ACM2-12)。驱动/依赖与信箱适配层 # (CminmsgMailbox/OutboxMailbox)随 U05 批次引入。 mailbox: - processed-value: PROCESSED # 处理标记写入值(C-5/Q7:值集与写权限以库方契约为准) + processed-value: PROCESSED # 处理标记写入值(C-5/Q8:值集与写权限以库方契约为准) shared-mysql: enabled: false url: ${MSGX_MAILBOX_URL} diff --git a/src/main/resources/db/migration/V1__flight_state_baseline.sql b/src/main/resources/db/migration/V1__flight_state_baseline.sql index 50c1109..ffa76e6 100644 --- a/src/main/resources/db/migration/V1__flight_state_baseline.sql +++ b/src/main/resources/db/migration/V1__flight_state_baseline.sql @@ -284,7 +284,7 @@ CREATE INDEX idx_flight_chock_flid ON FLIGHT_CHOCK_OP (FLID); CREATE TABLE MSG_EVENT ( EVENT_ID BIGSERIAL PRIMARY KEY, -- 对 KAFKA:msg 是稳定事件身份并决定投递顺序;对 KAFKA:schd 是每次接受 upsert 时替换的写代次 TARGET VARCHAR(30) NOT NULL, -- KAFKA:msg / KAFKA:schd - PARTITION_KEY VARCHAR(32) NOT NULL, -- 当前恒为 FLID(Q4 定案前为假定,C-29) + PARTITION_KEY VARCHAR(32) NOT NULL, -- 当前恒为 FLID(Q1 定案前为假定,C-29) EVENT_TYPE VARCHAR(16) NOT NULL DEFAULT 'UPSERT', -- UPSERT / TOMBSTONE STATE_VERSION BIGINT NOT NULL, -- 发布时航班版本;schd 聚合按 FLID 只进不退 PAYLOAD_JSON TEXT NOT NULL, -- TOMBSTONE 时至少含 FLID/STATE_VERSION/DELETED diff --git a/src/main/resources/db/migration/oracle11g/README.md b/src/main/resources/db/migration/oracle11g/README.md index 3c85d93..858cbad 100644 --- a/src/main/resources/db/migration/oracle11g/README.md +++ b/src/main/resources/db/migration/oracle11g/README.md @@ -20,7 +20,7 @@ Flyway 配置**;PG 路径使用 `classpath:db/migration`,两者互不混用 `NUMBER`/序列替代 `BIGSERIAL`、`TIMESTAMP WITH TIME ZONE`、`VARCHAR2` BYTE/CHAR 语义钉死。 - `INSERT ... ON CONFLICT` 改 11g MERGE(OPERATION_DAY 不可变条件,`INV-12`)。 - 空串按 NULL 的语义回归:显式清空的 presence 信息不得被 11g 空串语义吞掉 - (字段清空语义见 `Q13`;定案前按「未携带不清空」实现,`INV-14`)。 + (字段清空语义见 `Q11`;定案前按「未携带不清空」实现,`INV-14`)。 - 11g 无部分索引:`uq_req_open` / `uq_schd_event` / `idx_proc_backfill_due` 三个带 `WHERE` 的索引必须换成等价的函数索引或冗余列方案,不能照搬 PG 定义。