From 893d1801b5aee778ee116451a7f631ddef6dfbda Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 20 Aug 2026 19:55:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 17 +- common-event-contract/AGENTS.md | 6 +- deploy/sql/README.md | 2 +- deploy/sql/海外区域统一增量-MySQL8.sql | 6 +- event-bridge-service/AGENTS.md | 5 +- file/AGENTS.md | 1 + finance/AGENTS.md | 2 + firstleg/AGENTS.md | 2 + lastleg-service/AGENTS.md | 6 +- .../src/main/resources/db/lastleg.sql | 2 + scripts/README.md | 1 + scripts/agents-index-contract.ps1 | 152 ++++++++++++++++++ .../src/main/resources/db/warehouse.sql | 2 + 13 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 scripts/agents-index-contract.ps1 diff --git a/AGENTS.md b/AGENTS.md index afc6b887d..ba6956a59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,7 @@ | 分柜、柜次、智能排柜、预装/装柜清单、PDA | `firstleg/` | `firstleg/AGENTS.md`,再按 `split/`、`loading/`、`outbound/` 定位 | | 订舱、船期、拖车、报关 | `firstleg/` | `oceanbooking/`、`portschedule/`、`outbound/dispatch/`、`customs/` | | 客户账期、费用池、账单、收款、成本、核销 | `finance/` | `finance/AGENTS.md`;费用来源和柜次成本快照再联查 `firstleg/AGENTS.md`,凭证再联查 `file/AGENTS.md` | +| 入库/柜次应付、直接已付、付款流水与凭证 | `firstleg/`、`finance/`、`file/` | 业务费用与付款快照见 `firstleg/AGENTS.md` 的 `FeePaymentSnapshotValidator`;`/api/platform/finance/v1/vouchers` 上传凭证,File 按 `FINANCE_VOUCHER` 和客户范围校验 | | 仓库、往来单位、快递、托盘、库位 | `warehouse/` | `warehouse/AGENTS.md` | | 供应商、国内整柜库存与出入库 | `warehouse/` | `warehouse/AGENTS.md`;OpenAPI `warehouse/src/main/resources/openapi/supplier-v1.yaml`、`domestic-container-v1.yaml` | | 客户运营统计、在途柜量 | `firstleg/` | `firstleg/AGENTS.md`;OpenAPI `firstleg/src/main/resources/openapi/customer-statistics-v1.yaml` | @@ -35,8 +36,21 @@ | 百度/Amazon/OCR/第三方适配 | `integration-service/` | `integration-service/AGENTS.md` | | 海外 API 路由、海外 Token、Audience/JWKS | `gateway-overseas/` | `gateway-overseas/AGENTS.md` | | 尾程订单、海外入仓计划、换标、库存、采购、本土卡车 | `lastleg-service/` | `lastleg-service/AGENTS.md`,再按 `inboundplan/`、`relabel/`、`inventory/`、`procurement/`、`trucking/` 定位 | +| 海外入仓分页、FBA 预约、PDA 卸柜照片 | `lastleg-service/` | `inboundplan/controller/InboundPlanController.java`、`InboundPlanQueryMapper.java`、`InboundFbaAppointmentService.java`、`inboundplan/pda/` | | 海外仓库、海外库位、海外托盘、资源锁 | `warehouse-overseas-service/` | `warehouse-overseas-service/AGENTS.md` | -| PDF 标签、审计、事件 | `print/`、`audit-service/`、`event-bridge-service/` | 各服务指引 | +| PDF 标签、审计、跨区双向事件 | `print/`、`audit-service/`、`event-bridge-service/` | 事件模型先读 `common-event-contract/AGENTS.md`;可靠投递与 CN/OVERSEAS 目标路由读 `event-bridge-service/AGENTS.md` | + +## 公共模块快速索引 + +| 关键词 | 模块与入口 | +|---|---| +| 公共依赖版本 | `platform-bom/pom.xml`;统一管理公共组件版本,不放业务实现 | +| 通用响应、分页、异常、基础实体与导出契约 | `common-core/`;从 `ApiResponse.java`、`PageResult.java`、`BizException.java`、`ExportContracts.java` 定位 | +| Web 异常、请求关联 ID、Long ID 序列化 | `common-web/`;从 `GlobalExceptionHandler.java`、`CorrelationIdFilter.java`、`LongIdJacksonConfiguration.java` 定位 | +| JWT、JWKS、会话校验与认证用户 | `common-security/`;从 `JwtAuthenticationFilter.java`、`JwtClaimsMapper.java`、`AccessTokenSessionValidator.java` 定位 | +| Springdoc/OpenAPI 自动配置 | `common-openapi/`;从 `BaiyueOpenApiAutoConfiguration.java`、`OpenApiProperties.java` 定位 | +| 业务审计注解、脱敏、Outbox 与投递 | `common-audit/`;从 `BusinessAudit.java`、`BusinessAuditAspect.java`、`SensitiveDataSanitizer.java`、`AuditOutboxPublisher.java` 定位 | +| 跨区域事件信封、Payload 与哈希 | `common-event-contract/`;继续读该目录 `AGENTS.md` | ## 全量验收路由 @@ -60,6 +74,7 @@ - 数据库只访问所属服务库。模块表结构位于 `/src/main/resources/db/`;当前开发阶段直接更新最新模块基线和 `deploy/sql/头程数据库统一增量-MySQL8.sql`,不为历史开发数据新增兼容迁移。已有名称含 `migration` 的脚本仅作现有结构来源和开发追溯,部署说明见 `deploy/sql/README.md`。 - 通用配置在 `config/nacos/{local,cn}/`;服务日志、上传文件、`target/`、`reports/` 不属于源码。 - Java 签名变更的最低编译门禁是 `mvn -pl -am test-compile`,它必须在部署前完成并覆盖测试源码;有行为变化时继续运行 `mvn -pl -am test`。`-DskipTests` 可跳过测试执行但仍须保留测试编译,`-Dmaven.test.skip=true` 会跳过测试编译,不得作为签名变更的交付验证。全量验证仍使用 `mvn -DskipTests validate`、`mvn test`;不要在本地启动 Java/Nacos/数据库,除非用户明确要求。 +- `AGENTS.md` 索引维护完成后运行 `./scripts/agents-index-contract.ps1`;脚本只读源码目录和指定指引,验证部署单元、模块覆盖、关键入口与排除目录,不访问 HTTP、数据库或部署环境。 ## 全量 HTTP 验收脚本路由 diff --git a/common-event-contract/AGENTS.md b/common-event-contract/AGENTS.md index 6b92556e4..5981564aa 100644 --- a/common-event-contract/AGENTS.md +++ b/common-event-contract/AGENTS.md @@ -14,10 +14,12 @@ | 事件 ID 与业务键 | `EventIdentifiers.java` | | Payload 规范化与哈希 | `EventPayloadCanonicalizer.java`、`EventPayloadHash.java` | | 事件类型与区域 | `EventTypes.java`、`RegionCode.java` | -| 头程装柜完成 V1 | `FirstLegLoadingPlanCompletedV1.java`;国内生产者见 `../firstleg/src/main/java/com/baiyue/firstleg/service/LoadingCompletedOutboxService.java` | +| 头程装柜完成 V2(当前生产) | `FirstLegLoadingPlanCompletedV2.java`;国内生产者见 `../firstleg/src/main/java/com/baiyue/firstleg/service/LoadingCompletedOutboxService.java`,海外消费者见 `../lastleg-service/src/main/java/com/baiyue/lastleg/service/LoadingCompletedConsumer.java` | +| 头程装柜完成 V1 解析模型 | `FirstLegLoadingPlanCompletedV1.java`;用于消费端冻结字段映射,新增生产不得回退为 V1 | | 海外卸柜完成 V1 | `OverseasContainerUnloadedV1.java`;海外生产者见 `../lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundUnloadCompletedOutboxService.java`,国内消费者见 `../firstleg/src/main/java/com/baiyue/firstleg/service/OverseasContainerEventConsumer.java` | +| IAM 安全事件 V1 | `IamSecurityEventsV1.java`;账号、授权快照等安全事件的冻结模型 | | 契约说明 | `package-info.java` | -| 契约测试 | `src/test/java/com/baiyue/common/event/EventEnvelopeTest.java`、`FirstLegLoadingPlanCompletedV1Test.java`、`OverseasContainerUnloadedV1Test.java` | +| 契约测试 | `src/test/java/com/baiyue/common/event/EventEnvelopeTest.java`、`FirstLegLoadingPlanCompletedV1Test.java`、`FirstLegLoadingPlanCompletedV2Test.java`、`OverseasContainerUnloadedV1Test.java` | ## 修改与验证 diff --git a/deploy/sql/README.md b/deploy/sql/README.md index 486bd1d5b..e120a9295 100644 --- a/deploy/sql/README.md +++ b/deploy/sql/README.md @@ -3,7 +3,7 @@ ## 唯一数据库初始化与发布入口 - 国内区域固定入口:`头程数据库统一增量-MySQL8.sql`。文件名保留历史兼容,内容维护为当前完整数据库基线和存量环境兼容升级,不再按日期拆分发布脚本。 -- 海外区域固定入口:`海外区域统一增量-MySQL8.sql`;当前包含海外仓报价结构,后续海外主数据继续追加到同一入口,不按日期拆分。 +- 海外区域固定增量入口:`海外区域统一增量-MySQL8.sql`;空库先执行 `lastleg-service/src/main/resources/db/lastleg.sql` 基线,再执行该入口。当前包含海外仓报价结构,后续海外主数据继续追加到同一入口,不按日期拆分。 - 国内、海外 Compose 部署默认设置 `SPRING_SQL_INIT_MODE=never`,执行任一 SQL 均需用户单独授权。 - 该脚本汇总一期、二期及已实现三期出仓能力的数据库基线、存量升级、IAM 权限资源和最终结构校验,适用于 MySQL 8.0。 - 正式上线前的数据库变更直接维护该文件中的当前基线、存量兼容处理和最终校验,不再创建按日期拆分的发布 SQL;正式上线后的迁移策略在生产发布规范中另行冻结。 diff --git a/deploy/sql/海外区域统一增量-MySQL8.sql b/deploy/sql/海外区域统一增量-MySQL8.sql index 975fabc23..582ae2ad0 100644 --- a/deploy/sql/海外区域统一增量-MySQL8.sql +++ b/deploy/sql/海外区域统一增量-MySQL8.sql @@ -1,4 +1,8 @@ --- 海外区域固定 SQL 入口。只由人工审核执行;服务部署默认不自动执行 SQL。 +-- 海外区域固定增量入口。空库先执行 lastleg-service/src/main/resources/db/lastleg.sql 基线; +-- 本文件只由人工审核执行,服务部署默认不自动执行 SQL。 +SET NAMES utf8mb4; +CREATE DATABASE IF NOT EXISTS baiyue_lastleg + DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE baiyue_lastleg; CREATE TABLE IF NOT EXISTS ll_event_outbox ( diff --git a/event-bridge-service/AGENTS.md b/event-bridge-service/AGENTS.md index 7e2e6672b..aa40eee17 100644 --- a/event-bridge-service/AGENTS.md +++ b/event-bridge-service/AGENTS.md @@ -2,7 +2,7 @@ ## 职责边界 -- 负责跨区事件接收、Inbox 持久化、向海外尾程投递、失败重试、投递记录和人工补投。 +- 负责跨区事件接收、Inbox 持久化、按目标区域向海外尾程或国内头程投递、失败重试、投递记录和人工补投。 - 只承载可靠传输,不执行尾程建单逻辑,不查询头程或尾程业务表。 - 事件结构和 Payload 哈希以 `common-event-contract` 为准。 @@ -12,8 +12,9 @@ |---|---| | 接收、状态、人工补投 API | `src/main/java/com/baiyue/eventbridge/controller/EventBridgeController.java` | | Inbox 接收与幂等 | `service/EventInboxService.java` | -| 海外调度与重试 | `service/OverseasEventDispatcher.java` | +| 按目标区域调度与重试 | `service/OverseasEventDispatcher.java`;`targetRegion=OVERSEAS` 投 Lastleg,`targetRegion=CN` 回投 Firstleg | | 尾程 HTTP 客户端 | `service/LastlegEventClient.java`、`HttpLastlegEventClient.java` | +| 国内头程 HTTP 客户端 | `service/FirstlegEventClient.java`、`HttpFirstlegEventClient.java`;默认内部入口 `/internal/firstleg/v1/container-events` | | 人工补投 | `service/EventReplayService.java` | | Inbox 与投递记录 | `domain/BridgeInbox.java`、`BridgeDeliveryAttempt.java` 及对应 Mapper | | 内部服务令牌 | `security/InternalServiceTokenGuard.java` | diff --git a/file/AGENTS.md b/file/AGENTS.md index 47a1deec8..0a6a87575 100644 --- a/file/AGENTS.md +++ b/file/AGENTS.md @@ -13,6 +13,7 @@ | 导出中心 | `controller/PlatformExportTaskController.java`、`service/ExportTaskService.java`、`service/ExportStateService.java`、`service/GenericXlsxExportRunner.java`、`config/ExportDefinitionRegistry.java`、`client/ExportProviderClient.java`、`mq/` | | 测量图片/证据 | `controller/PlatformMeasurementImageController.java`、`InternalMeasurementImageController.java`、`service/MeasurementImageService.java` | | 装柜与业务文件证据 | `controller/PlatformLoadingEvidenceController.java`、`InternalLoadingEvidenceController.java`、`InternalBusinessFileController.java`、`service/InternalBusinessFileService.java` | +| 财务付款凭证、海外卸柜照片 | 通用业务文件入口 `InternalBusinessFileController.java`、`InternalBusinessFileService.java`;业务类型分别为 `FINANCE_VOUCHER`、`OVERSEAS_UNLOAD_PHOTO`,必须按客户与业务 ID 精确校验 | | 存储与实体 | `service/LocalQualificationStorage.java`、`MeasurementImageStorage.java`、`entity/FileObjectEntity.java` | | 下游 OCR | `client/WeightOcrClient.java` | | SQL/配置 | `src/main/resources/db/file.sql`、`application.yml` | diff --git a/finance/AGENTS.md b/finance/AGENTS.md index c9d1f04b2..eb5fbbf79 100644 --- a/finance/AGENTS.md +++ b/finance/AGENTS.md @@ -11,6 +11,7 @@ | 目标 | 首选入口 | |---|---| | 平台账户、费用池、账单、收款与成本 API | `controller/PlatformFinanceController.java`,统一前缀 `/api/platform/finance/v1` | +| 平台财务凭证上传 | `PlatformFinanceController.java` 的 `POST /vouchers`、`client/FinanceFileClient.java`;文件类型固定 `FINANCE_VOUCHER`,业务 ID/客户范围使用当前客户 ID | | 客户只读账单、收款与应收 API | `controller/ClientFinanceController.java`,统一前缀 `/api/client/finance/v1` | | 一期账户、费用来源审核与结算纳入 | `controller/FinancePhase1OperationController.java`、`service/FinancePhase1OperationService.java` | | 客户财务账户汇总 | `service/FinanceCustomerAccountService.java`、`client/IamCustomerClient.java`;客户主档事实仍归 IAM | @@ -46,6 +47,7 @@ - 应付费用来源、成本登记和应付结算单引用的供应商必须通过 Warehouse 校验 ID 与 `ACTIVE` 状态;费用项目 `supplierCategory` 为空时允许任意启用供应商,非空时严格校验类别,不得从费用编码或名称猜测。名称快照只能取 Warehouse 返回值,不能接受自由文本替代。Warehouse 不可用、供应商停用或非空类别不匹配时必须失败关闭;修改该链路时同步检查事件消费、人工成本、结算创建/付款、Nacos 客户端地址和双方契约测试。 - 修改平台或客户 DTO 时同步检查 Admin `../../apps/admin-web/src/modules/finance/`、Client `../../apps/client-web/src/modules/finance/`、Gateway 路由、权限码和契约测试;客户响应不得暴露供应商成本、内部备注、平台凭证或其他客户数据。 - 修改 Finance 导出字段、筛选或 `exportType` 时,同步检查 `FinanceExportProviderService`、File `ExportDefinitionRegistry`/`ExportProviderClient`、Admin `modules/finance/` 与 `modules/downloads/`、导出权限和双方契约测试;页面只创建异步下载任务,不绕过 File 导出中心直接拼装业务文件。 +- Finance 费用池必须保留上游 `direction`、客户/供应商名称和付款证据快照;Firstleg 的 `DIRECT_PAID` 校验仍归 Firstleg。Finance 上传端只创建受客户范围约束的 `FINANCE_VOUCHER` 文件,不替代上游费用审核与付款快照校验。 ## 验证 diff --git a/firstleg/AGENTS.md b/firstleg/AGENTS.md index 1a711b5d1..9a8cc9486 100644 --- a/firstleg/AGENTS.md +++ b/firstleg/AGENTS.md @@ -18,6 +18,7 @@ | 审核与初始计价 | `controller/PlatformInboundMeasurementReviewController.java`、`service/MeasurementReviewService.java`、`service/InitialInboundPricingService.java`、`dto/MeasurementApprovalResponse.java` | | FBA 主数据/计费 | `controller/PlatformFbaMasterDataController.java`、`PlatformFbaPricingController.java`、`service/FbaPricingService.java` | | 入库费用明细 | `controller/PlatformInboundFeeDetailController.java`、`service/InboundFeeDetailService.java`、`dto/InboundFeeDetailDtos.java`;Admin 消费端见 `../../apps/admin-web/src/modules/unified-orders/api/inboundFeeDetails.ts` | +| 入库/柜次直接已付快照与凭证校验 | `service/FeePaymentSnapshotValidator.java`、`client/FeePaymentVoucherFileClient.java`;写入入口分别为 `InboundFeeDetailService.java`、`ContainerFeeDetailService.java`,File 业务类型固定 `FINANCE_VOUCHER` | | 客户费用查询 | `controller/MerchantInboundBillingController.java`、`service/MerchantInboundBillingService.java` | | 客户运营统计/在途柜量 | `customerstatistics/controller/PlatformCustomerTransitStatisticsController.java`、`customerstatistics/service/CustomerTransitStatisticsService.java`;契约见 `src/main/resources/openapi/customer-statistics-v1.yaml` | | 费用项目与价格簿 | `controller/PlatformFeeItemController.java`、`PlatformPriceBookController.java`、`MerchantPriceBookController.java` | @@ -53,6 +54,7 @@ - 四期船节点任务从确认柜子离开国内仓库后启用,必须绑定真实订舱和柜次;标准节点固定为 `DEPARTED_WAREHOUSE → AT_ORIGIN_PORT → DEPARTED_ORIGIN_PORT → IN_TRANSIT → ARRIVED → PICKUP_READY`,保存来源、节点观测时间、最近成功结果、失败尝试及完整历史。现有 `CarrierScheduleQuery` 及“正常每 3 天一次、窗口最多 3 次、失败指数退避”约束属于四期;租约、调度尝试和内部停止入口不得暴露为平台页面 API,外部失败不得推进业务节点,不得在三期另建查询任务。 - 海外卸柜完成事件只接受 `OVERSEAS -> CN` 的 `OVERSEAS_CONTAINER_UNLOADED` V1,并通过内部服务令牌进入。消费者必须校验信封、Payload 哈希、来源货柜和时间顺序,以 event ID + Payload 哈希幂等,使用事件聚合版本阻止乱序覆盖;预计报空时间固定按卸柜照片上传时间加两天计算,实际报空时间可为空。 - Firstleg 只拥有业务费用及履约事实;Finance 拥有费用入池、账期、账单、收款、成本分摊结果和财务状态。修改费用来源版本、发布条件、柜次归属或体积快照时同步检查 `../finance/src/main/java/com/baiyue/finance/client/FirstlegFeeSourceClient.java`、同目录 `FirstlegCostSnapshotClient.java` 及双方契约测试,不在 Firstleg 复制财务状态机。 +- `DIRECT_PAID` 仅适用于 `PAYABLE`,必须同时保存 `paidAt`、合法 `paymentMethod`,并至少提供 `paymentReferenceNo` 或一个当前客户范围内的 `FINANCE_VOUCHER`;`RECEIVABLE` 与 `ON_ACCOUNT` 不得残留付款字段。创建、调整和审核前均通过 `FeePaymentSnapshotValidator` 失败关闭复核。 ## 三期装柜与 PDA 资源结算 diff --git a/lastleg-service/AGENTS.md b/lastleg-service/AGENTS.md index 08dc82844..39b3a4453 100644 --- a/lastleg-service/AGENTS.md +++ b/lastleg-service/AGENTS.md @@ -11,15 +11,17 @@ | 功能 | 入口 | |---|---| | 事件接收、订单列表/详情/导出、目的仓调整 | `src/main/java/com/baiyue/lastleg/controller/LastlegOrderController.java` | -| 装柜完成事件消费 | `service/LoadingCompletedConsumer.java` | +| 装柜完成事件消费 | `service/LoadingCompletedConsumer.java`;当前生产信封为 `FIRST_LEG_LOADING_PLAN_COMPLETED` V2,消费端按冻结字段校验后建单 | | 尾程单号生成 | `service/LastlegOrderNoGenerator.java` | | 订单查询与更新 | `service/LastlegOrderService.java` | | 业务 Inbox | `entity/LastlegEventInbox.java`、`mapper/LastlegEventInboxMapper.java` | | 尾程订单、明细、状态历史 | `entity/LastlegOrder.java`、`LastlegOrderDetail.java`、`LastlegOrderStatusHistory.java` 及对应 Mapper | | 内部令牌保护 | `security/InternalServiceTokenGuard.java` | -| 入仓计划分页、转换与详情 | `inboundplan/controller/InboundPlanController.java`、`inboundplan/dto/InboundPlanRequests.java`、`InboundPlanSummary.java`、`inboundplan/service/InboundPlanService.java` | +| 入仓计划分页、转换与详情 | `inboundplan/controller/InboundPlanController.java`、`inboundplan/dto/InboundPlanRequests.java`、`InboundPlanListResponse.java`、`inboundplan/mapper/InboundPlanQueryMapper.java`、`inboundplan/service/InboundPlanService.java` | | 托盘分配算法 | `inboundplan/service/PalletAllocator.java` | +| FBA 预约创建、详情与编辑 | `InboundPlanController.java` 的 `/fba-appointments/**`、`inboundplan/service/InboundFbaAppointmentService.java`、`BatchFbaAppointmentRequest.java`、`UpdateFbaAppointmentRequest.java` | | PDA 入仓、实收、上架、合托、完成 | `inboundplan/pda/controller/`、`inboundplan/pda/service/InboundPdaWorkflowService.java`;入口固定为 `/api/pda/v1/last-leg/**`,不得挂入平台浏览器 API | +| PDA 卸柜照片文件上传与归属校验 | `InboundPdaController.java` 的 `/unload-photos/files`、`inboundplan/pda/gateway/UnloadPhotoFileGateway.java`、`HttpUnloadPhotoFileGateway.java`;File 类型固定 `OVERSEAS_UNLOAD_PHOTO` | | 卸柜照片与海外卸柜完成 Outbox | `inboundplan/pda/controller/InboundPdaController.java`、`inboundplan/pda/service/InboundUnloadCompletedOutboxService.java`、`entity/LastlegEventOutbox.java`、`mapper/LastlegEventOutboxMapper.java`;事件模型见 `../common-event-contract/AGENTS.md` | | 入仓后 SKU 库存余额、库位和流水 | `inventory/`;平台只读查询与非出库库存命令分别从 `inventory/query/controller/InventoryQueryController.java`、`inventory/command/controller/InventoryCommandController.java` 进入 | | 仓储资源调用 | `inboundplan/pda/gateway/WarehouseResourceGateway.java`、`HttpWarehouseResourceGateway.java` | diff --git a/lastleg-service/src/main/resources/db/lastleg.sql b/lastleg-service/src/main/resources/db/lastleg.sql index a715465cf..e8bb9021a 100644 --- a/lastleg-service/src/main/resources/db/lastleg.sql +++ b/lastleg-service/src/main/resources/db/lastleg.sql @@ -1,3 +1,5 @@ +SET NAMES utf8mb4; + CREATE DATABASE IF NOT EXISTS baiyue_lastleg DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE baiyue_lastleg; diff --git a/scripts/README.md b/scripts/README.md index 8b4e5ba46..06dc4f67f 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -31,6 +31,7 @@ node scripts/create-pending-review-orders.mjs | Admin/Client 本地测试与类型检查 | `scripts/frontend-full-regression.ps1` | | PDA 本地页面和状态测试 | `../apps/pda-uniapp/tests/*.test.mjs` | | 本地数据库 SQL 静态/受控验收 | `scripts/local-db-full-acceptance.ps1` | +| AGENTS 快速索引一致性 | `scripts/agents-index-contract.ps1`;只读核对部署单元、业务模块、PDA 注册页面、Maven 模块、关键入口与排除目录 | Admin/Client HTTP 脚本的离线合同只验证脚本结构、参数和模块边界,不访问测试环境: diff --git a/scripts/agents-index-contract.ps1 b/scripts/agents-index-contract.ps1 new file mode 100644 index 000000000..7e4eaa97f --- /dev/null +++ b/scripts/agents-index-contract.ps1 @@ -0,0 +1,152 @@ +[CmdletBinding()] +param() + +$ErrorActionPreference = 'Stop' + +$backendRoot = Split-Path -Parent $PSScriptRoot +$workspaceRoot = Split-Path -Parent $backendRoot +$failures = [System.Collections.Generic.List[string]]::new() +$checked = 0 + +function Add-Failure([string]$message) { + $script:failures.Add($message) +} + +function Read-RequiredText([string]$path) { + $script:checked++ + if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { + Add-Failure "缺少索引文件: $path" + return '' + } + return Get-Content -LiteralPath $path -Raw +} + +function Assert-Contains([string]$text, [string]$needle, [string]$scope) { + $script:checked++ + if (-not $text.Contains($needle)) { + Add-Failure "$scope 未索引: $needle" + } +} + +function Assert-Path([string]$relativePath) { + $script:checked++ + $absolutePath = Join-Path $workspaceRoot $relativePath + if (-not (Test-Path -LiteralPath $absolutePath)) { + Add-Failure "索引入口不存在: $relativePath" + } +} + +$rootAgentsPath = Join-Path $workspaceRoot 'AGENTS.md' +$adminAgentsPath = Join-Path $workspaceRoot 'apps/admin-web/AGENTS.md' +$clientAgentsPath = Join-Path $workspaceRoot 'apps/client-web/AGENTS.md' +$pdaAgentsPath = Join-Path $workspaceRoot 'apps/pda-uniapp/AGENTS.md' +$backendAgentsPath = Join-Path $backendRoot 'AGENTS.md' + +$rootAgents = Read-RequiredText $rootAgentsPath +$adminAgents = Read-RequiredText $adminAgentsPath +$clientAgents = Read-RequiredText $clientAgentsPath +$pdaAgents = Read-RequiredText $pdaAgentsPath +$backendAgents = Read-RequiredText $backendAgentsPath + +# 部署单元必须能从根索引进入。 +Get-ChildItem -LiteralPath (Join-Path $workspaceRoot 'apps') -Directory | + Sort-Object Name | + ForEach-Object { Assert-Contains $rootAgents "apps/$($_.Name)/" '根 AGENTS.md' } +Assert-Contains $rootAgents 'baiyue-firstleg/' '根 AGENTS.md' + +# 前端当前全部业务模块必须能从应用级索引命中。 +$applications = @( + @{ Root = 'apps/admin-web/src/modules'; Text = $adminAgents; Scope = 'Admin AGENTS.md' }, + @{ Root = 'apps/client-web/src/modules'; Text = $clientAgents; Scope = 'Client AGENTS.md' } +) +foreach ($application in $applications) { + foreach ($moduleDirectory in (Get-ChildItem -LiteralPath (Join-Path $workspaceRoot $application.Root) -Directory | Sort-Object Name)) { + Assert-Contains $application.Text "modules/$($moduleDirectory.Name)/" $application.Scope + } +} + +# PDA 只检查 pages.json 正式注册页面,不把空目录或未注册原型纳入索引。 +$pagesJsonPath = Join-Path $workspaceRoot 'apps/pda-uniapp/pages.json' +$pagesJson = Get-Content -LiteralPath $pagesJsonPath -Raw | ConvertFrom-Json +$registeredPageRoots = $pagesJson.pages.path | + ForEach-Object { $parts = $_ -split '/'; "$($parts[0])/$($parts[1])/" } | + Sort-Object -Unique +foreach ($pageRoot in $registeredPageRoots) { + Assert-Contains $pdaAgents $pageRoot 'PDA AGENTS.md' +} + +# Maven 聚合声明的全部历史/当前模块必须在后端根指引中可定位。 +[xml]$pom = Get-Content -LiteralPath (Join-Path $backendRoot 'pom.xml') -Raw +foreach ($module in $pom.project.modules.module) { + Assert-Contains $backendAgents "$module/" '后端 AGENTS.md' +} + +# 对本轮高变化链路做精确文件门禁,防止改名或删除后留下悬空索引。 +$criticalPaths = @( + 'apps/admin-web/src/modules/overseas-warehouse/api/inboundOrders.ts', + 'apps/admin-web/src/modules/overseas-warehouse/api/inboundPlans.ts', + 'apps/admin-web/src/modules/overseas-warehouse/api/inventory.ts', + 'apps/admin-web/src/modules/overseas-warehouse/api/pallets.ts', + 'apps/admin-web/src/modules/overseas-business/api/platformOverseasBusiness.ts', + 'apps/admin-web/src/modules/overseas-master-data/api/overseasMasterData.ts', + 'apps/pda-uniapp/pages/tasks/tasks.vue', + 'apps/pda-uniapp/utils/evidence-upload-queue.js', + 'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/FeePaymentSnapshotValidator.java', + 'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/client/FeePaymentVoucherFileClient.java', + 'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/mapper/InboundPlanQueryMapper.java', + 'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java', + 'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/UnloadPhotoFileGateway.java', + 'baiyue-firstleg/event-bridge-service/src/main/java/com/baiyue/eventbridge/service/FirstlegEventClient.java', + 'baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV2.java' +) +$criticalPaths | ForEach-Object { Assert-Path $_ } + +# 只检查明确维护的快速索引表,避免把排除规则正文中的目录名误判为业务入口。 +$indexedAgentFiles = @( + $rootAgentsPath, + $adminAgentsPath, + $clientAgentsPath, + $pdaAgentsPath, + $backendAgentsPath, + (Join-Path $backendRoot 'firstleg/AGENTS.md'), + (Join-Path $backendRoot 'finance/AGENTS.md'), + (Join-Path $backendRoot 'lastleg-service/AGENTS.md'), + (Join-Path $backendRoot 'event-bridge-service/AGENTS.md'), + (Join-Path $backendRoot 'file/AGENTS.md'), + (Join-Path $backendRoot 'common-event-contract/AGENTS.md') +) +$excludedTargetPattern = '(?i)`(?:[^`]*/)?(node_modules|node_modules\.broken-by-path|dist|target|reports|output|outputs|uni_modules|\.git|\.codex[^/`]*)(?:/|`)' +$excludedPatternSamples = @( + '| 错误入口 | `node_modules/pkg/` |', + '| 错误入口 | `src/target/classes/` |', + '| 错误入口 | `.codex-temp/task/` |' +) +foreach ($sample in $excludedPatternSamples) { + $script:checked++ + if ($sample -notmatch $excludedTargetPattern) { + Add-Failure "排除目录检测器自检失败: $sample" + } +} +foreach ($agentFile in $indexedAgentFiles) { + $script:checked++ + if (-not (Test-Path -LiteralPath $agentFile -PathType Leaf)) { + Add-Failure "缺少受检索引文件: $agentFile" + continue + } + $lineNumber = 0 + foreach ($line in Get-Content -LiteralPath $agentFile) { + $lineNumber++ + if ($line.StartsWith('|') -and $line -match $excludedTargetPattern) { + Add-Failure "快速索引引用了排除目录: $agentFile`:$lineNumber" + } + } +} + +if ($failures.Count -gt 0) { + Write-Host "AGENTS 索引合同失败,共 $($failures.Count) 项:" -ForegroundColor Red + $failures | ForEach-Object { Write-Host "- $_" -ForegroundColor Red } + exit 1 +} + +Write-Host "AGENTS 索引合同通过:$checked 项检查,覆盖部署单元、前端模块、PDA 注册页面、Maven 模块、关键入口和排除目录。" -ForegroundColor Green +exit 0 diff --git a/warehouse-overseas-service/src/main/resources/db/warehouse.sql b/warehouse-overseas-service/src/main/resources/db/warehouse.sql index 109771014..7654de69b 100644 --- a/warehouse-overseas-service/src/main/resources/db/warehouse.sql +++ b/warehouse-overseas-service/src/main/resources/db/warehouse.sql @@ -3,6 +3,8 @@ -- database creation and USE are intentionally forbidden here so a miswired -- service account cannot create or switch schemas during startup. +SET NAMES utf8mb4; + CREATE TABLE IF NOT EXISTS wh_location ( id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)', customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',