Files
docs/三期/货柜管理全链验收矩阵-2026-08-13.md
T
2026-08-14 19:59:30 +08:00

147 lines
19 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.
# 货柜管理全链验收矩阵
> 更新时间:2026-08-14
> 当前任务:`019ff90b-a72d-7000-abdf-e5363357a564`
> 父任务:`019ff600-f9f1-78f1-a357-7c80c13e574e`
> 依赖任务:后端 `019ff90b-9b45-7191-b68f-c3b52567e3e4`、Admin `019ff90b-a037-79b0-b945-8f88bdbde9c5`
> 边界:只维护根目录脚本、验收文档和测试矩阵;不修改 Admin 或 Java 业务源码,不部署、不触发 Jenkins、不写测试环境数据库。
## 验收口径
- 本矩阵以当前对话、三期产品确认版开发规划和实际冻结契约为准。旧确认单中的待确认项不覆盖后续已冻结结论。
- 已冻结能力按事实来源落具体路径和断言;尚未冻结能力继续只保留能力级占位,不预设 HTTP 方法、路径、DTO 字段或业务错误码。
- 自动化必须通过业务 API 生成数据;人工验收必须能从 Admin/PDA 可见入口点击到对应状态。不得以数据库直写、mock、原型或前端本地假状态代替。
- 每次真实 HTTP 验收记录请求用途、响应状态、业务码、`requestId`、`traceId`、关键资源 ID 和清理/保留策略;敏感凭据不得写入报告。
- 柜态看板不纳入本轮。
## 状态数据目录
| 数据代号 | 必备状态/形态 | 生成前置 | 自动化断言 | 人工可点击入口 | 当前状态 |
|---|---|---|---|---|---|
| CT-D01 | 已确认订单 `CONFIRMED`,尚无柜次 | 可创建并确认订单 | 确认后自动产生唯一柜次;重复事件不重复建柜 | 订单详情可进入关联柜次 | 待契约 |
| CT-D02 | 不同渠道各一单 | 渠道主数据可用 | 柜次/清单/任务不得跨渠道混装或串查 | 排柜候选可按渠道辨识 | 待契约 |
| CT-D03 | 已排柜但无真实柜号 | 临时柜身份可生成 | 不要求真实柜号即可排柜,内部身份稳定 | 预装清单可查看“待补号”柜次 | 待契约 |
| CT-D04 | 已补真实柜号、PDA 可领取 | CT-D03 | 补号后 PDA 入口开放且关联原内部柜身份 | PDA 任务列表可进入 | 待契约 |
| CT-D05 | 作业中更换真实柜号 | CT-D04,PDA 已开始 | 柜号变化但柜次 ID、任务、清单、证据归属不漂移 | 详情与 PDA 同步显示新柜号 | 待契约 |
| CT-D06 | 预装清单已生成/确认 | CT-D03 | 清单版本、订单明细、数量及确认历史可追溯 | 预装清单列表/详情可点击 | 待契约 |
| CT-D07 | 装柜清单进行中/已完成 | CT-D04 | 装载明细、数量、状态与预装来源一致 | 装柜清单列表/详情可点击 | 待契约 |
| CT-D08 | PDA 领取、拣货、复核、异常摘要 | CT-D04 | overview 分别返回 `taskStatus`、`workflowStatus`、任务 ID、版本、计数、`photoCounts`、`photos`、`downloadPath` 和异常原因;逐照片代理下载成功 | PDA 可完成主流程;Admin 入口待回传 | 服务端已冻结;人工入口待定 |
| CT-D09 | 报关/清关资料及有效回执 | CT-D06 | 目的港清关走货柜 `/clearance`;出口报关走 loading-list `/customs`;分别验证上传、完成和完成后替换锁定 | 报关协同入口待回传 | 服务端已冻结;人工入口待定 |
| CT-D10 | DO/PU 未齐、部分完成、全部完成 | 柜次与运输协同已建立 | `DELIVERY_ORDER`、`PICKUP_ORDER` 可独立查询、上传和鉴权下载,版本与幂等有效 | 柜次详情入口待回传 | 服务端已冻结;人工入口待定 |
| CT-D11 | 正常、异常、取消异常 | 任意有效柜次及显式货柜版本 | 标记/取消使用版本和必填原因;overview 保留 `MARK`/`CANCEL` 全部历史 | 货柜详情入口待回传 | 服务端已冻结;人工入口待定 |
| CT-D12 | 多节点运输轨迹与操作日志 | CT-D10 | overview 时间线含运输更新、异常和 PDA 事件,按发生时间升序 | 详情时间线入口待回传 | 服务端聚合已冻结;人工入口待定 |
| CT-D13 | 满足全部 `LOADED` 硬门禁 | 订舱、拖车、有效放行回执、PDA、五类证据完成 | 仅全部满足时进入 `LOADED`,重复完成幂等 | 订单/柜次详情显示完成且编辑锁定 | 待契约 |
## 全链验收用例
| 用例 | 场景 | 服务端/契约断言 | UI/设备断言 | 证据要求 | 状态 |
|---|---|---|---|---|---|
| CT-E01 | `CONFIRMED` 自动建柜 | 状态事件自动建一个柜次;重放幂等;失败可观测 | 订单详情无需手工建柜即可看到柜次 | 前后资源 ID、事件/日志 | 待契约 |
| CT-E02 | 渠道隔离 | 不同渠道不能进入同一排柜结果;交叉 ID 请求失败 | 候选、清单和详情不串渠道 | 双渠道正向及交叉负向响应 | 待契约 |
| CT-E03 | 无真实柜号排柜 | 临时身份可完成排柜/预装;真实柜号字段可空 | 页面明确展示待补号,不伪造柜号 | 柜次 ID、预装版本 | 待契约 |
| CT-E04 | 补号开放 PDA | 合法补号后任务可领取;未补号时领取被稳定阻止 | 补号前后 PDA 入口状态同步 | 补号审计、领取响应 | 待契约 |
| CT-E05 | 作业中换号身份不漂移 | 只变更展示柜号;柜次 ID、任务 ID、清单、证据关联不变 | Admin/PDA 刷新后显示新号且进度不丢 | 换号前后关联快照 | 待契约 |
| CT-E06 | 预装/装柜清单 | 生成、确认、版本、装载数量及来源关系完整 | 两类列表和详情均可人工点击 | 清单响应与页面截图 | 待契约 |
| CT-E07 | PDA 主链 | 领取、扫码、批量提交、复核、完成;幂等与版本冲突有效 | 真机/目标设备可完成,失败不假成功 | 请求链、设备记录 | 待契约 |
| CT-E08 | PDA 进度异常摘要 | `GET /api/platform/v1/containers/{id}/overview` 返回 PDA `taskStatus/workflowStatus`、任务身份、版本、计数、照片摘要、文件 ID 与鉴权下载路径;每个路径真实 GET 200 | Admin 入口待回传 | overview 响应、字段完整性及二进制下载证据 | 服务端契约已冻结 |
| CT-E09 | 清关/报关资料闭环 | 目的港清关:货柜 `/clearance` 查询/上传/完成;出口报关:loading-list `/customs` 查询/上传/完成;两者完成后均禁止替换 | Admin 入口待回传 | 两条专用链路的版本、幂等、完成和锁定负向响应 | 服务端契约已冻结 |
| CT-E10 | DO/PU | 通用查询、multipart 上传、鉴权下载;上传要求 `Idempotency-Key`、真实文件、`expectedVersion`,重放不得重复上传 | Admin 入口待回传 | 两类型响应、文件哈希/ID、二进制下载、幂等重放 | 服务端契约已冻结 |
| CT-E11 | 货柜异常及取消历史 | `POST/DELETE /api/platform/v1/containers/{id}/exception` 要求 `expectedVersion` 和必填原因;冲突失败;overview 历史只追加不覆盖 | Admin 入口待回传 | 标记/取消响应、版本冲突、overview 历史 | 服务端契约已冻结;版本来源阻断 |
| CT-E12 | 运输轨迹/日志 | overview `timeline` 聚合 `TRANSPORT_UPDATE`、`MARK/CANCEL`、`PDA_*`,时间升序且含详情、操作者和发生时间 | Admin 入口待回传 | overview 时间线响应 | 服务端契约已冻结 |
| CT-E13 | `LOADED` 正向与逐项负向 | 五项硬门禁分别缺失时 fail-closed;全部满足后只迁移一次 | 完成后详情锁定,状态一致 | 5 个负向 + 1 个正向 + 幂等重放 | 待契约 |
| CT-E14 | 跨客户与跨仓库隔离 | 交叉资源 ID 不可读写下载,不泄露资源存在性 | 页面无越权入口 | 双身份交叉请求证据 | 待契约 |
## 契约冻结清单
### 既有冻结基线
以下能力在本轮新增 overview 契约之前已经由三期产品确认版、既有 OpenAPI/Controller 和专项测试冻结。本轮不重定义其路径或状态机。
| 能力标识 | 冻结边界 | 事实来源 | 状态 |
|---|---|---|---|
| `confirmed-auto-container` | `CONFIRMED` 自动建柜、幂等和唯一性 | 三期产品确认版及既有订单/货柜契约 | 既有冻结,待环境验收 |
| `channel-isolation` | 渠道隔离与禁止跨渠道混装 | 三期产品确认版及既有排柜契约 | 既有冻结,待环境验收 |
| `container-number-lifecycle` | 无真实柜号排柜、补号开放 PDA、作业中换号身份稳定 | 既有预装/货柜/PDA 契约 | 既有冻结,待环境验收 |
| `preload-and-loading-list` | 预装与装柜清单状态、版本、明细和历史 | 既有 Loading List OpenAPI/Controller/DTO | 既有冻结,待环境验收 |
| `customs-documents-lock` | 清关/报关专用流程、完成态禁止替换 | 既有 `LoadingListService`、专用 Controller 与专项测试 | 既有冻结,待环境验收 |
### 本轮新增冻结契约
事实来源:`baiyue-firstleg/firstleg/src/main/resources/openapi/phase3-container-overview-v1.yaml`、`PlatformContainerController`、`ContainerOverviewDtos`、`ContainerOverviewService`、`LoadingListService`。
| 能力标识 | 冻结路径与字段 | 权限/并发 | 状态 |
|---|---|---|---|
| `container-overview` | `GET /api/platform/v1/containers/{id}/overview`;聚合 container、loadingPlanId、PDA 摘要、documents、exception/history、timeline | `platform:firstleg:container:list`;旧 `container:view` 已移除 | 已冻结 |
| `pda-progress-exception-summary` | PDA `taskStatus/workflowStatus`、任务 ID/版本、明细计数、`photoCounts`、`photos`(含 fileId/status/downloadPath)及异常原因;照片下载为 `GET /api/platform/v1/containers/{id}/pda/photos/{fileId}/download` | 随 overview 查看权限;下载复核柜次、计划、入库单与文件归属 | 已冻结 |
| `container-abnormal-history` | `POST/DELETE /api/platform/v1/containers/{id}/exception`;请求使用 overview 返回的 container.version、必填原因和幂等键 | `platform:firstleg:container:edit`;版本冲突 fail-closed | 已冻结 |
| `container-documents` | 通用查询、multipart 上传和受控文件下载仅支持 DO/PU;下载透传已校验 Content-Type,非法类型回退 `application/octet-stream`,并返回 UTF-8 文件名、`no-store` 和内容长度 | 查询/下载用 `platform:firstleg:container:list`,上传用 `platform:firstleg:container:edit`;旧 `container:view` 已移除;下载校验柜次、类型、文件 ID 及文件服务 tenant/business 归属 | 已冻结 |
| `do-pu` | `DELIVERY_ORDER`、`PICKUP_ORDER` 通用查询/上传/下载 | 同 `container-documents` | 已冻结 |
| `transport-trajectory-log` | overview timeline 的事件类型、详情、操作者、发生时间;服务端升序 | 随 overview 查看权限 | 已冻结 |
### 最终安全分流
1. overview 与通用 documents 只覆盖 `DELIVERY_ORDER`、`PICKUP_ORDER`,不得向通用路径传清关或报关类型。
2. 目的港清关使用 `/api/platform/v1/containers/{id}/clearance` 及其专用上传、完成动作,权限为 `platform:firstleg:customs:manage`。
3. 出口报关使用 `/api/platform/v1/first-leg/loading-lists/{planId}/customs` 及其专用上传、完成动作;查询使用 `platform:firstleg:loading-list:list`,旧 `loading-list:view` 已移除,写入使用 `platform:firstleg:customs:manage`。
4. 清关和出口报关分别验证完成态禁止替换,不能用 DO/PU 通用上传替代。
5. 下载允许透传经校验的 Content-Type,非法值回退二进制类型;同时必须保留 UTF-8 文件名、`no-store`、内容长度及资源归属复核。
## 自动化落地门禁
真实环境脚本只有在对应能力“已冻结=是”后才能加入请求步骤,并必须满足:
1. 环境地址、账号和令牌只从环境变量读取。
2. 默认不执行;必须通过显式运行参数开启真实 HTTP。
3. 只通过业务 API 造数,不连接数据库,不调用 Jenkins。
4. 支持按本次运行标识检索资源,避免误用历史数据;清理动作仅在契约明确且安全时启用。
5. 输出脱敏 JSON 报告,逐请求记录 HTTP 状态、业务码、`requestId`、`traceId` 和资源 ID。
6. 对未冻结能力或冻结来源不一致输出 `BLOCKED_CONTRACT`,不得以跳过后仍报告全链通过。
## 当前阻断
| 阻断 | 影响 | 解除条件 |
|---|---|---|
| 测试环境未获得部署授权且本任务禁止部署 | 无法验证环境是否已包含依赖实现 | 人工部署明确提交后,再执行获授权的验收轮次 |
| 未提供测试环境凭据和两组隔离身份 | 无法执行跨客户/跨仓库/下载鉴权负向用例 | 由总控提供临时验收身份或既有安全注入方式 |
## Marker 回归增量(ADMIN-API-20260814032734876)
| 回归项 | 当前冻结事实与自动化断言 | 当前结论 |
|---|---|---|
| Release 正式 DTO | `POST /api/platform/v1/ocean-bookings/{id}/release` 已冻结;`ReleaseRequest` 必填提单号、船名、航次、ETD、ETA,并保留 `expectedVersion`。HTTP fixture 必须携带五字段;Admin 未填齐不得调用 release | `LANDED`,不是路径阻断 |
| PDA overview 状态语义 | PDA 任务的 `taskStatus=LOADING` 与业务流转 `workflowStatus=AWAITING_REVIEW` 必须分字段返回;进度 100%、未解决数为 0 且任务仍为 `LOADING` 时必须明确为 `AWAITING_REVIEW` | 后端 DTO/OpenAPI/聚合已回传;`LANDED`,待环境 HTTP 验收 |
| PDA overview 照片下载 | 对 `photos[]` 每个服务端 `downloadPath` 执行真实鉴权 GET;仅接受站内 `/api/` 路径、HTTP 200、非空二进制和非 JSON/HTML Content-Type | HTTP 回归已准备;待获授权环境验收 |
| 客户公开名称一致性 | `customerId` 筛选后的订舱、拖车和预装列表/详情必须显示 IAM `tenantName`,不得优先 `legalName`;列表、详情及关联名称一致 | 列表筛选与拖车预约新增表单已统一 `tenantName`;`LANDED`,待人工筛选回归 |
| 已有 `containerNo` 动作语义 | 已有真实柜号时补号动作不可伪装成首次补号;换号前后柜次 ID、PDA taskId、loadingPlanId 和证据归属必须稳定 | Admin 已按柜号是否存在显示“录入集装箱号/修改集装箱号”,后端 HTTP fixture 已锁定身份稳定;`LANDED` |
| 订舱/拖车详情关联名称 | 详情中的客户、柜次、订舱及关联资源名称必须来自正式详情响应,并与同 ID 列表显示一致 | 后端详情已返回稳定名称字段,Admin 使用详情快照与受控候选回显;`LANDED` |
| 拖车附件闭环 | `POST /truck-appointments/{id}/attachments` 引用、`POST /truck-appointments/{id}/attachments/upload` 上传关联与 `DELETE /truck-appointments/{id}/attachments/{attachmentId}` 已冻结 | Admin 已提供选择文件、上传并关联、列表及删除入口,HTTP 删除后回查已覆盖;`LANDED` |
| 中文状态、弹框与 390px 布局 | 列表/详情状态必须中文;release、附件、柜号动作使用正式弹框;390px 下字段、按钮、弹框不横向溢出或遮挡 | `AWAITING_REVIEW`、照片类型、确认按钮已中文化,放舱/改船/附件弹框已落地;桌面与 390px 浏览器无横向溢出;`LANDED` |
说明:`BLOCKED_CONTRACT` 仅标记明确缺失的 DTO 字段或 Admin 承载,不把已存在的 release、拖车附件 API 路径降级为未冻结能力。
## 订舱物流渠道与柜次隔离增量
| 验收项 | 自动化断言 | 当前结论 |
|---|---|---|
| Admin 渠道选择 | 订舱新增/编辑不允许自由输入 `channelCode/channelName`;选择起运仓后使用渠道下拉,查询必须携带 `originWarehouseId` | `LANDED`:Admin 使用受控渠道下拉并调用正式平台渠道接口;Admin 与根静态合同均锁定渠道选择正向及自由输入负向 |
| 平台渠道目录 | `GET /api/platform/v1/ocean-bookings/channels?originWarehouseId=...` 只返回当前 ACTIVE 价格簿渠道;HTTP fixture 记录本轮 marker、`originWarehouseId` 与服务端路径,不借 Merchant 身份或历史资源 | OpenAPI 已冻结;真实查询生产者已发布 `createdResources.platformLogisticsChannels` |
| 双有效渠道 fixture | 跨渠道负向必须使用同一起运仓下两个真实有效渠道;只有一个有效渠道时输出 `BLOCKED_FIXTURE`,禁止派生 `-OTHER` 伪渠道 | 脚本门禁与正式渠道生产者已落地;待环境数据验证是否存在双渠道 |
| 船公司与物流渠道独立 | `shippingCompanyId/shippingCompanyName` 与渠道选择分别建模,不用船公司字段代替渠道字段 | `LANDED`:Admin 与写请求模型分别承载船公司和物流渠道,静态合同已转绿 |
| `CONFIRMED` 柜次继承渠道 | 订舱确认生成柜次后,货柜详情 `channelCode` 必须等于所选有效渠道;异渠道入库单不能分配到该柜次 | 既有 HTTP 断言保留;异渠道负向已移除伪渠道来源;写 DTO 不再发送服务端拥有的 `channelName` |
## 订舱资料字段与可选客户增量
事实来源:原型 `prototype-src/modules/06-containers.html`、P3-Q14、`OceanBookingDtos.DraftData`、`ocean-bookings-v1.yaml`、Admin `OceanBookingDetailView.vue` 与 `OceanBookingDraftData`。
| 字段/链路 | 原型与阶段时序 | 自动化断言 | 当前结论 |
|---|---|---|---|
| `serviceTerm` | 原型第 516 行以 `*` 标记主要运输条款必填;P3-Q14 未删除该业务快照 | Admin 必填自由文本;Java `@NotBlank`;OpenAPI `required` 且非 nullable;模块基线和统一 SQL 均为 `NOT NULL`;不保留无来源的 `CY-DOOR/DOOR-CY/DOOR-DOOR` 自造字典;验收 fixture 使用原型展示值 `CY-CY` | `LANDED` |
| `freightTerm` | 原型第 518 行以 `*` 标记运费条款必填;示例值为 `NINGBO`,不构成枚举事实来源 | Admin 必填自由文本;Java `@NotBlank`;OpenAPI `required` 且非 nullable;模块基线和统一 SQL 均为 `NOT NULL`;不保留无来源的 `PREPAID/COLLECT` 自造字典;验收 fixture 使用原型展示值 `NINGBO` | `LANDED` |
| 可选客户 | 原型第 527 行“客户/公司名称”无必填标记;当前产品确认允许平台先建订舱后关联客户 | Admin 可清空选择;前端类型、Java DTO 与 OpenAPI 均允许 `customerId/customerName` 同时为空,单边填写必须拒绝 | `LANDED` |
| 无客户 HTTP fixture | 不以历史客户或占位 ID/名称替代可空契约 | `ocean-bookings` 使用本轮 marker、正式渠道和仓库创建无客户订舱,详情回读真实 `bookingNo` 后按订舱号查询列表,断言空客户快照、`CONFIRMED` 及稳定柜次;发布 `createdResources.oceanBookingUnassignedCustomer` | 已准备,待部署后 HTTP 验收 |
| 指定客户隔离链 | 保留来自本轮入库单的正式客户范围 | `phase3-container-loading` 与既有订舱主链继续断言客户、仓库、渠道一致和跨渠道拒绝,不借历史资源 | 已准备,待部署后 HTTP 验收 |
| 提单号、船名、航次、ETD、ETA | 原型存在相关展示/录入字段,但 P3-Q14 明确真实运输数据在 `RELEASE` 补录,阶段时序覆盖草稿直接编辑方式 | 草稿页面仅只读展示,`OceanBookingDraftData` 和保存 payload 不含五字段;确认放舱弹框与 `ReleaseRequest` 必须完整携带五字段 | `LANDED` |
| 单证号 | 原型第 529 行存在“单证号”,但当前阶段 DTO/OpenAPI 未冻结对应写字段 | 不猜字段名或复用提单号;本轮不扩展写契约 | 非本轮能力,不标记接口阻断 |
离线合同:`ocean-booking-prototype-contract.test.mjs` 锁定原型证据、跨端可选客户、条款字段、草稿/放舱时序;`ocean-booking-fixture-contract.test.mjs` 与 `full-regression-entry-contract.test.mjs` 锁定无客户/指定客户双链和默认编排。