diff --git a/README.md b/README.md index e10d8a7..63065ef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # 虫虫出海文档索引 -项目交付文档按业务域组织。当前开发环境以端到端全流程为统一范围;历史规划、确认和验收记录保留在对应业务域目录,仅用于追溯决策,不构成功能边界。 +项目交付文档按业务域组织。当前只有测试环境,以端到端全流程为统一范围;历史规划、确认和验收记录保留在对应业务域目录,仅用于追溯决策,不构成功能边界。 + +- [测试环境单机部署与配置契约](测试环境单机部署与配置契约.md):唯一环境、部署配置、整体切换与验收。 +- [统一认证与服务通信契约](统一认证与服务通信契约.md):统一入口、权限撤销、逐事件投递与幂等。 ## 业务域文档 diff --git a/业务快速索引.md b/业务快速索引.md index 86414ed..62bb0c1 100644 --- a/业务快速索引.md +++ b/业务快速索引.md @@ -2,6 +2,8 @@ 本文件按需检索,不作为启动必读文档。以下路径均按工作区根目录或表内注明的应用源码根目录起算,不相对于 docs/。 +架构/环境/部署查[测试环境单机部署与配置契约](测试环境单机部署与配置契约.md);网关/Token/会话撤销/事件通信查[统一认证与服务通信契约](统一认证与服务通信契约.md)。下文旧区域服务路径用于定位现有实现,目标规则以这两份主契约为准。 + ## 常用说法与歧义分流 仓储转运审核、转运驳回:Admin 尾程订单 `apps/admin-web/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue` → `apps/admin-web/src/modules/overseas-warehouse/components/WarehouseTransferReviewDialog.vue`;权限、状态及 API 见该模块 `AGENTS.md` 的“仓储转运审核、通过与驳回”。不要把该入口当作头程订单审单,也不要按“转运”误入排车转派送。 diff --git a/双区域部署与Nacos规划.md b/双区域部署与Nacos规划.md index 0dde6f8..30d0455 100644 --- a/双区域部署与Nacos规划.md +++ b/双区域部署与Nacos规划.md @@ -1,166 +1,5 @@ -# 双区域部署与 Nacos 规划 +# 双区域部署与 Nacos 规划(已替代) -## 1. 适用范围与结论 +自 2026-09-29 起,不再规划开发/测试/生产与 CN/OVERSEAS 双区域。当前唯一目标为单一测试环境、所有服务同机部署。唯一部署主契约见[测试环境单机部署与配置契约](测试环境单机部署与配置契约.md),认证通信见[统一认证与服务通信契约](统一认证与服务通信契约.md)。 -本文冻结国内头程与海外仓服务在开发、测试和生产环境中的部署拓扑、Nacos、数据库及 Event Bridge 边界。账号、Token、API 路由和事件语义继续以《跨区域认证与服务通信契约》为准。 - -当前结论: - -- 开发、测试采用单宿主机共置:同一环境内同时部署国内 Compose 与海外 Compose,通过独立容器、网络、端口、Nacos Namespace 和数据库 Schema 隔离。 -- 生产采用国内、海外两套独立区域控制面:各自使用本区域 Nacos 集群、数据库和 Redis,不允许海外服务跨境依赖国内 Nacos、MySQL 或 Redis。 -- 跨区域只开放双区域 API、JWKS 公钥和 Event Bridge 接收入口,不使用跨区域服务发现。 - -## 2. 环境拓扑 - -| 环境 | 宿主与网络 | Nacos | 数据库 | 适用目的 | -|---|---|---|---|---| -| development | 单宿主机共置国内/海外 Compose | 一套开发 Nacos,国内/海外独立 Namespace | 可共用一个开发 MySQL 实例,但必须使用独立 Schema | 日常开发联调 | -| test | 单宿主机共置国内/海外 Compose | 一套测试 Nacos,国内/海外独立 Namespace | 可共用一个测试 MySQL 实例,但必须使用独立 Schema | 集成测试和验收 | -| production-cn | 国内独立部署单元 | 国内高可用 Nacos 集群 | 国内独立 MySQL/Redis | Auth、IAM、头程、国内仓和 Finance | -| production-overseas | 海外独立部署单元 | 海外高可用 Nacos 集群 | 海外独立 MySQL/Redis | 海外 Gateway、Lastleg 和海外 Warehouse | - -如果开发与测试实际共用同一套 Nacos 实例,必须创建四个 Namespace,不得复用: - -```text -development-cn -development-overseas -test-cn -test-overseas -``` - -Namespace 名称不是服务名。环境变量必须填写 Nacos 实际 Namespace ID;控制台自动生成 UUID 时使用 UUID,不使用展示名称代替。 - -## 3. 服务归属 - -### 3.1 国内区域 - -- `gateway`、`auth-service`、`iam-service` -- `firstleg-service`、`order-service`、`finance-service` -- 国内 `warehouse-service`、`file-service`、`audit-service` 等公共服务 -- 国内 Event Bridge,用于接收目标区域为 `CN` 的事件并投递本地 Firstleg - -### 3.2 海外区域 - -- `gateway-overseas` -- `lastleg-service`,同时持有 `baiyue_lastleg` 内的 IAM 安全事件 Inbox/投影,并开放内部事件接收和实时校验端点 -- `warehouse-overseas-service` -- 海外 `file-service`,独占海外 RDS 中的 `baiyue_file`,只访问海外本区域私有 OSS Bucket;详细边界见《[阿里云 OSS 文件中心接入设计与评审](阿里云OSS文件中心接入设计与评审.md)》 -- 海外 Event Bridge,用于接收目标区域为 `OVERSEAS` 的事件;业务事件和三类 IAM 安全事件按事件类型投递 Lastleg 的不同内部入口 - -海外浏览器请求直接进入海外 Gateway,不经过国内 Gateway。Auth 仍只部署在国内;海外服务通过受控 JWKS 地址验证 Auth 签发的短时海外 Token,不访问国内 Redis。 - -## 4. Nacos 规划 - -### 4.1 开发与测试 - -非生产环境允许一套 Nacos 实例承载多个 Namespace。国内配置发布自 `baiyue-firstleg/config/nacos/cn/`,海外配置发布自 `baiyue-firstleg/config/nacos/overseas/`,相同 Data ID 依靠 Namespace 隔离。 - -国内环境变量: - -```dotenv -NACOS_SERVER_ADDR=<当前环境Nacos地址> -NACOS_NAMESPACE=<当前环境国内Namespace ID> -REGION_CODE=CN -DEPLOYMENT_CELL=-cn -DATA_RESIDENCY=CN -``` - -海外环境变量: - -```dotenv -OVERSEAS_NACOS_SERVER_ADDR=<当前环境Nacos地址> -OVERSEAS_NACOS_NAMESPACE=<当前环境海外Namespace ID> -OVERSEAS_DEPLOYMENT_CELL=-overseas -``` - -海外 Compose 必须强制传入 `REGION_CODE=OVERSEAS` 和 `DATA_RESIDENCY=OVERSEAS`,不得继承共享文件中的国内默认值。 - -### 4.2 生产 - -生产国内、海外分别部署本区域 Nacos 集群。服务只注册到本区域,不同步或复制临时服务注册表,也不通过公网访问另一地区 Nacos。 - -```dotenv -# 国内生产凭据 -NACOS_SERVER_ADDR=<国内Nacos内网地址> -NACOS_NAMESPACE= - -# 海外生产凭据 -OVERSEAS_NACOS_SERVER_ADDR=<海外Nacos内网地址> -OVERSEAS_NACOS_NAMESPACE= -``` - -生产 Nacos 必须启用认证、网络 ACL 和持久化;不暴露公网管理端口。数据库密码、JWT 私钥、内部服务 Token 和第三方密钥不得写入 Nacos 明文,继续由 Jenkins Credentials 或生产密钥管理系统注入。 - -## 5. 数据库隔离 - -开发、测试即使共用一个 MySQL 实例,也必须保持以下 Schema 独立: - -| 区域 | 服务 | Schema | -|---|---|---| -| 国内 | Event Bridge | `baiyue_event_bridge` | -| 海外 | Event Bridge | `baiyue_event_bridge_overseas` | -| 海外 | Lastleg | `baiyue_lastleg` | -| 海外 | Warehouse | `baiyue_lastlag_warehouse` | - -生产必须进一步使用区域内独立数据库实例或集群。国内服务不得查询海外 Schema,海外服务不得查询国内 Schema;跨区域事实只通过版本化事件或已确认的受保护内部接口传递。 - -## 6. Event Bridge 双实例 - -每个区域部署一个相同制品、独立数据库的 Event Bridge: - -```text -Firstleg Outbox - -> 海外 Event Bridge Inbox - -> Lastleg 本地消费者 - -Lastleg Outbox - -> 国内 Event Bridge Inbox - -> Firstleg 本地消费者 -``` - -国内 Firstleg 配置海外 Bridge 基础地址,Feign 自动追加接收路径: - -```dotenv -LASTLEG_EVENT_BRIDGE_URL=<海外Event Bridge基础地址> -``` - -海外 Lastleg 配置国内 Bridge 基础地址: - -```dotenv -FIRSTLEG_EVENT_BRIDGE_URL=<国内Event Bridge基础地址> -``` - -区域内消费者使用本地服务地址: - -```dotenv -# 海外 Bridge -EVENT_CONSUMER_URL=http://lastleg-service:9303/internal/lastleg/events - -# 国内 Bridge -FIRSTLEG_CONTAINER_EVENT_CONSUMER_URL=http://firstleg:9202/internal/firstleg/v1/container-events -``` - -跨区域 Bridge 接收入口使用 TLS、内部服务身份、网络白名单和幂等校验;不得暴露数据库或消费者内部接口。 - -## 7. Jenkins 与环境文件 - -开发、测试可以各用一份 Secret File,同时包含国内和海外非敏感路由变量;Compose 负责选择本区域变量。生产必须拆分凭据: - -```text -firstleg-production-cn-env -firstleg-production-overseas-env -``` - -生产海外部署不得读取国内数据库、Redis 或 Nacos 地址。Event Bridge 同一制品需要按 `CN`、`OVERSEAS` 两个部署单元分别发布,使用不同 Compose Project、容器名、端口和数据库。 - -## 8. 当前仓库实施差距 - -目标架构已冻结,但当前部署代码仍需完成以下收敛: - -1. `docker-compose.overseas.yml` 当前仍从 `NACOS_SERVER_ADDR` 取值,应改为显式使用 `OVERSEAS_NACOS_SERVER_ADDR`。 -2. `deploy/scripts/deploy-built-service.sh` 与 `deploy-services.sh` 的海外服务门禁应校验 `OVERSEAS_NACOS_SERVER_ADDR`。 -3. Jenkins 生产配置需要拆分国内/海外 Secret File,并为 Event Bridge 提供明确区域部署参数或独立 Job。 -4. 海外 Nacos Namespace 创建、配置发布、JWKS 可达性和双向 Event Bridge 真实投递必须分别验收,不能以容器健康检查代替。 -5. 海外 Gateway 和 Nacos 已存在 File Service 入口,但海外统一 SQL 与部署清单尚未包含海外 `file-service`、`baiyue_file`;OSS 接入实施前必须补齐并完成区域内真实上传、下载和双实例读取验收。 - -这些差距未完成前,不得声称生产双区域部署已就绪。 +此文件仅保留旧链接入口,不再定义有效规则。运行配置切换仍待实施与验证。 diff --git a/国内货柜履约/报关资料与船期价格接入梳理.md b/国内货柜履约/报关资料与船期价格接入梳理.md index f662bd5..b280d2b 100644 --- a/国内货柜履约/报关资料与船期价格接入梳理.md +++ b/国内货柜履约/报关资料与船期价格接入梳理.md @@ -1,6 +1,6 @@ # 报关资料与船期价格接入梳理 -> **当前用途:报关与船期价格专题参考。** 报关流程已经确认,代码已进入第一批开发;开发交接看[报关代码开发交接清单](../头程到尾程/报关代码开发交接清单.md)。主流程和节点关系以[头程到尾程流程节点梳理](../头程到尾程流程节点梳理.md)为准;本文保留资料字段、回执轮次、价格口径和接口查找信息。 +> **当前用途:报关与船期价格专题参考。** 报关流程已经确认,第一批代码和页面已经接入测试环境;开发交接看[报关代码开发交接清单](../头程到尾程/报关代码开发交接清单.md)。主流程和节点关系以[头程到尾程流程节点梳理](../头程到尾程流程节点梳理.md)为准;本文保留资料字段、回执轮次、价格口径和接口查找信息。 > > 文中“目标、实施顺序、进入条件、待确认事项”等段落属于原评审记录。开发已经完成后,不再据此重新拆开发任务;若与当前确认不一致,以总览和最新业务确认修正对应专题段落。 @@ -8,7 +8,22 @@ **当前基线**:以最新用户确认和[头程到尾程流程节点梳理](../头程到尾程流程节点梳理.md)为准。旧版需求表、README、开发规划和本文件中的历史建议若发生冲突,先在当前入口记录收尾变更,再决定是否需要修改专题细节。 -**当前实现快照(2026-09-26)**:两份文件链路已经落到平台、客户和 Firstleg 报关接口:客户资料、报关行回执、客户整份回执确认/打回、平台发送报关行执行、真实报关完税文件分别保存并受版本门禁控制。回执发送给报关行后不可再替换;只有包含退税货物的柜才允许走发送执行接口;全买单柜仍走平台直接完成。`brokerSubmittedAt` 只表示发送执行时间,不表示报关完成。PDA 只负责产生 `LOADED` 前置事实,报关验收不创建或操作 PDA 任务;船期、甩柜和改配只修改原柜运输信息,不重置报关资料和确认结果。 +**当前实现快照(2026-09-29)**:两份文件链路已经落到平台、客户和 Firstleg 报关接口,客户端“报关资料”和“船期价格”也已经作为独立模块接入导航和路由。客户资料、报关行回执、客户整份回执确认/打回、平台发送报关行执行、真实报关完税文件分别保存并受版本门禁控制。回执发送给报关行后不可再替换;只有包含退税货物的柜才允许走发送执行接口;全买单柜仍走平台直接完成。`brokerSubmittedAt` 只表示发送执行时间,不表示报关完成。PDA 只负责产生 `LOADED` 前置事实,报关验收不创建或操作 PDA 任务;船期、甩柜和改配只修改原柜运输信息,不重置报关资料和确认结果。 + +## 当前差异与下一步 + +当前主流程和代码的关系已经收敛:F01-F24(国内头程、报关、待发区、送港、进港、甩柜和实际开航)有最新真实 HTTP 证据;F25-F40(目的港、海外入库、库存、出库、派送和最终回写)已有综合真实 HTTP 证据和页面实现。客户端两个独立模块、订单快捷入口、平台整柜报关工作台和船期价格查询均已接入,不需要再按“新增页面”拆任务。 + +2026-09-29 的最新综合 F01-F40 验收报告为 `baiyue-firstleg/reports/fba-full-current-20260929.json`。报告前段业务链大量通过,但尾程和海外 PDA 产生了环境型阻断:`test-api-overseas.buggoglobal.com` 当时 DNS 不可解析,后续请求均为 `fetch failed`,因此这份报告不能作为全流程全绿结论,也不能据此判断报关或船期代码失败。此前报关专项 `customs-current-20260928.json`(543/543)和运输专项 `transport-current-20260929.json`(1036/1036)仍是当前可复用的绿色证据。 + +当前状态分为三类任务: + +1. **规则已简化并确认**:不维护资料类型清单,也不区分逐项责任人;客户或平台只要在资料包上传文件即可。查验、扣货、补资料均由平台人工标记异常,选择预设理由;选择“其他”时填写备注即可,不要求接入短信或自动海关系统。 +2. **环境/外部验收**:恢复海外测试域名解析后重新跑 F25-F40;COSCO 官方接口凭据、COSCO 动态页面和 ZIM hCaptcha 仍是外部非阻断项;Android/HBuilderX 真机扫码、弱网和在线草稿仍需现场设备验收。 +3. **后续增强**:报关行接收回执/回执轮次和下载凭证仍可增强,但不影响当前两份文件闭环、客户确认、正式申报和报关完成后进入待发区。 +4. **费用默认确认**:业务规则已经确认,但代码仍主要完成费用发布/客户确认;`LOADED` 时按已装范围写入 `SYSTEM_AUTO_AT_LOADED`、费用版本、柜次/入仓码和幂等审计的落地实现,仍需单独补齐,不能把 `SENT` 直接当成默认确认。 + +你当前不需要先操作系统或确认代码。资料上传和异常人工处理规则已经足够继续开发;其余技术修复和重新验收由开发侧继续处理。 ## 先锁定的范围 @@ -21,28 +36,28 @@ 费用确认是并行事实,不阻断排柜、预装、PDA 或装柜。装柜完成后,对应已实装范围若客户仍未确认当前有效且已发布费用版本,系统记录“系统默认确认(装柜完成)”;不伪造客户点击,保留 `SYSTEM_AUTO_AT_LOADED` 来源、费用版本、柜次/入仓码、时间和幂等标识。没有有效费用版本时不得生成零额或伪造确认,须保留费用异常待办。 -出仓后的实际装船、提单、舱单、结关、退税正式资料和船公司节点查询属于后续或海外仓业务事实,不作为本期国内货柜履约页面、接口和验收范围。若国内页面需要展示,只能消费已确认的跨服务只读快照,并单独定义事件、来源、更新时间和责任边界。 +实际装船、提单、舱单、结关、退税正式资料和船公司节点查询仍属于跨服务或外部业务事实;当前国内货柜链已实现本柜船期编辑、送港、进港和实际开航节点,外部船公司自动查询以及更复杂的提单/舱单凭证继续按独立来源和只读快照接入。若国内页面需要展示,只能消费已确认的跨服务只读快照,并单独定义事件、来源、更新时间和责任边界。 ## 入口与权威数据 | 入口 | 本期职责 | 权威数据 | 当前状态 | |---|---|---|---| -| 客户端“报关资料” | `LOADED` 后查看本企业资料包,上传/替换/补件,查看报关行回执并确认或打回 | Firstleg 报关协同;文件由 File 服务保存 | **目标新增独立入口** | +| 客户端“报关资料” | `LOADED` 后查看本企业资料包,上传/替换/补件,查看报关行回执并确认或打回 | Firstleg 报关协同;文件由 File 服务保存 | **已实现:独立入口 + 订单快捷入口** | | 订单中的“上传资料” | 带订单和入仓码上下文进入同一资料包 | 与独立入口共用 packageId 和接口 | **现有快捷入口** | -| 平台整柜报关工作台 | 按实际装柜清单通知报关行,管理客户资料、回执轮次、全部确认、整柜正式提交和海关结果 | Firstleg 柜级报关与提交批次 | **已有四态,需收敛新投影** | -| 客户端“船期价格” | 查询当前企业可见的有效渠道、参考船期、最晚进仓、参考时效和估价 | 生效价格簿及服务端估价 | **建议新增独立入口** | +| 平台整柜报关工作台 | 按实际装柜清单通知报关行,管理客户资料、回执轮次、全部确认、整柜正式提交和海关结果 | Firstleg 柜级报关、提交批次和结果事实 | **已实现:四态 + 独立正式申报/海关结果投影** | +| 客户端“船期价格” | 查询当前企业可见的有效渠道、参考船期、最晚进仓、参考时效和估价 | 生效价格簿及服务端估价 | **已实现:独立入口** | | 平台“船期价格表” | 上传、解析、核对、发布公共或客户专属价格簿 | Firstleg 价格簿版本 | **已有平台能力** | 平台端应写“按申报组整理并线下提交”。在跨客户合并规则确认前,默认禁止把不同客户放入同一正式报关单;不得在结论表中把待决规则写成既定能力。 ## 当前实现事实 -1. 客户端当前通过订单接口查询报关资料,现状主要只对服务端确认已完成装柜的退税订单开放;本目标稿调整为 `LOADED` 后启动本柜报关批次,按客户/入仓码收集资料、接收报关行回执、提交客户确认并支持打回重做。资料可上传、替换、改关联、删除并保留版本;每轮发送和回执都要留痕,客户确认后才进入该客户的 `CUSTOMER_CONFIRMED`。对应接口和权限见 [customs-v1.yaml](../../baiyue-firstleg/firstleg/src/main/resources/openapi/customs-v1.yaml#L48)。 -2. 当前柜级状态为 WAITING_CUSTOMER_DOCUMENTS → READY_TO_START → DECLARING → COMPLETED;目标需要增加客户确认轮次、整柜正式提交、查验/放行和送港子状态。资料关联以 loadingPlanId、柜级聚合、客户报关案例和整票入仓码为根。 +1. 客户端现在同时提供独立“报关资料”入口和订单快捷入口,二者共用同一资料包和版本历史;仅对 `LOADED` 后的退税订单开放,按客户/入仓码收集资料、接收报关行回执、提交客户确认并支持打回重做。资料可上传、替换、改关联、删除并保留版本;每轮发送和回执都留痕,客户确认后才进入该客户的 `CUSTOMER_CONFIRMED`。对应接口和权限见 [customs-v1.yaml](../../baiyue-firstleg/firstleg/src/main/resources/openapi/customs-v1.yaml#L48)。 +2. 当前柜级状态为 WAITING_CUSTOMER_DOCUMENTS → READY_TO_START → DECLARING → COMPLETED;客户确认轮次、首次发送批次、整柜正式提交、查验/放行和送港子状态通过独立事实和只读投影承载。资料关联以 loadingPlanId、柜级聚合、客户报关案例和整票入仓码为根。 3. 当前 COMPLETED 会发布报关完成事件并参与待发区门禁。契约将“客户资料确认轮次”“整柜正式提交”“海关查验/放行”分开;报关完成后才允许进入待发区,船期事实独立维护。 -4. 全买单柜已有独立的二次确认接口和导出契约,本期继续保留;需要补齐其在客户确认轮次、整柜正式申报、海关结果和送港/开船状态中的位置。 +4. 全买单柜已有独立的二次确认接口和导出契约;它不创建退税客户资料、回执和确认案例,运输节点仍按装柜、待发区、送港和开船事实推进。 5. 客户端现有价格接口为按起运仓查询渠道,以及按指定渠道估算参考费用。/estimate 只返回基础参考费用,不含复杂附加费和最终结算调整;pricingTaxMode 不等同于订单 taxMode。见 [fba-pricing-v1.yaml](../../baiyue-firstleg/firstleg/src/main/resources/openapi/fba-pricing-v1.yaml#L130)。 -6. 仓库内原型与页面索引仍将报关上传、回执下载和出仓前船期资料列为待原型或部分参考;页面范围需同步 [国内货柜履约页面与原型清单.md](国内货柜履约页面与原型清单.md#L30)。 +6. 原型文档仍有“待原型/部分参考”的历史表述,但当前页面已按现行契约接入;页面范围以客户端路由、平台报关工作台和当前 OpenAPI 为准,不再把原型中的待建入口当作开发缺口。 7. **费用默认确认目前是目标变更,不是现有实现。** 当前装柜完成逻辑只会自动发送/发布费用,不能把 `SENT` 直接当成客户确认;现有费用锁定也主要依赖客户确认时间。实现本轮目标时必须增加确认来源和幂等审计,并改为“客户确认或装柜默认确认 + 已装柜完成后才最终锁定”。部分装载只能确认本次已装范围,余量不能被顺手确认。 @@ -63,7 +78,7 @@ ### 1. 客户报关案例与资料包 -报关资料主流程在 `LOADED` 后启动。每个客户/入仓码在本柜建立一个 `customerCustomsCase`,再挂载稳定的 `packageId` 和文件版本。案例至少记录:订单/子订单、入仓码或入仓明细、实际装箱数展示、资料清单版本、每个清单项的文件版本、报关行发送时间、回执文件版本、客户确认/打回人和时间、打回原因、当前 `roundNo`、客户可见范围和审计记录。 +报关资料主流程在 `LOADED` 后启动。每个客户/入仓码在本柜建立一个 `customerCustomsCase`,再挂载稳定的 `packageId` 和文件版本。首期不定义文件类型清单和逐项责任人;资料包只需支持文件上传、替换、版本、报关行发送时间、回执文件版本、客户确认/打回人和时间、打回原因、当前 `roundNo`、客户可见范围和审计记录。 资料包不能只关联整票入仓码。已确认支持一单多柜、拆批和父订单—子订单关系,因此每个关联项保存客户、订单、入仓码和装柜明细引用;部分装柜只展示本柜实际箱数并标记线下处理,不在系统内自动做数量分摊。柜次一旦装柜完成不因甩柜改船而变化,受影响案例不能静默重置回执轮次。 @@ -100,7 +115,7 @@ | 送港/船期事实 | PORT_DELIVERY_PENDING、DEPARTED_WAREHOUSE、IN_TRANSIT_TO_PORT、PORT_RECEIVED、ROLLED_OVER、VESSEL_DEPARTED | 与报关案例独立;进港和甩柜不等于海运中,只有真实开船才进入海运节点 | | 装柜门禁 | PASS/BLOCKED | 只判断是否满足 LOADED 的已确认前置 | -上述是首期状态投影。回执首期以文件为主、客户确认整份回执;正式申报由平台授权人员人工提交并回填结果;实际开航首期人工录入,甩柜/改配人工修改原柜船信息并保留原报关事实,不重新评估申报批次。其余稳定编码、退回/重开规则和责任人仍需在开发前确认。当前四态不能直接承担新流程;收敛时应明确旧状态的映射和删除时点,不保留双协议。 +上述是首期状态投影。回执首期以文件为主、客户确认整份回执;正式申报由平台授权人员人工提交并回填结果;查验、扣货、补资料和其他情况均由平台人工点击标记异常、选择理由,选择“其他”时填写备注;异常解除也由平台人工点击处理。实际开航首期人工录入,甩柜/改配人工修改原柜船信息并保留原报关事实,不重新评估申报批次。当前四态不能直接承担新流程;收敛时应明确旧状态的映射和删除时点,不保留双协议。 物理 `LOADED` 门禁必须明确校验以下事实: @@ -142,19 +157,19 @@ ## 实施顺序与进入条件 -1. **冻结业务规则**:确认客户资料清单、回执轮次、打回重做、所有客户确认、整柜正式申报、查验/放行、甩柜/改配和跨客户合并;已确认规则以[需求确认表](国内货柜履约需求确认表.md#L24)为准。 +1. **冻结业务规则**:确认文件可上传即可、回执轮次、打回重做、所有客户确认、整柜正式申报、异常理由/备注、甩柜/改配和跨客户合并;已确认规则以[需求确认表](国内货柜履约需求确认表.md#L24)为准。 2. **先做服务端契约**:完成 customerCustomsCase、资料版本、报关行回执轮次、客户确认、整柜申报批次、送港/进港/甩柜/开船事实、状态投影、权限、幂等、审计、File 类别和初始化 SQL;同步更新 OpenAPI、Gateway、IAM 和相关消费者。 3. **接入客户入口**:独立列表/详情与订单快捷入口共用 packageId;仅在 `LOADED` 后进入本柜报关案例,覆盖资料上传、报关行回执查看、确认、打回、重新上传和新回执版本。 -4. **接入平台协同**:`LOADED` 后按最终实装快照通知报关行,逐客户处理资料和回执,全部客户确认后提交整柜资料;人工记录正式申报、查验、不查验放行和其他结果。送港线独立接入拖车、进港、甩柜和实际开船。 +4. **接入平台协同**:`LOADED` 后按最终实装快照通知报关行,逐客户处理资料和回执,全部客户确认后提交整柜资料;平台人工记录正式申报,并通过异常节点选择查验、扣货、补资料或其他理由,必要时填写备注和处理结果。送港线独立接入拖车、进港、甩柜和实际开船。 5. **接入船期价格**:先复用有效价格簿和单渠道参考估价,再实现批量估价;批量列表、排序和导出必须先通过接口和价格可比性评审。 -## 待确认事项 +## 已确认的简化规则 | 问题 | 阻断范围 | 需要形成的结论 | |---|---|---| -| 资料清单具体项目、条件规则和版本生效方式 | 清单、审核、补件 | 首版人工维护清单及版本负责人 | +| 报关资料上传 | 客户案例、整柜提交 | 不区分文件类型;有文件即可上传、替换和保留版本 | | 客户确认/打回原因和回执轮次 | 客户案例、整柜提交 | 回执版本、roundNo、确认人、打回重做规则 | -| 海关查验、不查验放行、扣货/补件等正式结果 | 整柜申报批次、客户展示 | 结果类型、凭证、来源、客户可见范围和责任人 | +| 海关查验、扣货、补资料和其他异常 | 整柜申报批次、客户展示 | 平台人工标记异常并选择理由;选择“其他”时填写备注,不接短信或自动海关系统 | | 送港、进港、甩柜、改配船次和实际开船事件 | 待发区、送港线、海运节点 | 事实字段、重试规则、客户通知和船次历史;首期人工录入实际开航,改配人工修改原柜船信息但不改变已完成报关事实 | | 价格比较、导出、报价有效期和金额变化提示 | 客户报价页、下单 | 统一币种/税模式/附加费和失效处理 | diff --git a/头程到尾程/README.md b/头程到尾程/README.md index 514137c..112637d 100644 --- a/头程到尾程/README.md +++ b/头程到尾程/README.md @@ -1,6 +1,6 @@ # 头程到尾程当前维护入口 -这里集中列出后续流程变更需要查找和修改的文档。整体流程基线已确认,除报关协同代码外进入收尾;日常只从本目录进入,历史开发材料统一放在[文档归档](../归档/README.md)。 +这里集中列出 F01-F40 全流程变更需要查找和修改的文档。报关协同代码已接入并通过真实 HTTP 验收,当前进入全流程状态与页面证据收尾;日常只从本目录进入,历史开发材料统一放在[文档归档](../归档/README.md)。 ## 当前流程文档 @@ -10,9 +10,9 @@ | 分段流程 | [头程到尾程分阶段流程](../头程到尾程分阶段流程/README.md) | 六个阶段的字段、页面操作、权限、状态和异常 | | 货柜入口 | [国内货柜履约 README](../国内货柜履约/README.md) | 分柜、装柜、报关协同、送港和进港的货柜范围 | | 报关与船期专题 | [报关资料与船期价格接入梳理](../国内货柜履约/报关资料与船期价格接入梳理.md) | 客户资料、报关行回执、客户确认/打回、正式申报、海关结果和船期价格 | -| 报关开发交接 | [报关代码开发交接清单](报关代码开发交接清单.md) | 当前未完成的报关代码范围、完成条件和开发入口 | +| 报关开发交接 | [报关代码开发交接清单](报关代码开发交接清单.md) | 报关代码完成条件、已验收范围和后续增强项 | | 头程与报关交互矩阵 | [头程节点与报关清关交互矩阵](头程节点与报关清关交互矩阵.md) | F01-F24 各节点的客户、平台、PDA、报关行和船期交互 | -| 第一阶段冻结矩阵 | [头程至实际开船节点冻结矩阵与缺口清单](头程至实际开船节点冻结矩阵与缺口清单.md) | F01-F24 节点、报关完成进入待发区、当前实现缺口和开发前确认项 | +| 全流程实现对照 | [全流程节点矩阵与缺口清单](头程至实际开船节点冻结矩阵与缺口清单.md) | F01-F40 节点、现行规则、实现差异和验证边界;保留原文件路径 | | 正式申报与海关结果 | [正式申报与海关结果接入设计](正式申报与海关结果接入设计.md) | F22.7 正式申报批次、报关单号、F22.8 查验/补资料/放行/扣货/其他结果及三端边界 | | 甩柜改配接入设计 | [甩柜改配接入设计](甩柜改配接入设计.md) | F23.3 原柜人工修改船信息并保留修改历史 | diff --git a/头程到尾程/头程至实际开船节点冻结矩阵与缺口清单.md b/头程到尾程/头程至实际开船节点冻结矩阵与缺口清单.md index c31bcdb..896c2fd 100644 --- a/头程到尾程/头程至实际开船节点冻结矩阵与缺口清单.md +++ b/头程到尾程/头程至实际开船节点冻结矩阵与缺口清单.md @@ -1,12 +1,12 @@ -# 头程至实际开船节点冻结矩阵与缺口清单 +# 全流程节点矩阵与缺口清单 -本文按当前确认结果冻结第一阶段范围:从头程下单开始,完成国内履约、报关协同、送港运输,并记录承运船舶实际开航。尾程入库、派送和签收不在本阶段实现。流程基线同时采用《报关代码开发交接清单》和《头程到尾程流程节点梳理》;原型只用于页面字段和承载方式参考。 +本文按当前确认结果冻结 F01-F40 全流程范围:从头程下单开始,完成国内履约、报关协同、送港运输、实际开航、海外入库、出库和最终回写。F01-F24 是国内头程至实际开航的前段,F25-F40 是海运目的港及尾程履约。流程基线同时采用《报关代码开发交接清单》和《头程到尾程流程节点梳理》;原型只用于页面字段和承载方式参考。 ## 一、阶段边界 ```text 头程下单 - F01-F13:下单、审核、到仓、测量、计费、费用确认、组托、待分柜 + F01-F13:下单、审核、到仓、测量、计费、费用确认、国内扣货/解除、组托、待分柜 国内货柜履约 F14-F21:分柜、订舱、拖车、拣货、装柜、LOADED 报关完成后进入待发区 @@ -14,38 +14,82 @@ F23:待发区、送港、进港、甩柜、改配 海运起点 F24:承运船舶实际开航 +目的港与海外入库 + F25-F30:目的港处理、尾程订单、入仓计划、接柜、收货、库存入账 +海外库存与出库 + F31-F37:库内操作、暂扣、库内服务、排车、生成出库/派送单、拣货发车、出库 +派送与完成 + F38-F40:签收、异常退回、回访和完成回写 ``` -本阶段的终点是实际开航事实,不是“报关完成”、国内离仓、目的港清关或海外入仓。`LOADED` 只表示物理装柜完成;报关完成是进入待发区的前置条件,待发区和船期节点分别保存,不能把其中一条线的结果写成另一条线的结果。 +国内前段 F01-F24 的终点是实际开航,全流程继续至 F40;其中 F37 为海外出库。`LOADED` 只表示物理装柜完成;报关完成是进入待发区的前置条件,待发区和船期节点分别保存,不能把其中一条线的结果写成另一条线的结果。 -## 二、F01-F24 节点冻结矩阵 +### 实现与验证口径 + +“已有实现”不等于最新版本已完成验收。下表的既有 HTTP 证据只证明对应报告范围与版本;历史通过不能替代当前完整链路、页面或 PDA 现场验证。报关和运输专项的通过也不能外推为 F01-F40 全部通过。后续增强项不作为首期主流程缺失处理。 + +2026-09-29 修复后的默认全量真实 HTTP 回归已通过:Admin 11,627 项检查、120 个模块、7,429 次请求,0 失败、0 跳过模块;Client 195 项检查全部通过。F31 换托同库位比较、A0 共享溢出位移库、F33 无贴标转仓查询及跨服务错误处理已修复并部署测试环境;验收脚本补齐直接贴标审核、返工重新领取及禁止回移虚拟收货位的边界。离线合同 128 个文件、773 项断言全部通过。 + +同票普通 FBA 主链证据为入仓码 `NYEXX2609290171`、柜次 `D1063`、柜号 `TSTU3425326`、排车单 `DS-WH-20260929-067073`、出库单 `OB-WH-20260929-158402`;两张目的仓派送单签收后,已核对来源入仓单 `DELIVERED` 和来源订单 `COMPLETED`。随后故意执行的退回异常测试会改变留存单据状态,不能把最终留存状态误读成未曾完成。退税报关分支另由同一全量报告中的混合柜检查覆盖,不冒充同一票退税至签收证据。 + +对应证据:`baiyue-firstleg/reports/admin-full-current-20260929-r7.json`、`reports/client-full-current-20260929-r3/client-test-env-20260929063613-e54d44dd.json`、`reports/fba-main-chain-evidence-20260929.json`(后两个路径同属后端仓库)。Admin/Client 报关详情已按 1920×1080 页面核对;船期日历网络恢复后重载正常。未离仓测试柜 `TSTU7897110` 已实际验证首次发送、普通文本回执上传、客户确认后的平台执行、正式申报、其他理由必填备注、异常保存与人工处理;客户确认通过该客户自己的 HTTP 接口完成。异常处理后回执确认保留,未上传完税文件仍保持报关中并阻断离仓。 + +页面复验发现并修复异常发生时间早 8 小时的问题:国内 `LocalDateTime` 接口改为接收上海业务时间。Admin 提交 `4ead51a5feedf65be9443ddfe3dd45da7ca49e64` 已通过测试环境 Jenkins #482 部署;262 个测试文件、2,121 项测试和构建通过。部署后真实页面新增查验记录的发生时间与服务器记录时间相差 0.879 秒。详见后端仓库 `reports/customs-time-postdeploy-20260929.json` 和 `reports/customs-other-resolved-1920-20260929.jpg`。Android 真机、弱网和外部船司正式凭据仍属于单列验证边界,不纳入本次内置浏览器与 HTTP 通过结论。 + +## 二、F01-F40 节点冻结矩阵 | 节点 | 客户可见进度 | 后台业务对象 | 必须形成的真实事实 | 当前状态 | 本阶段缺口 | |---|---|---|---|---|---| | F01-F07 | 待下单、审核中、已审核 | 企业、订单、审核任务 | 提交、补件、审核、入仓单生成 | 已有主链 | 按现有订单契约回归,不在本轮重做 | | F08-F10 | 待到仓、测量中、待确认 | 入仓单、测量记录 | 收货、扫码、称重、测量、审核 | 已有主链 | 只核对是否能稳定产出排柜事实 | -| F11-F13 | 费用待确认、待组托、待分柜 | 费用版本、确认记录、托盘 | 计费推送、客户确认、组托/封托 | 已确认并行规则 | 保证费用默认确认不能冒充报关确认 | +| F11 | 费用待确认 | 费用版本、客户确认记录 | 计费推送、客户主动确认、版本留痕 | 已有实现;旧总览的默认确认表述与阶段二及服务指引冲突 | 按现行规则,装柜可自动发布费用,但不能代替客户确认;不将缺少 `SYSTEM_AUTO_AT_LOADED` 列为必修代码缺陷 | +| F12 | 国内扣货中、已解除 | 国内入仓单 HOLD 记录 | 扣货、解除、原因和后续作业门禁 | 已实现;最新全量 inbound-hold 模块通过 | 与报关海关异常、海外库存暂扣分别维护,不能混为同一节点 | +| F13 | 待组托、待分柜 | 一件代发清点、托盘和封托记录 | 逐箱清点、归托、封托 | 已有主链 | 结合一件代发路径验证;不要求普通散货重复执行一件代发清点流程 | | F14-F20 | 待分柜、订舱中、装柜中 | 柜次、装柜计划、拖车、PDA 任务 | 分柜、订舱、排车、拣货、照片、铅封、数量核对 | 主链已有 | 核对真实柜号、订舱和装柜快照能否冻结 | | F21 | 国内已装柜 | 装柜计划、物理货柜、装柜证据 | 实际柜号、实装箱数、装柜证据、`LOADED` | 已有 | 报关案例按最终实装范围建立;部分装柜只显示已装箱数并标记线下处理,不在系统内自动分摊 | | F22.1 | 报关确认中 | 柜级报关聚合内的客户资料范围 | 每客户范围、入仓码范围、混合柜隔离、实装范围回显 | 已实现并通过真实 HTTP 验收 | 独立“案例”对象仍可在正式批次设计时补充;部分装柜仍线下处理 | -| F22.2 | 待提交资料、待补资料 | 客户资料包 | 上传、替换、关联范围、版本、冻结 | 已实现并通过真实 HTTP 验收 | 资料类型化清单和补件原因待补 | +| F22.2 | 待提交资料、待补资料 | 客户资料包 | 上传、替换、关联范围、版本、冻结 | 已实现并通过真实 HTTP 验收 | 首期不维护资料类型清单;有文件即可上传,补件通过人工异常理由和备注说明 | | F22.3 | 已发送报关行 | 独立首次发送批次 `brokerSubmission` | 业务批次号、发送人、发送时间、冻结版本、资料快照、幂等历史 | 已实现并通过定向测试与测试环境部署 | 报关行接收确认和回执轮次对象待补 | | F22.4 | 待客户确认 | 回执/完成文件版本 | 文件版本、关联客户范围、客户可下载 | 已实现;回执历史和确认动作历史均只读投影 | 独立回执返回时间/下载凭证仍待补 | | F22.5 | 客户确认中、已打回 | 客户确认记录与动作历史 | 确认/打回、回执版本、操作人、时间、原因 | 已实现并通过定向测试与测试环境部署 | 通知聚合和报关行回执轮次待补 | -| F22.6 | 等待整柜确认 | 完税文件齐全门禁 | 所有退税客户确认、发送执行、真实完税文件齐全 | 已实现并通过专项真实 HTTP 验收 | 复杂结果凭证和补资料专项门禁待补 | -| F22.7 | 已提交正式申报 | 正式申报批次 | 报关行确认、正式申报时间、操作人、批次、报关单号 | 已实现并通过真实 HTTP 7 步联调 | 后续补更复杂的结果凭证类型 | -| F22.8 | 查验中、待补资料、已放行、扣货/其他 | 海关结果事实 | 报关单号、结果类型、时间、凭证、处理结果 | 已实现并通过真实 HTTP 7 步联调 | 后续补查验/扣货/补资料专项场景的更细验收 | +| F22.6 | 等待整柜确认 | 完税文件齐全门禁 | 所有退税客户确认、发送执行、真实完税文件齐全 | 已实现并通过专项真实 HTTP 验收 | 查验、扣货、补资料作为平台人工异常节点处理,不新增自动凭证门禁 | +| F22.7 | 已提交正式申报 | 正式申报批次 | 报关行确认、正式申报时间、操作人、批次、报关单号 | 已实现并通过真实 HTTP 7 步联调 | 后续可补报关行接收时间和下载凭证 | +| F22.8 | 查验中、待补资料、已放行、扣货/其他 | 海关结果事实 | 报关单号、结果类型、时间、人工理由、备注和处理结果 | 已实现;真实 HTTP 与人工异常页面保存/处理通过,发生时间偏差已修复并部署复验 | 不接短信或自动海关系统;真机及外部系统不在页面验证范围 | | F23.1 | 待发区、送港中、已离仓 | 待发区与送港/出仓任务 | 报关完成时间、待发区门禁、离仓时间、车辆/任务、操作人、证据 | 已实现并通过真实 HTTP 验收 | 继续补待发区客户/平台投影展示 | -| F23.2 | 已送港、已进港 | 运输和港口事实 | 送港时间、进港时间、来源和凭证 | 部分已有 | 与订舱、拖车和船次事实统一读写 | +| F23.2 | 已送港、已进港 | 运输和港口事实 | 送港时间、进港时间、来源和凭证 | 已实现;已有真实 HTTP 证据 | 继续补充最新页面证据,并保持与订舱、拖车和船次事实统一读写 | | F23.3 | 已甩柜、等待改船后承运 | 船期记录修改历史 | 甩柜原因、发生时间、修改前后船名/航次/船期、处理人 | 已实现并通过测试环境真实 HTTP;平台与客户端最新船期投影一致 | 继续补页面截图和更复杂异常分支;柜次、订舱关联和报关事实不变 | -| F24 | 海运中 | 船次实际节点 | 承运船舶、航次、实际开航时间、来源/凭证 | 基础已有 | 只允许实际开航事实推进海运节点 | +| F24 | 海运中 | 船次实际节点 | 承运船舶、航次、实际开航时间、来源/凭证 | 已实现;实际节点与查询任务已有真实 HTTP 证据 | 继续补充最新一轮页面证据;只允许实际开航事实推进海运节点 | +| F25 | 目的港处理中、待海外接柜 | 船节点、目的港清关/提柜、尾程订单 | 到港、卸船、清关、提柜和可接柜事实 | 已实现并有综合真实 HTTP 证据 | 外部码头/车队差异继续按异常分支补充 | +| F26 | 尾程订单待建计划 | 跨区事件、尾程订单 | 装柜完成、船节点和来源入仓单快照可靠投递与消费 | 已实现并有综合真实 HTTP 证据 | 继续观察跨区事件延迟和补偿告警 | +| F27 | 待建立海外入仓计划 | 入仓计划、计划托盘和资源锁 | 按柜内每票生成计划、预计到仓和托盘资源冻结 | 已实现并有综合真实 HTTP 证据 | 继续补齐异常重试页面证据 | +| F28 | 待接柜、接柜中 | 海外 PDA 接柜会话 | 柜号认领、三类签收照片和签收确认 | 已实现并有综合真实 HTTP 证据 | Android 真机验收仍是独立非阻塞项 | +| F29 | 入库中 | 海外 PDA 收货任务 | FBA 散货、海外仓逐箱、一件代发整托等实收事实 | 已实现并有综合真实 HTTP 证据 | 继续补充现场设备和弱网证据 | +| F30 | 入库完成 | 入库任务、库存和跨区回写事件 | 全柜核平、库存同事务入账、卸柜完成事件 | 已实现并有综合真实 HTTP 证据 | 保持事件幂等和库存数量守恒 | +| F31 | 库存可用、库内服务中 | 库存、库位、托盘、盘点 | 上架、移库、合托/拆托、盘点和库存流水 | 已实现并有综合真实 HTTP 证据 | 继续补充大批量库存性能验收 | +| F32 | 暂扣中、已解除 | 暂扣记录和库存锁 | 暂扣原因、解除原因、操作人和库存可用性变化 | 已实现并有综合真实 HTTP 证据 | 暂扣与出库并发场景继续补充 | +| F33 | 换标/转运/废弃处理中 | 换标、转运、废弃子单 | 客户确认、箱唛/托盘变更、库存锁和实际扣减事实 | 已实现并有综合真实 HTTP 证据 | 继续补充复杂返工和跨仓异常 | +| F34 | 待派送、排车中 | 智能预排、排车单 | 候选、草稿锁、正式排车和目的仓分配 | 已实现并有综合真实 HTTP 证据 | 继续补充多车多目的仓页面证据 | +| F35 | 待转派送、待出库 | 排车转派送、出库单、派送单 | 出库/派送单生成、目的仓拆分、费用只发布一次 | 已实现并有综合真实 HTTP 证据 | 保持转派送前不可发车 | +| F36 | 拣货中、待发车 | 海外 PDA 排车任务 | 托盘扫描、数量核平、车辆资料和发车门禁 | 已实现并有综合真实 HTTP 证据 | Android 真机和弱网恢复仍需专项验证 | +| F37 | 已出库、派送中 | 出库单、派送单 | 出库完成、库存扣减和派送任务关联 | 已实现并有综合真实 HTTP 证据 | 继续补跨目的仓汇总展示 | +| F38 | 派送中、已签收 | 派送单、签收凭证 | 签收文件、签收时间和每个目的仓派送完成 | 已实现并有综合真实 HTTP 证据 | 继续补异常签收凭证类型 | +| F39 | 异常退回处理中 | 异常单、退回入仓和库存恢复 | 拒收/部分拒收、退回、库存恢复和原因历史 | 已实现并有综合真实 HTTP 证据 | 继续补多次退回和部分恢复组合场景 | +| F40 | 已完成、待回访 | 客户回访、跨区完成事件、订单回写 | 回访记录、`DELIVERED` 回写及订单 `COMPLETED` 收口 | 已实现并有综合真实 HTTP 证据 | 继续补跨区延迟时的客服投影 | ## 三、当前实现与目标的主要断点 -### 1. 报关数据模型已支持客户范围,发送批次仍需独立建模 +### 1. 客户范围和首次发送批次已落地,回执轮次属于后续增强 当前 `fl_customs_container` 仍是柜级状态聚合,但客户资料通过客户和入仓码范围隔离,真实验收已覆盖同柜多客户和混合柜。正式申报批次、海关结果事实、首次发送报关行批次和客户确认动作历史已经独立落地;尚未独立建模的是报关行接收回执、回执轮次和更细的客户案例聚合。 +### 1.1 费用自动发布与客户确认必须区分 + +阶段二“费用计费与确认”和 `baiyue-firstleg/firstleg/AGENTS.md` 明确规定:费用不阻断排柜和装柜,装柜完成不得代替客户自动确认,客户确认与本票装柜完成共同构成最终冻结条件。`FbaPricingService.autoSendAfterLoadingCompleted` 执行平台费用确认与发送,`confirmByCustomer` 才记录客户确认人和时间;`SENT` 不等于客户确认。旧总览要求 `SYSTEM_AUTO_AT_LOADED` 的表述与现行规则冲突,不能据此直接新增自动代客确认。若未来明确改变该规则,再同步费用版本、确认来源和冻结边界。 + +### 1.2 海关异常按人工节点处理 + +海关短信由平台人员人工查看和操作,系统不接短信、不自动判断查验或扣货。平台在正式申报批次上人工标记异常,选择“查验”“扣货”“补资料”或“其他”等理由;选择“其他”时填写备注,后续由平台人员人工解除或录入处理结果。异常是申报批次上的附加事实,不改变已上传资料、回执和客户确认历史。 + 目标至少需要以下关系: ```text @@ -86,14 +130,14 @@ - 按客户查看案例和实际装柜覆盖; - 报关行接收回执和回执轮次管理; -- 更细的查验、扣货、补资料和其他结果凭证历史。 +- 报关行接收回执时间和下载凭证等更细历史。 ## 四、接口、权限、审计和测试缺口 ### 接口与数据库 - OpenAPI 不能继续只暴露旧的四态 `ContainerView`。 -- 需要继续补充报关行接收回执、回执轮次、下载凭证及更复杂结果凭证的查询/命令契约;资料包、首次发送批次、回执版本和确认动作只读历史、整柜申报和海关结果基础契约已落地。 +- 需要继续补充报关行接收回执、回执轮次和下载凭证的查询/命令契约;资料包、首次发送批次、回执版本和确认动作只读历史、整柜申报和海关结果基础契约已落地。 - 文件仍由 File 服务保存,但每个文件必须绑定业务类型、客户案例/申报批次、版本和覆盖范围。 - 每个写命令都要带版本和幂等键;重放同参数返回原结果,不同参数返回冲突。 - 换柜时需要保留新旧柜关联;部分装柜只记录已装箱数和线下处理标记,不在系统内自动做数量分摊或覆盖旧资料。 @@ -110,7 +154,7 @@ ### 审计 -需要保留客户范围、资料版本、回执轮次、确认人、打回原因、提交批次、报关单号、结果凭证和操作时间。客户 A 的动作不能出现在客户 B 的案例中;柜级汇总可以看到客户名和业务编号,但客户端只能看到自身范围。 +需要保留客户范围、资料版本、回执轮次、确认人、打回原因、提交批次、报关单号、异常理由、备注和操作时间。客户 A 的动作不能出现在客户 B 的案例中;柜级汇总可以看到客户名和业务编号,但客户端只能看到自身范围。 ### 测试 @@ -127,9 +171,9 @@ 9. 客户越权读取同柜其他客户资料被拒绝。 10. 部分装柜能显示实际箱数并留下线下处理标记;换柜不能直接覆盖原案例和历史回执。 -## 五、开发前仍需业务确认 +## 五、后续增强(无需当前业务确认) -以下问题中,前四项已经由《报关代码开发交接清单》和《头程到尾程流程节点梳理》冻结,本轮又补充冻结了文件形态、部分装柜展示、回执确认、首期申报和实际开航/改配处理方式;表格后的内容仍需业务补充,不能由代码现状推断。 +以下内容不阻断当前开发:回执接收时间、回执轮次和下载凭证可以后续增强;海关短信、查验、扣货、补资料和其他异常按平台人工标记、选择理由和填写备注处理。 ### 已冻结的业务规则 @@ -151,14 +195,14 @@ | 资料继承 | 报关完成后资料、平台回执和客户确认与船期独立;甩柜/改配不触发重新上传或重新确认。 | | 航次任务 | 平台人工修改原柜船信息,继续使用原任务;保留修改历史和已有节点。 | -### 仍需补充的字段和操作规则 +### 已确认的字段和操作规则 -1. 首版资料清单具体项目、条件规则、版本生效方式和责任人是什么? -2. (已确认)第一版由平台人员直接修改原柜船名、航次和船期,填写原因并保留修改历史。 -3. (已确认)平台人工修改原柜船名、航次和船期;柜子与原任务不变。 -4. (已确认)原航次退税资料、回执和客户确认与船期独立,甩柜/改配不触发重新确认。 -5. (已确认)甩柜/改配与报关资料无关,不重新生成报关批次,不要求客户重新确认。 -6. 修改船信息不生成实际开航事实;只有本柜实际随船开航后才记录 `DEPARTED_ORIGIN_PORT`。 +1. (已确认)首期不维护资料类型清单和逐项责任人;资料包只要有文件即可上传、替换和留版本。 +2. (已确认)查验、扣货、补资料和其他结果由平台人员人工标记异常、选择理由;选择“其他”时填写备注,异常解除也由平台人工点击。 +3. (已确认)第一版由平台人员直接修改原柜船名、航次和船期,填写原因并保留修改历史。 +4. (已确认)平台人工修改原柜船名、航次和船期;柜子与原任务不变。 +5. (已确认)原航次退税资料、回执和客户确认与船期独立,甩柜/改配不触发重新确认。 +6. (已确认)修改船信息不生成实际开航事实;只有本柜实际随船开航后才记录 `DEPARTED_ORIGIN_PORT`。 ### 代码接入前置缺口 @@ -166,8 +210,8 @@ ## 六、冻结结论 -- 第一阶段覆盖 F01-F24,终点为实际开航。 +- 全流程基线覆盖 F01-F40;F01-F24 终点为实际开航,F25-F40 继续完成目的港、海外入库、出库、派送和最终回写。 - F22 报关完成后货柜进入 F23 待发区;甩柜/改配只改变运输航次,不改变报关事实。 - 客户确认、报关行回执、整柜正式申报、海关放行、离仓、进港、甩柜和实际开航都是独立事实。 -- 先完成节点矩阵、对象关系、状态投影、门禁和验收缺口确认,再进入代码设计。 -- 尾程 F25-F40 暂不纳入本阶段实现,但必须保留 F24 到目的港清关的接口衔接点。 +- 节点清单覆盖完整范围;各节点实现与验证程度以表内状态为准,不将整张矩阵标为全部验收完成。 +- F25-F40 已有实现,最新默认全量 HTTP 回归已通过,并核对同票签收后的国内完成回写;本轮报关可写异常页面操作已完成,设备和外部船司边界继续单列,不能用 HTTP 全绿替代这些证据。 diff --git a/头程到尾程/头程节点与报关清关交互矩阵.md b/头程到尾程/头程节点与报关清关交互矩阵.md index e4946b1..bb4598d 100644 --- a/头程到尾程/头程节点与报关清关交互矩阵.md +++ b/头程到尾程/头程节点与报关清关交互矩阵.md @@ -1,6 +1,6 @@ # 头程节点与报关清关交互矩阵 -> 本文把头程下单 F01-F24 与报关清关的客户、平台、报关行交互放在同一张图里。当前产品先覆盖国内头程到实际开航;尾程不在本轮。报关资料只适用于包含退税货物的柜,买单货物不创建客户资料协同。 +> 本文把 F01-F40 全流程中的头程、海运与报关清关交互放在同一张图里;其中 F01-F24 是国内头程到实际开航,F25-F40 由阶段四至阶段六继续承接。报关资料只适用于包含退税货物的柜,买单货物不创建客户资料协同。 ## 一、总链路 @@ -69,7 +69,7 @@ 仍需补齐: 1. 报关行接收确认、回执轮次和回执下载凭证的独立对象及更细历史投影。 -2. 待发区客户/平台投影的更细页面展示和截图证据;`LOADED → 报关 → 待发区` 已在既有混合柜报告中通过,平台与客户改船后的当前船期双端回读已验收。 +2. 待发区客户/平台投影的更细页面展示和截图证据;`LOADED → 报关 → 待发区` 已在混合柜报告中通过,平台与客户改船后的当前船期双端回读已验收。F25-F40 的海运目的港、海外入库、库存、出库、派送和最终回写由阶段四至阶段六维护,综合证据见 `baiyue-firstleg/reports/admin-overseas-chain-final-fixture-20260924.json`。 正式申报批次和海关结果已在本轮实现并通过真实 HTTP:平台创建/提交批次、录入查验、查询并处理结果,客户按自身订单查询结果;证据见 `baiyue-firstleg/reports/formal-customs-declaration-and-clearance-result-20260927.json`。 diff --git a/头程到尾程/报关代码开发交接清单.md b/头程到尾程/报关代码开发交接清单.md index 22c68a5..2c05c36 100644 --- a/头程到尾程/报关代码开发交接清单.md +++ b/头程到尾程/报关代码开发交接清单.md @@ -1,10 +1,10 @@ # 报关代码开发交接清单 -> **当前状态:第一阶段报关协同已接入测试环境。** 客户资料、首次发送报关行批次、回执、客户确认历史和真实完税文件已形成独立链路;报关行确认回执和更复杂结果凭证仍是后续补充项。第一阶段冻结范围和缺口以[头程至实际开船节点冻结矩阵与缺口清单](头程至实际开船节点冻结矩阵与缺口清单.md)为准;流程规则以[报关资料与船期价格接入梳理](../国内货柜履约/报关资料与船期价格接入梳理.md)为准,节点关系以[头程到尾程流程节点梳理](../头程到尾程流程节点梳理.md)为准。 +> **当前状态:报关协同已接入测试环境。** 客户资料、首次发送报关行批次、回执、客户确认历史和真实完税文件已形成独立链路;海关查验、扣货、补资料和其他结果由平台人员人工标记异常、选择理由并填写备注,不接短信或自动海关系统。报关行接收回执和下载凭证仍可后续增强。头程至尾程的全流程范围和缺口以[头程至实际开船节点冻结矩阵与缺口清单](头程至实际开船节点冻结矩阵与缺口清单.md)为准;流程规则以[报关资料与船期价格接入梳理](../国内货柜履约/报关资料与船期价格接入梳理.md)为准,节点关系以[头程到尾程流程节点梳理](../头程到尾程流程节点梳理.md)为准。 > **本轮补充确认:** 首期报关行回执以文件为主,客户确认整份回执;正式申报由平台授权人员人工提交并回填结果;报关完成后货柜进入待发区;实际开航首期人工录入,甩柜/改配只变更船期,不重新处理已完成报关资料。 -> **验收证据:** 既有全链路报告保留旧版 526/526、混合柜 532/532 记录;本轮新增代码、数据库和三端已部署,已用现有完成柜做接口烟测并核对首次发送门禁。完整造数到报关回归仍需要测试环境提供 PDA 作业员账号,当前 `test-acceptance.env` 缺少该变量,脚本按契约在装柜前置处停止。 +> **验收证据:** 既有全链路报告保留旧版 526/526、混合柜 532/532 记录;本轮新增代码、数据库和三端已部署,已用现有完成柜做接口烟测并核对首次发送门禁。完整造数到报关回归已补齐测试环境专用国内 PDA 作业员并通过;当前报关主链报告为 543/543,运输节点报告为 1036/1036。 ## 一、必须实现的报关流程 @@ -18,7 +18,7 @@ 6. 报关行执行完成后,平台上传真实报关完税文件;全部退税资料对应的完税文件齐全后,整柜报关完成。 7. 分别记录海关查验、不查验放行、扣货或其他正式结果。 -报关行回执、客户确认、整柜正式申报和海关放行是不同节点。客户确认不能自动完成,费用的系统默认确认也不能代替报关资料确认。 +报关行回执、客户确认、整柜正式申报和海关放行是不同节点。客户确认不能自动完成,平台费用确认与发布也不能代替报关资料确认。 ## 二、报关完成与待发区关系 @@ -70,11 +70,16 @@ - 甩柜改配投影提交 `ac3acfce`、`f1218cef`,平台容器读模型修复提交 `2c4f1ea3`;当前分支的船期展示修复已由 `backend-java #649`、`baiyue-firstleg-firstleg #452` 和 `client-web-test #351` 成功部署。真实验证确认改船只更新原柜船期,平台与客户端同步最新船期,柜号和报关资料/回执/完成文件保持不变,证据见 `baiyue-firstleg/reports/platform-and-client-transport-projection-20260927.json`。 - 回执历史投影提交 Firstleg `f6e70ea5`、Admin `ffe91a1`、Client `3e28478` 已成功部署:`backend-java #650`、`baiyue-firstleg-firstleg #453`、`admin-web-test #471`、`client-web-test #353`。健康检查为 `UP`,平台和客户真实接口均返回 `receiptHistory`;证据见 `baiyue-firstleg/reports/customs-receipt-history-20260928.json`。 - 本轮首次发送批次与确认动作历史提交为 Firstleg `e63cb2b2`、Admin `730defa`、Client `8fd4063`;数据库已核对 `fl_customs_broker_submission` 与 `fl_customs_completion_action_history`。现有完成柜烟测返回 `A0409 当前柜不在报关中`,确认新首次发送接口的状态门禁;证据见 `baiyue-firstleg/reports/customs-send-batch-confirmation-history-20260928.json`。 +- 本轮页面回归又修复了一个实际问题:Client 订单列表契约此前没有保留 `taxMode`,导致真实退税订单在“报关资料”页被过滤为 0 个资料包;Client `214fe4f` 已补齐退税字段映射,测试部署 `client-web-test #357` 成功。随后发现船期价格页首次加载重复请求渠道列表,`32c5241` 已收敛初始化监听,`client-web-test #358` 成功。 +- 后续回归又修复两个页面事实问题:未知海外仓不再把内部仓库 ID当作客户可见名称;报关完成详情改为明确提示“真实报关完税文件已齐全”。同时同步了现有实现对应的离线合同断言,客户端全量 `npm test` 已通过 `398/398`,生产构建通过,提交 `ffbe348`,测试部署 `client-web-test #359` 成功。 +- 测试环境内置浏览器已按 1920×1080 复验 Admin 与 Client:最新 Admin 柜次详情展示 `LOADED`、8 条仓内节点、PDA 作业摘要 100%、报关“已完成”、国内离仓“已自动离仓”和 7/7 门禁通过;最新 Client 报关资料页展示退税资料包“报关完成”,详情可见回执版本、客户确认状态、真实完税文件和下载入口。Client 船期价格查询以 100 KG/1.2 CBM 真实调用 15 个估价接口并返回 4 个匹配渠道;同一页面初始化只保留 1 次渠道列表请求。 +- 页面请求量抽样:Admin 货柜详情 13 个 API 请求且无重复;Client 报关资料列表 10 个不同 API 请求,打开两个资料详情各刷新一次资料接口;Client 船期价格初始化 1 次渠道请求,查询阶段 15 次并行估价请求,符合当前“每渠道估价”契约。完整新造数 HTTP 链已解除 PDA 前置阻塞并通过;报告 `baiyue-firstleg/reports/customs-current-20260928.json` 共 543/543 项通过,包含订单、测量、PDA 装柜、混合柜报关资料、回执、客户确认、报关行执行、完税文件、自动离仓和客户端下载。 +- 2026-09-28 再次复核:测试 API 健康检查、Admin 货柜列表/详情和 Client 报关资料页均返回 HTTP 200;Admin 与 Client 均在 1920×1080 下重新打开验证。已完成柜调用首次发送接口并携带确认参数,服务端返回 `A0409 当前柜不在报关中`,证明已完成柜不会重复创建报关批次;当前无新增数据库记录。客户端全量测试保持 `398/398` 通过,`client-web-test #359` 成功。 当前仍需继续补齐的不是客户资料协同、正式申报和海关结果基础链路,而是: - 报关行回执的外部确认/接收回执、下载凭证和回执轮次的更细对象;首次发送批次与客户确认动作历史已经落地; -- 更复杂的结果凭证上传和补资料专项门禁; +- 更细的报关行接收回执和下载凭证;海关异常继续按人工理由和备注处理,不新增自动结果凭证门禁; - 将正式申报/海关结果继续扩展到待发区、送港、进港和实际开航的只读投影,保持运输线独立;F23.3 的船期投影已完成真实 HTTP 核验。 开发时不要只增加页面节点文案,也不要把旧的 `COMPLETED` 直接当成客户确认、正式申报或海关放行。 @@ -96,7 +101,10 @@ - 每个客户都能完成“资料上传 → 报关行回执 → 客户确认/打回”,资料和完成文件保留版本,客户范围严格隔离。 - 首次发送报关行必须生成独立业务批次;客户每次确认或打回都保留对应回执版本、操作人、时间和原因。 - 未全部客户确认时不能完成整柜报关;正式申报批次、海关回填结果和报关单号已独立建模,不能把客户确认或完税文件上传直接当作海关放行事实。 -- 海关查验、不查验放行、扣货和其他结果已落地为批次下独立事实;后续只需补更复杂的凭证上传和补资料专项验收。 +- 海关查验、不查验放行、扣货、补资料和其他结果已落地为批次下独立事实;平台人员人工选择理由,选择“其他”时填写备注并人工处理异常。 - 报关完成后才能进入待发区;进入待发区后才推进送港/进港。甩柜/改配只修改原柜船名、航次和船期并保留历史,不能伪造或覆盖报关资料、回执和客户确认。 - 重复请求、版本冲突、换柜、部分装柜箱数展示和权限越界都有明确结果和审计记录;部分装柜的后续处理在线下完成。 -- 完成代码联调后,再回写 F22 和阶段三的实现状态;当前真实 HTTP 已通过,后续仍按 `COMPLETED`、海关放行和运输节点分别验收。 +- F22 和阶段三的实现状态已按当前代码和真实 HTTP 结果回写;后续继续按 `COMPLETED`、海关放行和运输节点分别验收,不把报关完成合并成海运或尾程完成。 + +- 2026-09-29:补齐测试环境专用 `CN_FIRSTLEG_PDA_OPERATOR` 账号并验证登录,重新执行 `phase3-container-customs` 正式 HTTP 造数链;订单、测量、PDA 领取/扫码/提交、`LOADED` 硬门禁、混合柜 BUY/TAX 隔离、首次发送批次、回执幂等、客户确认、报关行执行、完税文件、`COMPLETED`、自动离仓和 Client 完税文件下载共 543/543 通过,348 个唯一 HTTP 请求,0 个 coverage gap。报告:`baiyue-firstleg/reports/customs-current-20260928.json`。 +- 2026-09-29:继续执行头程运输节点造数链;订舱、港务船期、甩柜改船、拖车预约、报关完成后的待发区、国内离仓门禁和船司查询策略共 1036/1036 通过,641 个唯一 HTTP 请求,0 个阻塞缺口。甩柜只更新原柜船期,柜次及报关事实不变。报告:`baiyue-firstleg/reports/transport-current-20260929.json`;剩余 4 个缺口均为非阻塞的 COSCO/ZIM 外部接入或 Android 真机验收。 diff --git a/头程到尾程分阶段流程/README.md b/头程到尾程分阶段流程/README.md index 2bf4ac4..7c72a1e 100644 --- a/头程到尾程分阶段流程/README.md +++ b/头程到尾程分阶段流程/README.md @@ -1,6 +1,6 @@ # 头程到尾程分阶段流程 -本目录是端到端流程的分段查找入口。流程基线已确认,当前用于收尾变更;其中阶段三的报关协同代码尚未完成。总览和节点关系看[《头程到尾程流程节点梳理》](../头程到尾程流程节点梳理.md),字段、页面操作、权限和异常细节在对应阶段文件维护。 +本目录是端到端流程的分段查找入口。F01-F40 流程基线已确认,当前用于全流程收尾变更;阶段三报关协同代码已接入并通过真实 HTTP 验收。总览和节点关系看[《头程到尾程流程节点梳理》](../头程到尾程流程节点梳理.md),字段、页面操作、权限和异常细节在对应阶段文件维护。 ## 三大业务块与六个分段 @@ -25,7 +25,7 @@ - 阶段三的装柜完成(`LOADED`)后先完成退税报关;报关完成后货柜进入待发区,再推进送港运输。甩柜/改配只影响船期,不改变已完成报关事实。 - 报关协同必须经过“客户资料 → 报关行回执 → 客户确认/打回重做”,柜内所有客户确认后才提交整柜资料并正式申报。 - 送港完成、进港或甩柜都不等于海运中;承运船舶实际开航后才进入阶段四的海运节点。 -- 阶段四形成海外接柜输入后,阶段五负责实收、入库和库存,阶段六负责出库、派送、签收和异常回写。 +- 阶段四形成海外接柜输入后,阶段五负责实收、入库和库存,阶段六负责出库、派送、签收和异常回写。F01-F37 以海外出库为阶段性业务终点,F38-F40 继续完成派送、签收和国内最终回写。 ## 旧文档的使用范围 diff --git a/头程到尾程流程节点梳理.md b/头程到尾程流程节点梳理.md index 4a930eb..247e04a 100644 --- a/头程到尾程流程节点梳理.md +++ b/头程到尾程流程节点梳理.md @@ -1,6 +1,6 @@ # 头程到尾程流程节点梳理 -> **当前用途:收尾变更的流程入口。** 整体流程基线已确认,报关协同代码尚未完成;本文件只保留三大业务块、关键节点和节点之间的关系,便于查找和修改。报关开发请看[报关代码开发交接清单](头程到尾程/报关代码开发交接清单.md),历史开发规划、进度、门禁和评审不在这里继续维护。 +> **当前用途:全流程收尾变更的流程入口。** F01-F40 的业务基线已经确认,报关协同代码已接入并通过测试环境验收;本文件只保留三大业务块、关键节点和节点之间的关系,便于查找和修改。报关实现细节请看[报关代码开发交接清单](头程到尾程/报关代码开发交接清单.md),历史开发规划、进度、门禁和评审不在这里继续维护。 > > **维护原则:** 客户看到的是进度投影,后台看到的是业务对象节点,明细节点记录真实操作和结果。三者使用同一组业务事实,不另建一套客户状态。 @@ -42,10 +42,10 @@ |---|---|---|---|---|---| | F01-F07 | 头程下单 | 待下单、审核中、已审核 | 企业、订单、审核任务 | 填写、提交、补件、审核、生成入仓单 | 审核通过后进入国内履约 | | F08-F10 | 头程下单 | 待到仓、测量中、待确认 | 入仓单、测量记录 | 到仓收货、扫码、称重、测量、审核 | 形成可排柜的实测数据 | -| F11-F13 | 头程下单 | 费用待确认、待组托、待分柜 | 费用版本、确认记录、托盘 | 计费、推送、客户确认、组托/封托 | 费用不阻断主链;装柜完成时未确认的当前有效费用按系统默认确认留痕 | +| F11-F13 | 头程下单 | 费用待确认、国内扣货/解除、待组托、待分柜 | 费用版本、确认记录、HOLD 记录、托盘 | 计费、推送、客户确认、国内扣货/解除、组托/封托 | 费用确认不阻断主链;国内扣货单独控制作业门禁;装柜不能代替客户确认费用 | | F14-F20 | 海运(货柜) | 待分柜、订舱中、装柜准备/进行中 | 柜次、装柜计划、拖车任务、拣货任务 | 分柜、订舱、排车、拣货、拍照、铅封、数量核对 | 通过装柜门禁后才能完成装柜 | | F21 | 海运(货柜) | 国内已装柜 | 装柜任务已完成 | 实际柜号、实装数量、装柜证据确认 | 产生 `LOADED`;完成报关后才进入待发区 | -| F22 | 海运(货柜) | 报关确认中、待补资料、已提交报关 | 客户报关案例、报关批次 | 收集资料、发报关行、接收回执、客户确认或打回、重新上传和重发 | **流程已确认、代码未完成**;柜内所有客户确认后,才能提交整柜资料并正式申报;客户确认不等于海关放行 | +| F22 | 海运(货柜) | 报关确认中、待补资料、已提交报关 | 客户报关案例、报关批次 | 收集资料、发报关行、接收回执、客户确认或打回、重新上传和重发 | **已实现并通过真实 HTTP 验收**;柜内所有客户确认后,才能提交整柜资料并正式申报;客户确认不等于海关放行 | | F23 | 海运(货柜) | 待发区、送港中、已进港、待开船、已甩柜 | 待发区、送港/拖车任务、港口和船次事实 | 报关完成后入待发区、离仓、送港、进港、甩柜、改配 | 报关完成是进入待发区的门槛;甩柜/改配只改变运输船期,不重做已完成报关 | | F24 | 海运(货柜) | 海运中 | 船次实际状态 | 承运船舶实际开航、船期回写 | 只有实际开航后进入海运节点 | | F25-F27 | 海运(货柜) | 目的港处理中、待海外接柜 | 目的港清关/提柜、尾程订单、入仓计划 | 清关、提柜、创建尾程计划 | 形成海外接柜输入,不等于已经入库 | @@ -66,7 +66,7 @@ ### 2. 费用确认不阻断装柜主链 -费用确认是头程下单块中的并行事项。客户未确认时可以继续排柜、拣货和装柜;装柜完成后仍未确认的当前有效费用按系统默认确认,并保留“系统默认确认”的来源和时间。系统默认确认不能用于报关资料的客户确认。 +费用确认是头程下单块中的并行事项。客户未确认时可以继续排柜、拣货和装柜。按阶段二及 Firstleg 当前服务指引,装柜完成可以触发平台费用确认与发布,但不能代替客户主动确认;客户已确认且本票装柜完成时才最终冻结。费用确认与报关资料的客户确认分别记录。 ### 3. 异常附着在主节点上 diff --git a/测试环境单机部署与配置契约.md b/测试环境单机部署与配置契约.md new file mode 100644 index 0000000..a1eb472 --- /dev/null +++ b/测试环境单机部署与配置契约.md @@ -0,0 +1,100 @@ +# 测试环境单机部署与配置契约 + +更新日期:2026-09-29。当前只有 test,没有开发/生产环境。本文定义目标部署、切换与验收;具体路由、认证、投递契约唯一见[统一认证与服务通信契约](统一认证与服务通信契约.md)。 + +状态:目标已确认,实现仍在迁移。第 0A 批资金消费者本地修复已完成;新 Gateway/Token/投递/Compose 尚未落地或发布。运行服务器、Nacos 发布值、主机资源和真实 MySQL 故障恢复尚未验证。 +## 结论与范围 + +按“头程和海外仓不再分区域部署、所有服务同机运行、取消独立事件接收服务与海外网关”设计。这里将“事件接收”对应为当前 `event-bridge-service`,不推定要删除业务通知、异步任务或消息队列。 + +建议目标:一个 Gateway、一套 Auth/IAM 登录与权限体系、一个测试 Nacos 命名空间和一套测试内部容器网络。保留 Firstleg、Lastleg、Warehouse、Warehouse Overseas 等业务服务,各自拥有数据表与业务规则。同机可以共用 MySQL 实例,继续按服务分 Schema;不要求合并为一个数据库或一个 Java 进程。 + +最终移除 `gateway-overseas` 与 `event-bridge-service` 部署单元及其区域分支。服务名称中的海外业务含义可以保留;仓库类型、仓管角色、仓绑定和客户数据隔离仍有业务用途。 + +## 测试环境目标部署清单 + +| 类别 | 目标 | +|---|---| +| 环境 | 仅 test,所有服务同一台宿主机 | +| 用户端 | Admin、Client、国内 PDA、海外 PDA 共用一个业务 API 入口;页面和作业职责保留 | +| 入口 | Nginx/反向代理接统一 Gateway,业务内部端口不作为客户端访问入口 | +| 认证 | Auth、IAM、统一 JWT 与 Redis 会话,按平台/客户/PDA 校验权限 | +| 业务 | Order、Firstleg、Lastleg、Warehouse、Warehouse Overseas、Finance | +| 公共能力 | File、Print、Audit、Integration 按现有职责保留 | +| 配置与发现 | 一套 Nacos,使用实际 Namespace ID 的单一测试命名空间,不再分 test-cn/test-overseas | +| 数据与缓存 | 一套测试 MySQL 实例,按服务分 Schema;统一可访问的测试 Redis,保留必要键隔离 | +| 消息 | 保留现有 RocketMQ 用于导出、通知和审计等已发现用途 | +| 服务协同 | 同机内部调用;需要可靠交付的业务采用本地事务记录加直接投递和消费幂等 | +| 退出部署 | gateway-overseas、CN/OVERSEAS 两个 Event Bridge 实例及专用配置 | + +服务名、Schema、端口、数据卷和实际中间件配置在改造前做一次清单核对;当前表是目标部署结构,不是对服务器现状的确认。旧 development/production 配置不再作为本次发布入口,也不要求新建对应环境。 + +## 分批实施与交付门槛 + +| 批次 | 工作 | 完成依据 | +|---|---|---| +| 0:文档与基线 | 确认仅 test 的目标、唯一接口路径、统一认证、直接投递职责;列出当前配置与服务清单 | 新目标、当前实现、待办三者明确区分 | +| 0A:资金消费前置修复 | 区分临时执行失败与最终业务拒绝;补齐并发 Inbox 抢占后的摘要校验和一致结果处理 | 临时故障原事件重试、并发同 hash/异 hash、执行成功后结果保存失败的恢复验证通过;修复规则见统一认证与服务通信契约;本地已通过,实库待验证 | +| 1:入口与认证 | Gateway 接入全部业务;Auth/common-security/海外服务统一认证;各端共用入口;解决仓库路由冲突 | 本地编译、认证测试、路由合同及受影响前端测试通过 | +| 2:业务通信 | 替换装柜、船节点、卸柜、暂扣、派送、费用和资金链;补齐直接投递重试及失败处置 | 各链路有直接消费者,成功确认、重复投递和故障恢复测试通过 | +| 3:部署收敛 | 单套 test Compose/Nacos/Jenkins;清理两个废弃服务和专用配置、SQL 初始化引用、安全投影依赖 | 构建与配置合同通过;形成唯一测试发布清单及启动依赖 | +| 4:测试环境验证 | 发布一致的新版本,以新造数据执行 API 全链路和各端实际操作 | 下表业务验收全部通过,保留报告及未通过项 | + +改造批次可以分别完成代码检查;仅入口批次完成时,不把测试环境视为已跑通。正式测试部署须使用接口、认证、通信与配置相互匹配的一组版本,避免先停 Bridge 导致现有业务失联。 + +本地编译和离线检查只是开发工具使用,不代表存在独立“开发环境”。最低检查包括相关 Maven 测试编译/测试、网关路由与拓扑合同、前端类型检查及受影响测试;不以构建成功代替测试环境闭环通过。 + +## 测试环境跑通的验收标准 + +所有项目初始状态均为“待实施、待验证”。 + +| 验收项 | 操作与预期 | +|---|---| +| 部署与发现 | 所有保留服务启动健康,统一命名空间中可发现;客户端无需访问海外 Gateway 或 Bridge | +| 登录与权限 | Admin、Client、两类 PDA 使用统一认证;刷新有效、退出后失效;停用账号/客户和越权访问被拒绝 | +| PDA 仓绑定 | 未绑定拒绝作业,绑定仓限制正确,换仓后旧会话失效 | +| 仓库路由 | 仓库主档、库位、托盘访问正确服务,原重复前缀不再造成路由歧义 | +| 订单到装柜 | 新造客户与订单走审核、入仓、测量、分柜和装柜;完成后正确生成尾程数据 | +| 海外履约 | 船节点同步、接柜、卸柜、入仓、库存、排车、出库、派送形成闭环;签收按来源回写 Firstleg/Order | +| 状态协同 | 暂扣/解除、卸柜事实、分单签收作用于正确单据,不误推进同柜或同车其他订单 | +| 费用与资金 | 费用准确入 Finance;资金指令与结果对应;重复请求不重复入账、冻结或扣款 | +| 可靠性 | 消费服务短时停止、重启、响应超时、重复和乱序投递后可恢复,失败可查且可重试,无永久丢单 | +| 公共能力 | 文件上传下载、标签打印、异步导出、消息通知、审计正常 | +| 客户与作业界面 | Admin/Client 和 PDA 实际操作完成核心流程;HTTP 通过不能替代页面/设备验证 | + +每次验收记录版本、测试数据业务编号、覆盖场景、结果及错误诊断信息。修复失败项后执行受影响回归,再给出整体是否跑通的结论。 + +### D. 唯一测试环境的整体切换与失败恢复 + +本次采用测试停机窗口一次切换,允许测试数据按明确范围重建,不做新旧协议并行。实际部署、SQL、清理操作不在本文编写过程中执行。 + +| 顺序 | 操作 | 放行条件/记录 | +|---|---|---| +| D0 版本准备 | 记录各后端/前端/PDA 仓库提交、镜像 tag/digest、APK/WGT 版本、Nacos 配置版本与 SQL 基线 | 各端对应同一架构契约;本地检查通过 | +| D1 运行清单 | 列出当前容器、Compose 项目、网络、服务注册、Nacos Data ID/Group/Namespace、Redis DB/key、MQ topic/group、DB/文件卷引用 | 填实际标识,不输出凭据;确认主机容量和端口 | +| D2 停止写入 | 公告测试窗口、停止正在进行的验收/造数、阻断业务写入;停止旧业务容器、Relay 和相关消费任务 | 没有旧进程继续发消息、续写数据库或向旧 Nacos 注册 | +| D3 应用基线与配置 | 按逐项对象清单处理测试业务数据/旧投递、会话、必要 MQ 测试消息与文件引用;发布统一 test Nacos/Compose 配置 | 数据一致;不整机清空 Redis/MQ/文件,不触碰不在清单中的资源 | +| D4 启动新服务 | 中间件健康 → IAM/Auth 及公共能力 → 所有业务消费者与生产者 → Gateway → 前端;写入口保持关闭 | 健康检查通过且消费者就绪;无循环依赖导致的启动等待;旧网关/Bridge 不再启动 | +| D5 端侧切换 | 发布 Admin/Client 新构建,更新两类 PDA,清除旧登录态后重新登录 | 验收设备构建版本与配置正确;原生地址不再指向海外入口 | +| D6 冒烟 | 统一登录、主档/资源查询、越权拒绝、文件上传,加一条装柜→尾程链与一条资金指令→结果回传 | 无路由误投、认证失效或严重业务错误 | +| D7 完整验收 | 开放本轮验收写入,按前述矩阵新造数据执行完整 API、页面、PDA 及故障恢复 | 所有阻断项关闭才声明跑通 | +| D8 清理退役资源 | 核对旧容器、注册、配置及专用卷/库引用,形成明确清理清单 | 新链路通过、没有残余调用;删除动作单独按范围执行 | + +启动顺序是依赖就绪原则,不允许写死为某服务必须业务调用另一未启动服务后才能健康。生产端 Outbox 可先记录并有限重试,不能在业务消费者启动前产生验收写入;冒烟前以实际健康状态确认。 + +停止条件:认证/客户隔离错误、资金重复执行、必需消费者不可达、投递无法恢复、数据库基线不匹配,任何一项即关闭测试写入并停止本轮验收,不用跳过场景换取整体通过。 + +失败恢复默认选择:保留故障证据,环境继续停写,修复新架构后用匹配版本重新部署并重建本轮失败测试数据。只有确需恢复原测试工作时,整体恢复旧镜像/前端/PDA、旧 Nacos/Compose 和匹配旧 Schema 基线,清理新旧会话及消息交叉引用;不恢复已经放弃的测试业务数据。单服务镜像回滚仅适用于确认契约和 Schema 未变的情况,不能代替本次架构整体恢复。 + +待部署准备时填写的运行值:测试窗口、发布清单、实际 Namespace ID、Data ID/Group、域名与端口、Redis DB/key 前缀、MQ 范围、SQL/卷操作清单、主机资源预算、验收数据编号。不得用猜测值替代运行检查;这些值未填写不进入 D2。 + + +## 基线与范围 + +测试数据可以按明确对象重建,不设计存量迁移、双写、旧协议兼容或生产发布。本地编译不是独立开发环境。执行初始化、清理和部署前落实具体对象清单与适用授权,本契约不表示这些动作已执行。 + +配置收敛必须覆盖 Compose、Jenkins、deploy/service-map.yml、发布脚本、Nacos Data ID/Group/Namespace、前端代理与构建变量、PDA 地址、SQL 初始化引用、服务发现和健康检查。容器内不能用 localhost 代替其他服务名。保留文件数据卷及仍被导出/通知/审计使用的 RocketMQ。 + +不新增中间件,不合并业务服务、Schema、两类 PDA 或领域状态机;旧 development/production 退出当前发布入口,不顺手删除无关历史文件。模块旧指引中双区域部署、双 Token 或必须经海外 Gateway 的强制描述属于迁移前实现,后续实现以本契约和统一认证契约为准,并随对应批次更新模块说明。 + +验收记录保存各仓库提交、镜像/配置版本、业务编号、覆盖场景与失败项。本地检查、H2 事务测试与真实 MySQL/HTTP/页面/PDA 验收分别记录,不能互相代替。 diff --git a/统一认证与服务通信契约.md b/统一认证与服务通信契约.md new file mode 100644 index 0000000..14b323d --- /dev/null +++ b/统一认证与服务通信契约.md @@ -0,0 +1,120 @@ +# 统一认证与服务通信契约 + +更新日期:2026-09-29。本文是已确认目标的唯一主契约;当前仅有测试环境,所有服务同机部署。部署与切换见[测试环境单机部署与配置契约](测试环境单机部署与配置契约.md)。 + +状态:目标契约已确定,整体迁移尚未完成。统一 Token/JWKS/Redis 会话与八类业务事件直连、结构化 ACK 已进入源码并完成分批本地验证;旧海外网关/事件桥模块、部署配置仍未退役。撤销并发窗口、投递失败治理、协议去区域字段与测试环境联调尚待完成,不得混合发布新旧协议或把本地测试视为环境验收。 + +下文路径、响应与时序为改造目标。实际业务服务、客户隔离、仓库类型、作业角色与状态机保持原职责;不能将“同机”解释为合并数据库表或绕过权限。 +### A. 唯一路由与消费端映射 + +全部客户端共用 Gateway。下表写完整服务端路径;前端 HTTP Base 若已含 `/api`,业务调用不重复拼接该段。所有资源接口仍校验平台身份、客户范围及业务权限。 + +海外资源前缀记作 R=`/api/platform/v1/overseas-warehouse-resources`,权限前缀记作 P=`platform:overseas-warehouse:`。以下 R/P 仅用于文档缩写,不是配置变量。 + +| 方法与目标路径 | 目标服务 | 权限 | 主要调用方/改动 | +|---|---|---|---| +| GET `/api/platform/v1/warehouse-admin` 及现有主档 CRUD | Warehouse | 维持现有主档权限,GET 为 `platform:warehouse:list` | 主档页面与 IAM 的共享收货仓查询保留现有调用;写操作不改权限 | +| GET `/api/platform/v1/warehouse-admin/overseas-receiving-options` | Warehouse | P+`warehouse:list` | 新增限定用途查询;替代海外资源服务原根目录查询,返回平台公共、OVERSEAS、ACTIVE、RECEIVING 仓库,不因迁移给资源角色授予主档维护权限 | +| GET R+`/pallets`、R+`/pallets/summary` | Warehouse Overseas | P+`pallet:list` | Admin `overseas-warehouse/api/pallets.ts` 跨仓查询 | +| GET R+`/{warehouseId}/locations`、R+`/{warehouseId}/locations/{id}` | Warehouse Overseas | P+`location:list` | Admin `overseas-warehouse/api/locations.ts` | +| POST R+`/{warehouseId}/locations` | Warehouse Overseas | P+`location:create` | 同上 | +| PUT R+`/{warehouseId}/locations/{id}` | Warehouse Overseas | P+`location:edit` | 同上 | +| DELETE R+`/{warehouseId}/locations/{id}` | Warehouse Overseas | P+`location:delete` | 同上 | +| GET R+`/{warehouseId}/pallets`、`/pallets/summary`、`/pallets/{id}`、`/pallets/{id}/label`(后面三项同属 R+`/{warehouseId}`) | Warehouse Overseas | P+`pallet:list` | Admin `overseas-warehouse/api/pallets.ts`,标签二进制响应保持原格式 | +| POST R+`/{warehouseId}/pallets` | Warehouse Overseas | P+`pallet:create` | 同上 | +| PUT R+`/{warehouseId}/pallets/{id}` | Warehouse Overseas | P+`pallet:edit` | 同上 | +| DELETE R+`/{warehouseId}/pallets/{id}` | Warehouse Overseas | P+`pallet:delete` | 同上 | +| 现有方法 `/api/platform/v1/last-leg/**`、`/api/merchant/v1/last-leg/**`、`/api/pda/v1/last-leg/**` | Lastleg | 保留对应 Controller 权限与作业数据范围 | Admin、Client、海外 PDA 改用统一 HTTP/Token,业务路径保持 | +| 现有文件、打印、审计、集成公开接口 | 原对应服务 | 保留现有权限 | 从原双网关去重后接入唯一入口 | +| 任意 `/internal/**` | 仅服务间内部网络 | 内部服务身份 | Gateway 无公开路由;测试内部接口不能通过公网入口调用 | + +新增收货仓选项查询沿用原海外目录的分页参数 `page/size`(size≤200)和 `WarehouseOption` 字段语义,由 Warehouse 直接查询权威主档,不能只通过客户端过滤实现范围限制。该用途查询需在 Warehouse Controller/OpenAPI/IAM 权限合同中明确登记。现有 IAM 查询与 Admin pallets 中 `listSharedReceivingOverseasWarehouseOptions` 已使用主档接口,保留其现有权限边界;仅原海外目录的直接调用者迁移到新用途接口,不批量改写无关主档消费者。 + +修改 `PlatformWarehouseResourceController` 和 `PlatformWarehouseDirectoryController` 的资源路径;移除海外服务中的重复目录代理和无独立必要性的公开健康路由。内部资源锁、托盘作业路径保持服务内使用。Gateway 对 `/warehouse-admin/**` 只指向 Warehouse,对 R 只指向 Warehouse Overseas,不按路由先后顺序或请求 warehouseId 猜测目标服务。 + +路由验收:逐条 method/path 唯一匹配;静态 `/overseas-receiving-options` 不误命中 `/{id}`;同名旧前缀下的国内接口仍有效;海外调用方全部迁移,不为其保留旧别名;客户端角色只能读取被授权目录,不能借新增用途查询修改主档。 + +### B. 逐事件直接投递与结果确认 + +以下内部路径复用当前消费者入口,统一为 POST,使用内部服务令牌、服务发现或容器服务名,不能经公开 Gateway。按 eventType 明确选择目标,不再根据 CN/OVERSEAS 选择目标;未知事件类型直接记录永久错误,不默认投某个业务服务。 + +| eventType | 当前生产与投递入口 | 直接目标 | +|---|---|---| +| `FirstLegLoadingPlanCompleted` | Firstleg `LoadingCompletedOutboxService` → `LoadingCompletedOutboxRelay` | Lastleg `/internal/lastleg/events` | +| `FirstLegContainerShippingNodeRecorded` | Firstleg `CarrierScheduleNodeOutboxService` → 同一 `LoadingCompletedOutboxRelay` | Lastleg `/internal/lastleg/events` | +| `OverseasContainerUnloaded` | Lastleg `InboundUnloadCompletedOutboxService` → `InboundUnloadCompletedOutboxRelay` | Firstleg `/internal/firstleg/v1/container-events` | +| `OverseasInboundOrderDetainedChanged` | Lastleg `InboundOrderDetainedOutboxService` → 同一卸柜 Relay | Firstleg `/internal/firstleg/v1/container-events` | +| `OverseasDeliveryCompleted` | Lastleg `DeliveryCompletedOutboxService` → 同一卸柜 Relay | Firstleg `/internal/firstleg/v1/container-events` | +| `BusinessFeeSourceChanged` | Lastleg `OverseasFeeOutboxService` → `OverseasFeeOutboxRelay` | Finance `/internal/finance/v1/business-fee-source-events` | +| `WalletCommandRequested` | Lastleg `WalletCommandOutboxService` → `InboundUnloadCompletedOutboxRelay` | Finance `/internal/finance/v1/wallet-command-events` | +| `WalletCommandCompleted` | Finance 资金指令处理的结果 Outbox → `WalletResultOutboxRelay` | Lastleg `/internal/lastleg/events` | +| `IamUserStatusChanged`、`IamTenantStatusChanged`、`IamPermissionVersionChanged` | IAM 安全事件专用生产/Relay | 不迁移业务投递;完成 C 的撤销替代验证后移除专用投影链 | + +已核对:Lastleg 卸柜 Relay 的 Repository 还选择了资金指令,不能把它整体改成 Firstleg URL;费用 Relay 只选择费用来源事件。实现时使用明确的事件白名单分派,并测试资金请求不误投 Firstleg。Firstleg 现有直达 Finance 的其他费用链、Order 的既有投递和 RocketMQ 导出/通知不并入本次新路由表,保持现有行为并做受影响回归。 + +统一目标返回结构为 `ApiResponse`,其中 `DeliveryAck={eventId,payloadHash,outcome}`。`outcome` 只允许 `APPLIED`(已完成消费)、`DUPLICATE`(已成功处理的同一事件)、`STALE`(该类事件明确允许忽略的旧版本)。四个内部消费路径同步修改为这个返回结构,Relay 与全部直接调用者同步更新;当前 Integer/Object/feeSourceId 等响应不作为最终成功判定依据,不引入双响应兼容。 + +成功必须同时满足:HTTP 2xx、body code 为字符串 `200`、ACK 中 eventId/payloadHash 与发送一致、outcome 为该类事件允许的值。消费端只在可靠提交后返回成功;不能刚入内存或仅保留待处理记录就返回 APPLIED。重复确认必须来自持久化幂等记录;同 eventId 不同 hash 为冲突,不允许覆盖。 + +消费处理的原子性按业务实现验证:普通消费者将业务变更与成功幂等记录同事务提交;第 0A 批已将资金执行、成功 Inbox 和结果 Outbox 收敛到同一事务,保存结果失败时资金一同回滚;事件身份独立持久化防止重试换内容。保留既有钱包业务幂等键和状态机,真实 MySQL 故障恢复仍需验证。 + +特别约定:资金指令的投递成功不等于冻结/扣款成功。Finance 必须可靠保存 SUCCEEDED 或 FAILED 业务结果及结果 Outbox 后确认该指令已消费,Lastleg 以 `WalletCommandCompleted` 更新业务状态。余额不足等已形成 FAILED 结果的指令不进行无意义的传输重试;成功扣款后结果发送失败,只重试原结果事件,不能再次生成扣款指令。 + +| 情况 | 生产端动作 | 消费端要求 | +|---|---|---| +| APPLIED / DUPLICATE | 标记完成 | 已提交、幂等记录可核验 | +| STALE | 仅显式允许旧版本忽略的事件标记完成 | 证明较新版本已覆盖且不丢独立业务事实;资金和独立费用动作不能泛用 STALE | +| 连接失败、超时、HTTP 5xx/429、临时数据库失败 | 原事件重试 | 超时后可能已提交,下次必须幂等 | +| 船节点等先于依赖单据到达 | 返回明确的可重试“依赖未就绪”业务错误,退避重试 | 不以不存在直接当成功,不靠查询顺序假设到达顺序 | +| 非法信封/版本、hash 冲突、未知类型、明确不可执行协议错误 | DEAD 并保留原因 | 不修改业务,不兜底成功 | +| 401/403 或内部令牌错误 | DEAD,标注配置/认证失败,修复后人工原样重试 | 失败关闭,不绕过鉴权 | +| 响应缺失、ACK 不匹配、未识别业务错误 | 不确认成功,有限重试后 DEAD | 保留诊断信息,不能仅按 HTTP 200 通过 | + +统一逻辑状态为待投递、投递中、重试等待、完成、DEAD;可映射到现有表字段,不要求批量改名。初始测试参数:连接超时 3 秒、单次请求超时 15 秒、租约 60 秒、累计自动尝试 12 次、退避从 5 秒翻倍上限 30 分钟,加入小幅抖动;参数需可配置。租约失效后的恢复和最终状态更新必须校验持有者,避免旧任务覆盖新任务。消费超时不能被解释为事务一定回滚。 + +源码配置已统一为 `baiyue.event-delivery.max-attempts=12`、`base-delay-seconds=5`、`max-delay-seconds=1800`、`jitter=0.1`、`lease-seconds=60`,供四个业务 Relay 使用。`retry_count` 表示已失败或租约超时的投递次数;普通领取不递增,领取超时任务或恢复超时租约时计入一次,自动预算耗尽后保持 DEAD。实际投递失败从失败时刻计算下一次重试时间;每次领取使用独立租约 ID 和当前时间,最终写入必须匹配该 ID。DEAD 保留原始事件,不能通过定时扫描自行恢复。当前人工重试、逐次审计和指标仍在实施,未达到停桥部署门槛。 + +每次尝试记录事件、目标、时间、耗时、结果、错误和下一次重试;按服务/类型提供 pending/DEAD 数量及最老待处理时长。告警接入现有能力,不为本次新增独立监控平台。人工重试采用各生产服务的受保护内部操作与配套运维脚本,不新增公开后台页面:只允许 DEAD 原事件重试,记录操作人/原因,保留 eventId/hash/payload/业务幂等键,禁止修改载荷或伪造新 ID 后重发。精确运维接口及脚本参数随对应服务代码提交冻结并测试,不使用直接改表作为验收方式。 + +信封保留业务事件类型/版本、客户归属、聚合版本、因果/追踪标识及 payloadHash;删除 sourceRegion/targetRegion 及纯区域部署字段时同步 DTO、Validator、构造调用、SQL 基线和测试。语义事件版本及业务载荷不因去桥而随意改动。本轮不重写旧测试事件,不做旧信封兼容。 + +### C. 统一认证和会话撤销矩阵 + +Auth 是唯一签发者;Gateway 负责入口令牌与访问域校验,业务服务通过 common-security 校验同一会话及业务权限。统一使用 Auth 现有国内会话协议,不只调整海外 Audience。Auth、Gateway、Lastleg、Warehouse Overseas 必须使用一致 Redis DB、会话键前缀、序列化结构与有效期规则;业务缓存用独立前缀,不能混同会话键。 + +JWT 不携带角色或权限集合,只保留必要身份、客户/应用/仓绑定与版本声明;授权快照取服务端会话,平台/客户/PDA 访问域仍独立校验。客户端不能从 JWT 或外部伪造头获得绕过服务器权限检查的能力。 + +| 触发行为 | 撤销范围与负责链 | 必须验证 | +|---|---|---| +| 当前会话退出 | Auth 撤销当前会话的 Access/Refresh 能力 | 原 Access 被拒绝,原 Refresh 不能恢复 | +| 密码重置、账号停用 | Auth 或 IAM 调 Auth,撤销该账号全部相关会话 | 多端旧 Token 均失效,停用后不可重新登录 | +| 客户停用 | IAM 确定该客户成员范围,Auth 撤销该客户作用域会话 | 该客户业务不可访问/刷新;其他客户与平台账号不被误撤销 | +| 成员移除、成员角色改变 | IAM → Auth 撤销对应成员/客户作用域会话 | 旧权限不可继续使用,重新登录/刷新不能恢复被移除身份 | +| 角色权限、角色分配变化 | IAM RBAC 确定所有受影响账号与作用域 → Auth 撤销 | 已登录用户不能继续使用旧权限快照,遗漏批量关联用户算失败 | +| 平台人员角色改变 | IAM 平台人员维护 → Auth 撤销相应账号会话 | 新旧角色与平台访问域正确 | +| PDA 仓绑定修改/清空 | IAM → Auth 撤销绑定账号全部相关会话 | 原仓 Token 拒绝;新登录只获得新仓;无绑定拒绝受限作业 | +| Refresh Token 轮转与重放 | Auth 维持现有会话轮转规则,各端共用刷新编排 | 失效 Refresh 不重复换取;并发刷新行为与当前契约一致 | + +撤销职责优先复用现有 MemberService、RbacService、PlatformInternalUserService/PlatformUserManagementService 与 Auth revokeSessions 链。逐入口确认,不能只凭其中一处已有调用就删除全体安全投影。 + +安全变更不得在撤销失败后仍返回完整成功。实施必须核对调用与提交顺序,证明“新安全状态已生效、旧会话却残留”的异常路径不会继续授权;同进程 try/catch 或口头要求重试不构成保证。若当前实现无法保证,应在该批次补齐可靠撤销及失败关闭机制,并先验证再删投影,不能降级为等待 Token 自然过期。这里冻结的是安全结果,具体撤销代码调整依据逐入口核查限定范围。 + +必须覆盖 Redis 不可用、Auth 撤销调用超时、账号/客户停用后的刷新、跨客户 Token 混用、伪造身份头。业务服务不能仅信任浏览器提供的权限头;统一服务端认证后清除对原海外可信头及 Lastleg 安全投影的专用依赖。权限继续由服务器决定,客户端快照只用于显示。 + + +## 业务归属与权限边界 + +平台和客户两级模型、服务端客户隔离、实际收货仓与 FBA 目的仓的区分继续有效。仓管绑定修改须撤销会话;无关平台角色不能通过客户端参数假冒仓绑定。统一认证后,不再用双区域安全投影作为权限来源。 + +资金指令当前实现补充:Finance 先单独提交 eventId/hash 身份记录,再在事务内锁定 Inbox 并复核 hash。资金变更、Inbox 最终结果及结果 Outbox 同事务提交;明确业务拒绝在原事务回滚后重新加锁记录,已有最终结果不得覆盖。可重试异常不产生最终 FAILED。当前内部响应维持原接口,统一 DeliveryAck 属于后续通信批次。 + +最终业务拒绝白名单为 FIN-WALLET-INSUFFICIENT、FIN-WALLET-HOLD-409、FIN-IDEMPOTENCY-CONFLICT、FIN-REQ-400;处理中、乐观锁冲突、依赖冻结未到达及未分类异常继续向投递方抛出。基于 H2 的 JDBC 并发与回滚测试已经通过,不替代真实 MySQL 和测试环境全链路验证。 + +### 国内仓库目录同步读取 + +- 国内 `warehouse-service` 是 Warehouse ID、类型、状态、地址和能力的唯一权威。海外数据库不得复制仓库、地址或服务能力主表。 +- `warehouse-overseas-service` 只保存库位、托盘、资源锁及其国内 `warehouseId` 引用;资源写入和 Lastleg PDA 仓绑定校验通过受内部服务令牌保护的国内只读目录完成。 +- 只允许平台共享、`OVERSEAS`、`ACTIVE` 且启用 `RECEIVING` 的仓作为海外实际收货仓。低频正结果可缓存 30 分钟,空目录、不存在和停用结果不得长缓存。 +- FBA 目的仓同样只以国内 `warehouse-service` 的平台公共主数据为权威,但语义与海外实际收货仓严格分离:Admin 候选使用 `warehouseType=FBA&status=ACTIVE` 的平台仓库分页;Lastleg 写入通过受内部服务令牌保护的 `/internal/warehouses/0/{warehouseId}/active` 读取当前事实,并继续校验 `warehouseType=FBA` 及 ID/编码/名称一致。`OVERSEAS`、`OVERSEAS_PARTNER` 或 `DOMESTIC` 均不得作为 FBA 目的仓。 + +- 按 FBA 仓拆分的海外派送单在签收完成时,由 Lastleg 在同一事务按关联来源入仓单分别写 `OverseasDeliveryCompleted` V1 Outbox;Event Bridge 定向投递 Firstleg。Firstleg 校验事件信封、客户、来源入仓单/订单、入仓码和 FBA 仓后,只将该来源入仓单从 `LOADED` 推进到 `DELIVERED`;同一 Order 的全部有效入仓单均为 `DELIVERED` 后,才以内部服务身份幂等推进该 Order 到 `COMPLETED`。同车其他 FBA 派送单必须各自签收,不得随整车一起完成。 diff --git a/财务管理/财务领域模型与跨服务契约.md b/财务管理/财务领域模型与跨服务契约.md index 8000e14..faad48d 100644 --- a/财务管理/财务领域模型与跨服务契约.md +++ b/财务管理/财务领域模型与跨服务契约.md @@ -123,6 +123,16 @@ Finance 不以当前查询结果覆盖已保存快照。查询超时、5xx 或 ## 7. 错误码与响应语义 +### 资金指令消费可靠性(2026-09-29) + +`WalletCommandRequested` 先独立提交 eventId/hash 身份记录,再在处理事务使用 Inbox 行锁重新校验 hash;相同 ID 不同 hash 即使并发到达也不能执行钱包。资金变更、成功 Inbox 结果和结果 Outbox 同事务提交,任何结果写入失败均回滚资金变更,原事件保留身份并允许重试。 + +仅 `FIN-WALLET-INSUFFICIENT`、`FIN-WALLET-HOLD-409`、`FIN-IDEMPOTENCY-CONFLICT`、`FIN-REQ-400` 作为明确业务拒绝,在原事务回滚后重新锁定事件、确认无既有最终结果,再保存 FAILED 与结果 Outbox。临时数据库异常、处理中、乐观锁冲突、冻结依赖未到达及其他未分类异常继续抛出,不确认消费成功,不固化为最终业务失败。传输确认仍不等于资金业务成功,Lastleg 继续消费资金结果事件。 + +本条是当前消费者实现规则;单机去桥目标及统一 ACK 见[统一认证与服务通信契约](../统一认证与服务通信契约.md),后者尚未整体落地。 + +### 通用响应 + 错误码是跨服务稳定字符串,message 可本地化且不能作为程序判断依据: | 错误码 | 语义 | 是否重试 | diff --git a/跨区域认证与服务通信契约.md b/跨区域认证与服务通信契约.md index 06ea3ad..77049d9 100644 --- a/跨区域认证与服务通信契约.md +++ b/跨区域认证与服务通信契约.md @@ -1,55 +1,5 @@ -# 跨区域认证与服务通信契约 +# 跨区域认证与服务通信契约(已替代) -## 适用范围 +自 2026-09-29 起,当前目标仅有一个测试环境,服务同机部署。旧双区域认证、独立海外网关及事件桥约束已由[统一认证与服务通信契约](统一认证与服务通信契约.md)替代;部署与切换见[测试环境单机部署与配置契约](测试环境单机部署与配置契约.md)。 -- 本契约适用于 Admin、Client、国内头程服务、海外网关、尾程服务、海外仓资源服务及跨区域事件桥接。 -- 业务范围仍按对应阶段和模块文档确定;本文件只冻结跨区域账号、请求路由、服务鉴权和事件通信边界。 -- 开发/测试同机共置及生产国内/海外双控制面的实际部署拓扑、Nacos、数据库和 Event Bridge 规划见[双区域部署与 Nacos 规划](双区域部署与Nacos规划.md)。 - -## 统一账号与 Token - -- Admin、Client 只维护一套前端和一套用户账号体系;用户登录和 Token 签发统一归国内头程 Auth,不得为海外仓再创建独立登录、账号或权限体系。 -- 统一使用 RS256/JWKS 信任链,但区分 Token 用途:国内登录/刷新时由同一 Auth 同时签发国内 Token 和短时海外 Token;海外 Token 限定海外 Audience,只携带稳定身份、客户范围与版本声明,不携带角色或权限集。 -- 平台 `WAREHOUSE_PICKER` 必须在 IAM 成员关系中绑定一个启用的实际海外收货仓;Auth 将该绑定以可空 `overseas_warehouse_id` Claim 同步写入国内与海外 Token,海外 Token 同时携带账号 `token_version`。该 Claim 只用于已绑定的平台仓管员,页面和 PDA 请求不得传入或覆盖仓库身份;修改或清空仓绑定时 IAM 必须调用 Auth 撤销该账号全部会话并递增 `token_version`,随后重新签发 Token。 -- 用户只登录一次,由前端统一认证模块按目标 API 自动选择 Token,不在页面或业务模块中分叉登录逻辑。 -- JWKS 只暴露公钥验证能力,不暴露私钥;国内服务验证登录 Token 并结合 Redis 会话实现即时退出和权限变更,海外业务服务不访问国内 Redis。`gateway-overseas` 对普通 Admin/Client 海外接口验证海外 Token 的签名、Issuer、Audience、有效期、应用域和客户范围,再按 `userId/tenantId/permissionVersion` 从 Lastleg 安全投影取得当前海外授权快照;仅 `/api/pda/**` 在本地验签后,以内部服务身份向 Auth 发送 `userId/tokenVersion/overseasWarehouseId` 做无缓存实时核对。该调用不得传递 raw Token 或用户凭据,Auth 超时、不可用、账号停用、版本或仓绑定不一致均 fail-closed。 -- 本期普通 Admin/Client 海外 Token 的即时失效范围固定为 IAM 投影的账号停用、客户停用和权限版本推进;Gateway 向 Lastleg 安全投影仅发送 `userId/tenantId/permissionVersion`,旧 Token 被拒绝后客户端必须退出并重新登录。`token_version` 仍是海外 JWT 必填 Claim,但其权威实时比对只用于上述 PDA→Auth 链;普通 Admin/Client 的退出、密码重置或普通会话撤销依赖短时 Token 自然过期,不得宣称已由 Lastleg 即时撤销。 - -## 区域 API 路由 - -- 一套前端使用国内、海外两个区域 API Base:国内业务直连 `gateway/`,海外仓业务直连 `gateway-overseas/`,再由海外网关路由到 `lastleg-service/`、`warehouse-overseas-service/` 和海外部署的公共服务。 -- 日常海外请求不得经国内 Gateway 中转。区域地址、Token 选择和刷新由环境配置与统一 API/认证层处理,业务页面不得感知部署区域差异。 -- 海外浏览器请求的具体 Audience、Claim 和路由以前端项目、`auth/`、`gateway-overseas/` 最近的 `AGENTS.md` 与实际配置为准;修改其中任一项时必须联查全部生产者和消费者。 - -## 跨区域事件与服务身份 - -- 头程与海外仓的数据流转使用 MQ 的 Outbox → Inbox、事件幂等、重试和死信机制。 -- 事件使用版本化信封、事件 ID、业务键、来源/目标区域和 Payload 哈希,不携带用户 Access Token。 -- 费用由海外仓发布事件,头程 Finance 消费并按来源快照入账;财务状态机和结算口径仍由财务契约冻结,海外服务不得自行定义。 -- MQ 使用独立的服务身份、TLS 和 ACL;服务间事件鉴权与用户 JWT 鉴权分开。只有明确的同步 HTTP 内部接口才使用内部服务令牌。 -- 修改事件时联查 `common-event-contract/`、`event-bridge-service/`、生产服务、消费服务、幂等记录、重试/死信和契约测试。 -- 按 FBA 仓拆分的海外派送单在签收完成时,由 Lastleg 在同一事务按关联来源入仓单分别写 `OverseasDeliveryCompleted` V1 Outbox;Event Bridge 定向投递 Firstleg。Firstleg 校验事件信封、客户、来源入仓单/订单、入仓码和 FBA 仓后,只将该来源入仓单从 `LOADED` 推进到 `DELIVERED`;同一 Order 的全部有效入仓单均为 `DELIVERED` 后,才以内部服务身份幂等推进该 Order 到 `COMPLETED`。同车其他 FBA 派送单必须各自签收,不得随整车一起完成。 - -### 国内仓库目录同步读取 - -- 国内 `warehouse-service` 是 Warehouse ID、类型、状态、地址和能力的唯一权威。海外数据库不得复制仓库、地址或服务能力主表。 -- `warehouse-overseas-service` 只保存库位、托盘、资源锁及其国内 `warehouseId` 引用;资源写入和 Lastleg PDA 仓绑定校验通过受内部服务令牌保护的国内只读目录完成。 -- 只允许平台共享、`OVERSEAS`、`ACTIVE` 且启用 `RECEIVING` 的仓作为海外实际收货仓。低频正结果可缓存 30 分钟,空目录、不存在和停用结果不得长缓存。 -- FBA 目的仓同样只以国内 `warehouse-service` 的平台公共主数据为权威,但语义与海外实际收货仓严格分离:Admin 候选使用 `warehouseType=FBA&status=ACTIVE` 的平台仓库分页;Lastleg 写入通过受内部服务令牌保护的 `/internal/warehouses/0/{warehouseId}/active` 读取当前事实,并继续校验 `warehouseType=FBA` 及 ID/编码/名称一致。`OVERSEAS`、`OVERSEAS_PARTNER` 或 `DOMESTIC` 均不得作为 FBA 目的仓。 - -### IAM 安全事件海外投影冻结 - -- `IamUserStatusChanged`、`IamTenantStatusChanged`、`IamPermissionVersionChanged` V1 固定由 Lastleg 独立安全入口 `/internal/lastleg/security/v1/events` 消费;不得投递到 Lastleg 的 LoadingCompletedConsumer。 -- 安全状态只使用 `ACTIVE`/`DISABLED`:`IamTenantStatusChanged` 仅在 IAM 客户业务状态为 `ACTIVE` 时发布 `ACTIVE`,`PROFILE_REQUIRED`、`PENDING`、`REJECTED`、`DISABLED`、`ARCHIVED` 及其他不可用状态统一折叠为 `DISABLED`。Lastleg 只校验该两态安全快照,不解释国内建档/审核工作流。 -- Event Bridge 只按冻结的 eventType→consumer URL 选择下游,不解析状态、权限版本或 payload 业务字段。海外业务事件仍投 Lastleg,国内回流事件仍投 Firstleg。 -- Lastleg 以 MySQL `ll_security_event_inbox` 和 `ll_security_projection` 为可靠来源:eventId 相同 hash 相同幂等,异 hash 冲突;聚合版本只单调推进,旧版本标记 STALE,同版本异 hash 冲突。Redis 仅为提交后写入的可重建镜像,授权校验不依赖 Redis 默认放行。 -- 海外 Gateway 对全部 `/api/**` 在本地 JWT 验签后,传递 `userId/tenantId/permissionVersion` 到 Lastleg 安全入口。Lastleg 校验通过时返回该版本的角色与海外权限快照,Gateway 清除外部伪造的授权头后,以内部服务令牌保护的可信头传给海外业务服务。业务服务必须同时验证 JWT 和内部服务令牌,不得从 JWT 回退读取完整权限集。用户停用返回 A0401;客户停用或 Token 权限版本不一致返回 A0403;安全投影、SQL 或调用链不可用均 fail-closed。PDA 在此基础上继续执行 Auth 仓绑定实时核验。 -- Auth 的登录、刷新和海外 Token 兑换响应在响应体中返回当前 `roles/authorities` 授权快照;国内与海外 JWT 都只保留主体、客户、成员、应用、版本和海外仓绑定等最小身份 Claim,不携带角色或权限集合。客户端可用响应快照做入口展示或本地前置提示,但每次业务请求的最终授权仍由 Gateway/Lastleg 的实时投影决定;客户端不得再从 JWT 解析角色或权限,也不得把响应快照作为绕过服务端校验的依据。 -- 新客户创建、审核激活以及新用户授权均由 IAM 在业务事务内写初始安全事件。开发阶段不提供历史账号长期 Bootstrap 或兼容入口;固定 `platform_admin` 由 Lastleg 数据库基线初始化 version=0 的 USER/AUTHORIZATION 投影,其中 AUTHORIZATION 冻结当前 `PLATFORM_ADMIN` 角色及 IAM 跨区前缀下的完整权限集合,空库重建后无需人工补投即可访问海外接口,后续 version>=1 的真实 IAM 事件单调覆盖。其他既有开发账号仍须由总控按 IAM 当前事实一次性重建授权快照;任何缺失投影继续 fail-closed,不能在 Lastleg 运行时代填或默认放行。 - -## 修改与验收 - -- Token、Audience、Claim、JWKS、API Base 或刷新策略变化时,至少联查 Auth、IAM、Admin/Client 统一认证层、国内/海外 Gateway、`common-security/` 和目标海外服务。 -- `overseas_warehouse_id` 变化时还需联查 IAM 平台用户维护、海外 PDA、Lastleg 收货会话及 Warehouse Overseas 共享仓校验;验收必须同时覆盖未绑定拒绝、非仓管角色禁止绑定和换仓后旧 Token 失效。 -- 跨区域事件变化时同步检查事件版本、Payload 哈希、Outbox、Inbox、重复投递、失败重试、死信和全部实际消费者。 -- 本文件是跨区域通信的公共事实来源;项目和模块 `AGENTS.md` 只保留执行所需摘要及本文件入口,不复制完整协议。 +此文件仅保留旧链接入口,不再定义有效规则。目标已确认不代表当前代码和环境已经迁移完成。