本文解决的不是“系统里有哪些接口”,而是“一个请求究竟从哪里进入、如何获得用户和服务站上下文、怎样找到真实业务代码、成功或失败如何表达、发生异常时从哪一层开始查”。

DGJ2.0 不是统一 REST 架构。当前代码同时保留 PC 控制器、inner JSON 接口、App tradeCode 网关、直接 App/PDA Controller、老 OpenAPI、全车件代理路由、报表导出、CLI/MQ 消费者等多代入口。相同业务可能由多种入口复用同一个 Service,因此只修一个 Controller 或只回归一个页面是不够的。

1. 业务目标

  • 看见 URL、tradeCode、transCode、routing key 或 CLI 命令后,能在 3 分钟内找到入口文件。
  • 明确每类入口的请求载体、登录态、服务站字段、请求 ID、响应结构和幂等边界。
  • 能沿“入口 -> 参数解析 -> 鉴权 -> Service -> Model -> 表/MQ”解释完整数据流。
  • 能区分前端接口、内部接口、外部回调、消息消费者和人工补偿任务,避免错误调用。
  • 联调时不依赖真实密钥示例;所有签名、令牌和账号信息都由环境安全注入。
  • 修复公共 Service 时,能根据入口影响矩阵决定需要回归哪些调用方。

2. 适用场景

场景先看哪一节最小定位信息
PC 页面报错或返回登录失效PC 控制器协议URL、用户、sid、请求时间
OPS 调用 DGJ 内网接口失败inner 协议URL、Request-Id、请求体、调用方身份头
手机 App 提示接口类不存在App tradeCode 网关tradeCode、reqCode、App 版本
PDA/盘点接口失败直接 App/PDA ControllerURL、reqCode、设备与登录态
OMS/NC 老接口重复执行老 OpenAPItransCode、requestId、来源系统
全车件页面返回上游错误allcarpart 代理原 URL、登录服务站、代理目标响应
导出接口浏览器拿到 JSON/HTML报表与文件下载URL、权限、响应头、文件路径
支付/OA/订单消息未生效MQ 消费入口destination、routing key、业务单号
秒杀超时订单没有释放CLI/定时任务命令、limit、任务日志、订单状态

3. 八类入口总览

3.1 入口协议矩阵

类型典型入口路由键请求载体身份来源主要响应
PC 控制器/scm/invPo/getInvPoListURL controller/methodQuery、Form、部分 JSONCI Session、菜单权限splash、splashJson、resp、HTML
inner API/inner/activity/flashActivity/listFlashActivityURL controller/methodJSON 或 Form内部边界、Inspire-Api-User、部分 tokenR::successJson、R::bizErrorJson
App 网关/carsteward/index、index2tradeCodeForm 或 JSON 外壳,data 为 JSON 字符串App Session、uid、设备、签名BaseService::splash
直接 App/PDA/app/...、/pda/...URL controller/methodJSON 外壳,data 为对象App Session、签名、设备R::*Json
老 OpenAPI/openapi/indextransCodeForm,data 为数组来源系统字段、可选 requestId_success、_error
allcarpart/allcarpart/...显式 routes + 通配路由JSON/Form/文件PC Session、全车件开关上游 JSON 或文件流
报表/导出/reports/...、业务 controller exportURL methodQuery/FormPC Session、查询/导出权限JSON、Excel、PDF、HTML
MQ/CLItasks/*/consume、tasks/*/*routing key 或 CLI methodMQ payload 或 CLI 参数MQ 配置、部署进程、主机权限ACK/NACK、标准输出、日志

3.2 请求进入系统的总图

flowchart LR
    Browser["PC 浏览器"] --> PC["BaseController"]
    OPS["OPS / 内部服务"] --> Inner["BaseApiController"]
    Mobile["手机 App"] --> Gateway["Carsteward + OpenAppService"]
    PDA["PDA / 新 App"] --> Direct["BaseAppController"]
    Legacy["OMS / NC / 老商城"] --> Open["Openapi + OpenService"]
    AllCar["全车件前端"] --> Proxy["allcarpart Controller"]
    MQ["RabbitMQ"] --> Consumer["tasks/*Notify"]
    Cron["crontab / 人工命令"] --> Task["tasks/*"]
    PC --> Service["业务 Service"]
    Inner --> Service
    Gateway --> Service
    Direct --> Service
    Open --> Service
    Proxy --> Remote["全车件微服务"]
    Consumer --> Service
    Task --> Service
    Service --> Model["Model / Provider"]
    Model --> DB["MySQL / Redis / MongoDB"]
    Service --> OutMQ["MQ / 外部系统"]

3.3 不同入口最容易混淆的地方

混淆点正确认知
URL 里出现 inner 就一定校验 inner_token不能这样推断,必须结合 BaseApiController 当前分支和网关边界核对
success: true 就代表业务成功R::bizError/bizErrorJson 也写 success: true,必须同时判断 code
appapis.php 有映射就一定可调用还要检查对应 application/service/api/...php 是否存在、类名是否可加载
HTTP 200 就代表业务成功多数旧接口把业务错误放在 JSON 字段中,MQ 则看 ACK/NACK
Request-Id 自动保证所有入口幂等PC/inner 多用于日志串联;老 OpenAPI 才实现独立的请求锁与完成记录
tasks 方法能通过浏览器调用多数消费者/新任务有 is_cli() 保护,应该由 CLI 或进程管理器运行
allcarpart 是 DGJ 本地完整实现大部分是登录校验后转发到微服务,本地只保留导入、导出、打印等适配

4. 从 URL 或 code 定位代码的统一方法

4.1 URL 路由入口

CodeIgniter 常规 URL 可按以下方式初步映射:

/目录/控制器/方法
    -> application/controllers/目录/控制器.php
    -> class 控制器
    -> public function 方法()

例如:

/scm/invPo/getInvPoList
    -> application/controllers/scm/InvPo.php
    -> InvPo::getInvPoList()

但以下情况不能直接套用:

  • application/config/routes.php 做了显式改写。
  • allcarpart 使用显式路由和三段通配路由。
  • App 网关 URL 固定,真实目标由 tradeCode 决定。
  • 老 OpenAPI URL 固定,真实目标由 transCode 决定。
  • 版本路由 Hook 可能在控制器前改写 API 版本。

4.2 code 到文件的解析公式

App 网关:

tradeCode
  -> application/config/appapis.php
  -> app.purchase.purOrderList
  -> application/service/api/app/purchase/purOrderList.php
  -> PurOrderList::service($data)

老 OpenAPI:

transCode
  -> application/config/apis.php
  -> invoice.statusUpdate
  -> application/service/api/invoice/statusUpdate.php
  -> StatusUpdate::service($data)

4.3 定位决策图

flowchart TD
    A["拿到调用信息"] --> B{"是 URL 还是业务 code?"}
    B -->|URL| C{"URL 前缀"}
    C -->|scm / basedata / reports| D["controllers 对应目录"]
    C -->|inner| E["controllers/inner"]
    C -->|app / pda| F["controllers/app 或 pda"]
    C -->|allcarpart| G["先查 routes.php"]
    B -->|tradeCode| H["查 appapis.php"]
    B -->|transCode| I["查 apis.php"]
    B -->|routing key| J["查 MqEventEnums 和 registryCallback"]
    B -->|CLI method| K["controllers/tasks"]
    D --> L["找 Controller 方法"]
    E --> L
    F --> L
    G --> L
    H --> M["service/api/app 文件"]
    I --> N["service/api 文件"]
    J --> O["消费者回调方法"]
    K --> P["任务方法"]
    L --> Q["继续追 Service / Model / 表"]
    M --> Q
    N --> Q
    O --> Q
    P --> Q

5. PC 控制器协议

5.1 核心入口文件

文件职责
application/core/BaseController.php登录、账号、菜单、维护状态、请求数据和响应封装
application/controllers/scm/*.php采购、销售、库存、财务等 PC 业务入口
application/controllers/basedata/*.php商品、客户、供应商、仓库等基础资料入口
application/controllers/reports/*.php报表查询和导出入口
application/service/scm/*.php大量历史业务 Service
application/Services/*新领域 Service

5.2 构造阶段发生什么

普通 Controller 继承 BaseController,默认构造参数是 base。除 API 类型和特殊静默登录外,构造阶段会依次处理:

  1. 从 Session 读取 $this->jxcsys。
  2. 判断系统维护状态。
  3. 判断是否登录。
  4. 判断账号和服务站是否可用。
  5. 判断 PC 登录状态缓存是否允许继续访问。
  6. 判断用户是否能获得菜单。
  7. 记录用户活跃时间和 Request-Id。
  8. 解析 JSON 请求体到 $requestData。
sequenceDiagram
    participant B as PC 浏览器
    participant C as BaseController
    participant S as Session/Redis
    participant M as 菜单与账号
    participant A as 业务 Controller
    participant D as Service/DB
    B->>C: GET/POST/JSON + Cookie + Request-Id
    C->>S: login_session()
    S-->>C: sid/uid/name/area
    C->>M: 账号状态、登录状态、菜单校验
    M-->>C: 可访问/重定向
    C->>A: 注入 jxcsys 与 requestData
    A->>D: 业务查询或写入
    D-->>A: 业务结果
    A-->>B: splash / resp / HTML / 文件

5.3 请求字段如何合并

getPageData() 先合并 GET 与 POST,再补分页和登录上下文:

字段来源说明
page请求最小为 1
rows请求未传时默认 99999,列表接口应警惕大查询
JXCSIDSession当前服务站 ID
JXCUIDSession当前用户 ID
JXCUNAMESession当前用户名
areaCodeSession区域编码
eparchySession地市/区域上下文

getRequestData() 再把以上页面参数与 JSON 请求体合并。出现“请求明明传了 sid,代码却查了另一个站”的问题时,要确认最终使用的是 JXCSID、sid、storeId 还是总部账号切换后的默认门店。

5.4 PC 请求骨架

以下示例只表达协议,不包含真实 Cookie:

curl '/scm/invPo/getInvPoList?page=1&rows=20&status=3' \
  -H 'Accept: application/json' \
  -H 'Request-Id: <调用链请求ID>' \
  -H 'Cookie: <由已登录浏览器安全提供>'

JSON 写接口常见骨架:

curl -X POST '/scm/invSa/addNew' \
  -H 'Content-Type: application/json' \
  -H 'Request-Id: <调用链请求ID>' \
  -H 'Cookie: <由已登录浏览器安全提供>' \
  --data '{"contactId":123,"goodsList":[{"skuId":456,"qty":2}]}'

不能只用裸 curl 判断接口是否可用,因为缺少 Session 时可能返回登录页、重定向或 nologin JSON。

5.5 PC 响应并不统一

方式形状客户端判断
splashJson('success',...){"success":true,"status":"success","msg":"..."}status 和同名布尔字段
splashJson('error',...){"error":true,"status":"error","msg":"..."}status=error
resp(){"code":0,"msg":"...","data":{...}}code
页面渲染HTMLHTTP 状态、页面内容、重定向
导出文件流或临时下载地址Content-Type、文件名、返回体

5.6 PC 代表性入口字典

业务Controller 方法继续追踪
采购列表scm/InvPo::getInvPoListInvPoService、采购 Model、分表
采购保存scm/InvPo::saveInvPo参数校验、订单主明细写入
采购提交scm/InvPo::submitInvPo状态、OA/订单中心、支付方式
采购取消待支付scm/InvPo::cancelWaitPayOrder库存/额度释放、支付异常
采购入库scm/InvPo::invPoInStroage入库单、库存流水、实时库存
销售列表scm/InvSa::SalesList销售主表/明细
销售新增scm/InvSa::addNew、add销售 Service、价格和库存校验
销售出库scm/InvSa::addOutBound出库单、库存扣减、配送与同步
销售退货scm/InvSa::saveAftersale、returnupdate售后、退货入库、退款
付款单scm/Payment::addNew、updatePayment付款主明细、账户流水
无页面支付scm/Payment::noPagePay支付中心下单与回调
采购报表reports/PurchaseReport::*ReportValidate、Report Service、报表 Model

5.7 PC 失败分支

flowchart TD
    A["PC 请求失败"] --> B{"返回内容"}
    B -->|登录页/302| C["Session 失效、账号不可用或菜单为空"]
    B -->|status=nologin| C
    B -->|status=error| D["业务校验或 Service 异常"]
    B -->|HTTP 200 但页面空| E["权限、筛选条件、sid 上下文"]
    B -->|导出失败| F["导出权限、时间范围、数据量、文件流"]
    C --> G["核对 Cookie、sid、uid、登录状态缓存"]
    D --> H["按 Request-Id 和方法名查日志"]
    E --> I["核对最终 JXCSID/storeId"]
    F --> J["核对查询权限与导出权限是否分离"]

6. inner 内部 API 协议

6.1 核心入口

目录业务
controllers/inner/activityOPS 活动、秒杀活动管理
controllers/inner/moveMallE站、移动商城、机器人、秒杀购买
controllers/inner/channel大客户渠道订单和售后
controllers/inner/Inventory.php库存内部查询/同步
controllers/inner/Goods*.php商品、物料和搜索
controllers/inner/Payment.php支付和财务内部能力
controllers/inner/sysOPS 白名单、系统配置

这些 Controller 通常继承 BaseApiController,构造时调用 parent::__construct('api'),因此不走 PC Session 登录校验。

6.2 请求解析

条件解析方式
Content-Type 以 application/json 开头raw_input_stream JSON 解码
非 JSON合并 GET、POST 和 php://input 解析结果
Request-Id 请求头存在保存到 $requestID,用于日志串联
Shipper 请求头存在保存到 $scmShipper
Inspire-Api-User 存在URL 解码后 JSON 解码为 $apiUser

6.3 内部身份和安全边界

静态代码显示:

  • cacheManage、manage、province 被列入 token 校验例外模块。
  • 只有 InnerTokenAuth::isInnerServer() 为真时才进入 token 分支。
  • token 从请求体 inner_token 读取。
  • 当前条件还判断 URI 第一段是否不等于 inner;正常 /inner/... 路径第一段通常就是 inner。
  • Inspire-Api-User 被直接按数组键读取,调用方未传时存在告警或契约不稳定风险。

因此不能仅凭应用代码声称所有 inner 请求都经过 token 校验。正确做法是同时确认:

  1. 生产入口是否只允许内网或可信网关访问。
  2. 网关是否完成身份校验并写入调用方用户头。
  3. InnerTokenAuth::isInnerServer() 在各环境如何判断。
  4. URI 条件是否符合原设计。
  5. 敏感写接口是否有业务级权限和幂等校验。
安全文档只记录校验位置和风险,不记录任何真实 token、密钥或内部账号值。

6.4 通用请求骨架

curl -X POST '/inner/activity/flashActivity/listFlashActivity' \
  -H 'Content-Type: application/json' \
  -H 'Request-Id: <全链路请求ID>' \
  -H 'Inspire-Api-User: <由可信网关注入的URL编码JSON>' \
  --data '{
    "page": 1,
    "page_size": 20,
    "activity_name": "",
    "status": ""
  }'

调用方需要 token 时应由安全配置注入:

{
  "inner_token": "<由调用方运行环境安全注入>",
  "activity_id": 10001
}

6.5 OPS 秒杀活动入口

方法关键请求Service结果
listFlashActivity页码、名称、状态、时间FlashActivitySer::listFlashActivity活动分页
detailFlashActivityactivity_iddetailFlashActivity主表、商品、范围
saveFlashActivity活动字段、商品列表saveFlashActivity新增/编辑结果
submitFlashActivityactivity_id、提交参数submitFlashActivity直接生效或 OA 结果
saveFlashActivityStationScope活动、类型、站点saveStationScope黑白名单分页结果
importFlashActivityGoods文件、活动 IDimportGoods解析后的商品明细
exportFlashActivityGoodsactivity_idbuildGoodsExport下载地址/文件
endFlashActivityactivity_id、原因endFlashActivity提前结束结果
sequenceDiagram
    participant O as OPS
    participant I as FlashActivity Controller
    participant E as RequestEntry
    participant S as FlashActivitySer
    participant DB as 活动表
    participant OA as OA/MQ
    O->>I: JSON + Request-Id + 用户头
    I->>E: fromArray(requestData)
    E-->>I: 规范化 activityId/参数
    I->>S: save/submit/detail
    S->>DB: 主表、商品、站点范围
    opt 需要审批
        S->>OA: 发起 OA
    end
    S-->>I: 业务结果或异常
    I-->>O: R successJson / bizErrorJson

6.6 服务站秒杀入口

inner/moveMall/FlashSale.php 会把请求体中的 sid 转成 JXCSID,然后删除原 sid,复用站管家侧 Service 约定。

{
  "sid": 100001,
  "activity_goods_id": 20001,
  "qty": 2
}
flowchart LR
    A["请求 sid"] --> B["stationRequestData"]
    B --> C["JXCSID = sid"]
    C --> D["删除 sid"]
    D --> E["FlashSaleSer"]
    E --> F["活动可见性"]
    E --> G["库存与限购"]
    E --> H["购物车/订单"]

主要方法:goodsList、goodsDetail、packageGoodsList、goodsFilters、getCartCount、addCart、cartList、cartFilters、updateCart、orderPreview、submitOrder、orderDetail、cancelOrder。

6.7 渠道入口与幂等

inner/channel/Order.php 的 create、confirm_receipt、order_approve 使用请求体 JSON 的 MD5 组成 Redis 锁键,降低短时间重复提交风险。

方法业务幂等/校验下游
Order::create大客户渠道下单Redis 锁 + OrderCreateValidate场景化订单 Service
Order::confirm_receipt渠道确认收货Redis 锁 + Validate渠道订单 Service
Order::order_approve渠道审核订单Redis 锁 + ValidateFC 订单 Service
Aftersale::apply渠道售后申请Redis 锁 + Validate售后 Service
Aftersale::get_return_stock_in查询退货入库当前静态实现直接返回空成功尚未形成真实查询链路

Redis 锁只覆盖锁有效期内的相同请求,不等同于数据库唯一约束。渠道单号、来源订单号和落库唯一性仍需单独核对。

6.8 R 响应语义

{
  "success": true,
  "code": 0,
  "data": {},
  "msg": ""
}

业务错误示意:

{
  "success": true,
  "code": "<业务错误码>",
  "data": {},
  "msg": "业务校验失败原因"
}

R::bizError 与 R::bizErrorJson 的 success 仍为 true。前端和调用方必须以 code 为主要判断条件,不能只写:

if (response.success) { 当作成功 }

7. App tradeCode 网关协议

7.1 调用链

sequenceDiagram
    participant A as App
    participant C as Carsteward
    participant O as OpenAppService
    participant CFG as appapis.php
    participant S as service/api/app
    participant DB as DB/Redis
    A->>C: tradeCode + data + sign + reqCode
    C->>O: parse(params)
    O->>O: checkParams/sign
    O->>O: checkLogin/device/blacklist
    O->>CFG: tradeCode 查映射
    CFG-->>O: app.purchase.purOrderList
    O->>S: service(注入登录上下文后的 data)
    S->>DB: 查询或写入
    S-->>A: splash JSON

7.2 统一入口

URL请求解析
/carsteward/index读取 Form POST
/carsteward/index2合并 Form POST 与原始 JSON
/carsteward/build根据传入数据生成签名外壳;不应作为生产公共签名能力暴露

7.3 外层字段合同

字段必填说明
tradeCode是appapis.php 的映射键
data是JSON 字符串,不是直接对象
sign是客户端签名模块生成;文档不保存密钥
reqCode是常见 app_android、app_ios、qcj
targetCode是目标系统标识
uid登录接口外通常需要设备与登录用户关联
device登录接口外通常需要App 设备标识
verify不应由普通调用方使用当前代码值为 yes 时跳过签名比较,属于高风险旁路

7.4 请求骨架

{
  "tradeCode": "apppurOrderList",
  "reqCode": "app_android",
  "targetCode": "SMH",
  "uid": "<当前登录用户ID>",
  "device": "<当前设备ID>",
  "sign": "<由客户端签名模块生成>",
  "data": "{\"status\":\"pending\",\"page\":1,\"limit\":20,\"offset\":0,\"skey\":\"\"}"
}

注意两层 JSON:外层 data 是字符串。若直接传对象,签名结果、JSON 解码和 Service 参数可能不一致。

7.5 登录上下文注入

除以下接口外,网关会做登录检查:

  • applogin
  • appMobileLogin
  • appgetVersion
  • appMobileLoginSmsCode
  • appMobileLoginSelectStation

登录通过后,网关把 Session 用户数据合入业务 data:

注入字段含义
sid服务站 ID
user_id用户 ID
user_name用户名
areaCode / province区域兼容字段
eparchy地市/片区
user_ip调用 IP

AppSessionHook 在 pre_system 阶段识别 app_android、app_ios,把 Session 过期和更新时间调到 30 天。排查“PC 正常、App 经常掉线”时,应同时检查 Hook 是否启用、请求体是否能被 Hook 解析、reqCode 是否准确。

7.6 静态映射审计结果

对 appapis.php 跳过整行注释后进行静态扫描,得到:

指标结果含义
有效映射行190配置中的活动映射行数
唯一 code189存在重复 code
重复 codeapphomePage 2 行当前值相同,但会掩盖后续维护差异
映射目标文件不存在40 行配置存在不代表当前代码树可调用

映射目标缺失集中在部分首页、旧销售、旧采购、资金、系统联系人、个人消息等模块。遇到“接口类不存在”时,必须确认:

  1. 映射是否仍是线上有效协议。
  2. 文件是否被迁移到新 Controller 或新 Service。
  3. 大小写是否与 Linux 文件系统一致。
  4. 部署包是否漏文件。
  5. App 是否仍在调用已废弃 code。

7.7 主要 App code 分类

分类代表 code目标目录
公共/商品appgetInventory、appgetBarCodeapp/public
配送transportTaking、transportReceiptapp/transport
销售appsaleOrderList、appsale2StockOutapp/sale、app/sale2
采购apppurOrderList、apppurOrderReturnListapp/purchase
资金appfundReceiptList、appfundPaymentListapp/fund
系统系统设置、客户、提醒相关 codeapp/system
WMS扫码、入库、出库类 codeapp/wms
盘点inventoryCheck*app/invCheck
微仓moveOpen、inventoryCheckCreateapp/moveStore

7.8 App 网关高风险点

风险当前静态证据影响
签名旁路verify=yes 跳过比较必须由网关禁止普通调用方传入
设备校验失效checkDevice() 查询后立即 return后续设备不存在校验不可达
异常输出不稳定parse() 捕获后 print_r($e)可能破坏 JSON 合同并泄露内部信息
签名辅助入口Carsteward::build 可生成签名外壳需确认生产路由是否隔离
映射悬空40 行目标文件不存在老版本 App 可能运行时失败
重复映射apphomePage 重复后写覆盖前写,审计困难
缺少统一请求幂等网关层没有 requestId 完成记录写接口必须在业务层实现幂等

8. 直接 App 与 PDA Controller

8.1 为什么还有第二种 App 协议

新一些的接口不再通过 tradeCode 找类,而是直接使用 URL Controller,继承 BaseAppController。代表目录:

  • application/controllers/app
  • application/controllers/pda

代表入口包括:

Controller方法示例业务
app/MoveSupplygetMsAppList、moveSupplyIn微仓申请与入库
pda/Userlogin、home、bannerPDA 登录与首页
pda/PurchasegetInStroComfirm、inStoInPDA 采购入库
app/SaOrders销售单相关方法新 App 销售能力

8.2 请求数据流

flowchart TD
    A["JSON 外壳"] --> B["BaseAppController"]
    B --> C["检查 sign/reqCode/uid"]
    C --> D["检查 Session 与设备"]
    D --> E["data 解析为 businessData"]
    E --> F["注入 sid/user_id/user_name"]
    F --> G["具体 Controller 方法"]
    G --> H["R::successJson / bizErrorJson"]

8.3 风险边界

  • checkSign 对空 data 或 reqCode=debug 存在跳过路径,必须确认外部网关不允许生产调用方使用调试来源。
  • R::bizErrorJson 仍返回 success:true。
  • 直接 App 和 tradeCode App 可能使用相同 Session,但参数合同不同,不能互相套用请求体。
  • PDA 登录接口可能是例外入口,排查时先看具体 Controller 构造函数是否跳过父类校验。

9. 老 OpenAPI 协议

9.1 核心文件

文件职责
application/controllers/Openapi.php统一 HTTP 入口
application/service/OpenService.php校验、幂等、映射和调用
application/config/apis.phptransCode 到 Service 映射
application/service/api/*真实老接口实现
Mongo dgj_api_log可选 requestId 请求执行记录

9.2 请求骨架

老 OpenAPI 的 data 通常是 Form 数组,不是 App 网关那种 JSON 字符串:

curl -X POST '/openapi/index' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'transCode=shmStatusUpdate' \
  --data-urlencode 'reqCode=<来源系统>' \
  --data-urlencode 'targetCode=<目标系统>' \
  --data-urlencode 'requestId=<来源系统唯一请求ID>' \
  --data-urlencode 'data[orderNo]=<业务单号>' \
  --data-urlencode 'data[status]=<目标状态>'

9.3 参数和幂等流程

sequenceDiagram
    participant X as 外部系统
    participant O as OpenService
    participant R as Redis Lock
    participant M as Mongo dgj_api_log
    participant S as API Service
    X->>O: transCode + data + requestId
    O->>O: 校验必填和映射
    opt 有 requestId
        O->>R: 设置 10 分钟请求锁
        O->>M: 查询历史记录
        alt 已完成 status=1
            O-->>X: 直接 success,不重复执行
        else 未完成或首次
            O->>M: 写 status=0
        end
    end
    O->>S: service(data)
    S-->>O: success callback(requestId)
    O->>M: 更新 status=1
    O-->>X: legacy success response

9.4 requestId 的真实语义

  • 有 requestId 时先设置 Redis 锁,降低并发重复。
  • 请求内容写入 Mongo dgj_api_log,初始 status=0。
  • 如果找到相同 requestId 且 status=1,直接返回成功,不再执行 Service。
  • Service 成功时通过 callback 把记录更新成完成。
  • 若首次执行已经产生部分副作用但没有更新完成标记,重试仍可能再次进入业务层。

因此 requestId 是重要保护,但写接口仍需数据库唯一键、状态前置检查或业务幂等共同兜底。

9.5 代表性 transCode

code映射业务
shmStatusUpdateinvoice.statusUpdate订单审核状态同步
shmstockOutinvoice.StockOut订单出库
shmCloseOrderinvoice.closeOrder订单关闭
shmUpdateOrderinvoice.updateOrder订单修改
shmGatheringBillApproveinvoice.receiptCallback预订单收款成功回调
shmInfoEditgoods.InfoEdit商品新增/修改/删除
shmDisabledgoods.Disabled商品上下架同步
shmAdvanceOrderadvanceOrder.listInfo预订单列表

9.6 OpenAPI 失败分支

flowchart TD
    A["OpenAPI 失败"] --> B{"在哪一步失败"}
    B -->|必填/映射| C["E1000x 参数错误"]
    B -->|文件不存在| D["E50001 接口类不存在"]
    B -->|requestId 冲突| E["检查 Redis 锁和 Mongo 状态"]
    B -->|Service 异常| F["legacy _error"]
    B -->|返回成功但业务没变化| G["可能命中已完成 requestId"]
    E --> H["区分 status=0 部分执行与 status=1 已完成"]
    F --> I["按 transCode、requestId、业务单号查日志"]
    G --> J["核对来源是否错误复用了 requestId"]

10. allcarpart 路由与代理协议

10.1 路由特点

application/config/routes.php 为全车件配置了两类路由:

  1. 导入、导出、打印等显式路由。
  2. allcarpart/(:any)/(:any)/(:any) 三段通配路由。

代表性映射:

外部 URL本地方法
/allcarpart/purchase/po-return-order/batch-return-importPoReturnOrder::batchReturnImport
/allcarpart/sale/sa-order/importSaOrder::import
/allcarpart/sale/sa-invoice-order/exportSaInvoiceOrder::export
/allcarpart/storage/inventory/exportInventory::export
/allcarpart/fund/payment-order/exportPaymentOrder::export
/allcarpart/purchase/rfq/inquiryRfq::inquiry

10.2 代理数据流

sequenceDiagram
    participant U as 登录用户
    participant D as DGJ allcarpart Controller
    participant S as Session/Station
    participant M as 全车件微服务
    U->>D: /allcarpart/... + JSON/文件
    D->>S: 校验 PC 登录和 enableAllCarPart
    S-->>D: sid/uid/user_name
    D->>M: 转发原 URI 和请求体,注入用户头
    M-->>D: JSON/文件/错误
    D-->>U: 透传或本地适配

排查全车件问题时应把责任边界分成:

  • DGJ 登录和服务站功能开关。
  • DGJ 本地导入/导出/打印适配。
  • 代理 URL、请求头和请求体。
  • 全车件微服务实际业务逻辑。
  • 微服务返回后 DGJ 的透传或文件处理。

11. 报表、导出和文件入口

11.1 查询和导出权限可能分离

以 reports/PurchaseReport.php 为例,查询和导出分别检查权限。用户“能看到列表但不能导出”不一定是 bug,应核对:

  • 查询权限,例如采购报表查询资源。
  • 独立导出权限,例如订单查询导出资源。
  • 导出日期范围限制。
  • 导出数据量和超时。

11.2 报表调用链

flowchart LR
    A["报表 Controller"] --> B["权限检查"]
    B --> C["Validate"]
    C --> D["Report Service"]
    D --> E["报表 Model / 分表 SQL"]
    E --> F["口径计算"]
    F --> G{"查询还是导出"}
    G -->|查询| H["splashJson 分页"]
    G -->|导出| I["Excel/PDF/下载地址"]

11.3 文件接口判断顺序

  1. 看 HTTP 状态和 Content-Type。
  2. 看返回体是 JSON 下载地址、二进制文件还是 HTML 错误页。
  3. 核对前端是否把下载接口当普通 JSON 请求。
  4. 核对临时文件是否写入成功、路径和文件名是否一致。
  5. 核对反向代理的响应体大小、超时和缓冲配置。
  6. 核对导出数据是否跨越过多分表或日期。

12. MQ 消费者与 CLI 任务入口

12.1 这不是 HTTP API

tasks/*Notify.php 的 consume() 通常创建 topic consumer,按 routing key 注册回调并长期运行。业务函数接收的是 MQ 解码后的数组,返回 ACK 或 NACK。

sequenceDiagram
    participant P as 外部生产者
    participant Q as RabbitMQ
    participant C as tasks Consumer
    participant H as 回调方法
    participant DB as 业务表
    P->>Q: destination + routing key + payload
    Q->>C: 投递消息
    C->>H: registryCallback 对应方法
    H->>DB: 校验状态并写业务数据
    alt 成功或可忽略重复
        H-->>Q: ACK
    else 可重试失败
        H-->>Q: NACK
    end

12.2 代表性消费者

消费者destination主要 routing key/业务
PayCenterNotifyDEST_PAYCENTER_NOTIFY支付结果、支付异常、退款、白条、分期
OrderCenterNotifyDEST_ODC_NOTIFY订单审核、更新、关闭、取消、自制订单
OaNotifyDEST_OA_NOTIFYOA 审批通知
OaResultNotifyOA 结果 destinationOA 状态同步
ItemCenterNotify商品中心 destination限购、套包、价格、敏感词
DispatchCenterNotify配送中心 destination出库、物流、自提、退货关闭
SaasOrderNotifyDEST_DGJSAAS 订单、库存事件、采购关闭确认
ChannelOrderNotifyDEST_DGJ_CHANNEL渠道下单、发货、退款、审核

12.3 正确启动方式

php index.php tasks/PayCenterNotify/consume
php index.php tasks/OaNotify/consume

消费者应该由进程管理器守护,不应把 consume 暴露成浏览器接口。排查“完全没有消费”时先看进程、队列绑定和 destination,而不是先查业务表。

12.4 秒杀补偿任务

php index.php tasks/FlashSaleTask/expireWaitPayOrders 100
php index.php tasks/FlashSaleTask/refreshGoodsStatus 500
php index.php tasks/FlashSaleTask/refreshInvalidCarts 500
php index.php tasks/FlashSaleTask/compensatePaidOrders 100
php index.php tasks/FlashSaleTask/compensateClosedOrders 100
php index.php tasks/FlashSaleTask/runCompensate 500
方法作用主要风险
expireWaitPayOrders释放超过支付截止时间的订单与迟到支付回调并发
refreshGoodsStatus刷新活动商品有效状态批量范围过大
refreshInvalidCarts失效不可购买购物车前端缓存与数据库状态不同步
compensatePaidOrders补支付成功但活动单未同步重复推进采购单
compensateClosedOrders补关闭后未释放库存重复释放锁量
runCompensate顺序执行五类补偿单项失败只输出 JSON,进程退出码未必能表达失败

FlashSaleTask 捕获异常后输出失败 JSON,但没有显式非零退出。因此调度平台不能只看进程退出码,还应解析输出或任务日志。

13. 统一数据流转链路

13.1 查询类请求

flowchart LR
    A["请求参数"] --> B["入口解析"]
    B --> C["身份/服务站上下文"]
    C --> D["Validate / Entry"]
    D --> E["Service 查询条件"]
    E --> F["Model / 分表"]
    F --> G["MySQL/Redis/ES"]
    G --> H["领域格式化"]
    H --> I["入口响应封装"]

查询结果不正确时按反方向排:响应格式化 -> Service 条件 -> 分表/表 -> 上下文字段 -> 原始请求。

13.2 写入类请求

flowchart TD
    A["写请求"] --> B["鉴权和参数校验"]
    B --> C["重复请求/状态前置检查"]
    C --> D["事务开始"]
    D --> E["主表"]
    E --> F["明细/扩展/关系表"]
    F --> G["库存/资金/活动副作用"]
    G --> H{"事务结果"}
    H -->|成功| I["提交事务"]
    H -->|失败| J["回滚数据库"]
    I --> K["MQ/外部系统/缓存"]
    K --> L["响应成功"]
    J --> M["响应失败或 NACK"]

外部调用如果发生在事务提交后,数据库成功而 MQ 失败需要补偿;外部调用如果发生在事务中,超时会拉长锁和事务。具体入口必须继续追 Service,不能从 Controller 层假设原子性。

13.3 回调类请求

flowchart TD
    A["支付/OA/订单回调"] --> B["按来源单号找业务单"]
    B --> C{"业务单存在?"}
    C -->|否| D["NACK/记录异常"]
    C -->|是| E{"当前状态允许推进?"}
    E -->|否且已完成| F["按幂等策略 ACK 或忽略"]
    E -->|否且冲突| G["NACK/人工确认"]
    E -->|是| H["写回调事实和业务状态"]
    H --> I["写明细/资金/库存副作用"]
    I --> J["提交后 ACK"]

14. 响应合同总表

入口成功判断业务失败判断传输失败
PC splashJsonstatus=successstatus=error/nologinHTTP/网络
PC respcode=0非零 codeHTTP/网络
R::successJsoncode=SUCCESSbizError 的业务 codeHTTP/网络
App splashstatus=successstatus=errorHTTP/非 JSON
OpenAPIlegacy status/message/result_error code/messageHTTP/非 JSON
allcarpart依上游合同依上游合同代理超时/上游不可达
MQACKNACK消费进程/连接失败
CLI输出内容与任务日志输出 success=0 等进程未启动;退出码不一定可靠

14.1 调用方统一判断建议

第一层:HTTP/MQ/进程是否成功传输
第二层:响应是否符合该入口 JSON 合同
第三层:业务 code/status 是否成功
第四层:关键业务表和副作用是否真的完成

任何一层都不能代替下一层。尤其是回调和补偿任务,最终必须核对业务状态、明细和副作用表。

15. 鉴权与上下文矩阵

入口Session签名/token菜单/资源服务站来源幂等
PC必需通常无独立签名构造层菜单 + 方法内资源Session JXCSID业务层
inner不走 PC Session内部 token 分支需按环境核验依网关/业务校验请求 sid 或显式字段部分 Redis 锁/业务层
App 网关登录接口外必需App 签名黑名单/强制下线Session 注入 sid业务层
直接 App/PDA多数必需BaseApp 签名Controller 特定逻辑Session 注入业务层
OpenAPI不依赖 PC Session来源系统合同transCode 白名单data 明确传入requestId 锁 + Mongo
allcarpartPC Session代理边界enableAllCarPartSession 注入上游/业务层
MQ不需要 SessionMQ 连接配置routing key 注册payload 中 sid/业务单回调方法
CLI主机执行权限无 HTTP 鉴权is_cli()参数/数据本身任务实现

16. 按现象排查

16.1 “接口类不存在”

  1. 确认是 tradeCode 还是 transCode。
  2. 在对应配置中找映射,注意大小写和重复键。
  3. 把点替换成斜杠,拼出 application/service/api/...php。
  4. 核对文件是否存在、类名是否 ucfirst 后可实例化。
  5. 核对当前部署版本,而不是只看本地分支。
  6. 确认 App 是否仍调用已经迁移或废弃的 code。

16.2 “HTTP 200 但前端提示失败”

  1. 识别响应体系。
  2. 检查 status、code、msg,不要只看 HTTP 和 success。
  3. R::bizErrorJson 需要按非成功 code 处理。
  4. 检查前端是否把文件流当 JSON。
  5. 检查异常是否被 print_r 破坏了 JSON。

16.3 “请求成功但数据查不到”

  1. 记录完整业务键:sid、单号、主键、来源单号。
  2. 确认上下文最终使用 JXCSID 还是请求 sid。
  3. 确认分表定位。
  4. 查主表、明细、关系表是否都写入。
  5. 查事务是否提交。
  6. 查缓存/ES/报表是否异步刷新。

16.4 “同一个请求执行了两次”

flowchart TD
    A["重复执行"] --> B{"入口类型"}
    B -->|OpenAPI| C["核对 requestId 是否唯一且稳定"]
    B -->|渠道 inner| D["核对 Redis 锁时长和请求体是否完全相同"]
    B -->|App/PC| E["核对前端连点、超时重试、业务唯一键"]
    B -->|MQ| F["核对 NACK、消费重启、ACK 时机"]
    B -->|补偿任务| G["核对状态前置和处理标记"]
    C --> H["Mongo dgj_api_log 状态"]
    D --> I["数据库唯一性兜底"]
    E --> I
    F --> I
    G --> I

16.5 “回调完全没有进入业务代码”

  1. 确认入口是 HTTP 回调还是 MQ routing key。
  2. MQ 场景检查消费者进程是否运行。
  3. 检查 destination、exchange、queue、routing key 是否匹配。
  4. 查消费者启动日志和注册回调。
  5. 查消息是否进入死信、重试或其他环境。
  6. HTTP 场景检查网关路由和来源鉴权。
  7. 最后才查业务单状态。

17. 常用定位命令

17.1 URL 和 Controller

rg -n "public function getInvPoList|public function addOutBound" application/controllers
rg -n "allcarpart/.+po-return-order|allcarpart/.+sa-order" application/config/routes.php
rg -n "class .* extends BaseApiController" application/controllers/inner
rg -n "class .* extends BaseAppController" application/controllers/app application/controllers/pda

17.2 App 和 OpenAPI 映射

rg -n '"apppurOrderList"|"appsale2StockOut"|"transportTaking"' application/config/appapis.php
rg -n '"shmStatusUpdate"|"shmstockOut"|"shmGatheringBillApprove"' application/config/apis.php
find application/service/api -type f -name '*.php' | sort

17.3 MQ 和任务

rg -n "createTopicConsumer|registryCallback|startConsume" application/controllers/tasks
rg -n "DEST_PAYCENTER_NOTIFY|TYPE_PAYCENTER_PAY_RESULT" application/KzData/Enums application/controllers/tasks
rg -n "return MqResultEnums::ACK|return MqResultEnums::NACK" application/controllers/tasks
rg -n "is_cli\(\)" application/controllers/tasks

17.4 从业务方法追到表

rg -n "function submitOrder|function paycenterPayResult" application/controllers application/Services
rg -n "SCM_PO_ORDER|SCM_SA_ORDER|SCM_INVENTORY|SCM_PAYMENT" application/Services application/service application/models
rg -n "send.*Mq|MqSer::|sendOA" application/Services application/service

17.5 日志检索键

优先组合检索,而不是只搜错误文本:

Request-Id + Controller 方法
业务单号 + routing key
sid + tradeCode
requestId + transCode
来源订单号 + 回调方法

18. 接口变更影响面

18.1 修改 Controller 时

  • 请求字段是否由前端直接传入还是由父类注入。
  • GET、Form、JSON 三种请求是否都需要兼容。
  • 是否改变 splash、resp、R 的响应形状。
  • 导出接口是否仍返回正确文件类型。
  • 方法是否被 routes.php 改写或由旧 App code 间接调用。

18.2 修改公共 Service 时

flowchart TD
    A["公共 Service 改动"] --> B["PC 调用方"]
    A --> C["inner 调用方"]
    A --> D["App tradeCode"]
    A --> E["直接 App/PDA"]
    A --> F["OpenAPI"]
    A --> G["MQ 回调"]
    A --> H["补偿任务"]
    B --> I["统一回归矩阵"]
    C --> I
    D --> I
    E --> I
    F --> I
    G --> I
    H --> I

重点核对:

  • 参数名称和默认值是否兼容旧入口。
  • sid/JXCSID/storeId 是否统一。
  • 返回值是否被不同 Controller 二次包装。
  • 异常类型是否会被旧入口捕获。
  • 事务外 MQ 和缓存是否会重复发送。
  • 回调和补偿是否能够重复执行。

19. 回归清单

19.1 通用回归

  • [ ] 正常请求返回符合对应入口合同。
  • [ ] 缺少必填字段返回明确业务错误。
  • [ ] Session/token/签名失效时不能进入业务写入。
  • [ ] 服务站上下文不能由普通调用方越权覆盖。
  • [ ] 同一请求快速重复提交不会重复创建主单。
  • [ ] 请求超时后重试不会产生重复库存、资金或 MQ 副作用。
  • [ ] Request-Id 能在入口和业务日志中串联。
  • [ ] 业务错误不能仅依靠 HTTP 500 表达。
  • [ ] 敏感信息不出现在响应、日志和文档中。

19.2 PC

  • [ ] 登录、账号停用、服务站停用、菜单为空分别验证。
  • [ ] GET、Form 和 JSON 参数合并符合预期。
  • [ ] 总部账号切换门店后 JXCSID 正确。
  • [ ] 查询权限和导出权限分别验证。
  • [ ] 登录失效时 AJAX 和页面请求表现符合前端预期。

19.3 inner

  • [ ] JSON 与 Form 请求都能按约定解析。
  • [ ] Inspire-Api-User 缺失/格式错误有明确处理。
  • [ ] 网关、网络和 token 安全边界经过环境验证。
  • [ ] R::bizErrorJson 前端按 code 识别失败。
  • [ ] 渠道重复请求和数据库唯一性共同验证。

19.4 App

  • [ ] tradeCode 映射文件真实存在。
  • [ ] 外层 data 字符串和签名数据完全一致。
  • [ ] Android、iOS、全车件来源分别回归。
  • [ ] Session Hook 的 30 天策略生效。
  • [ ] 设备校验、签名旁路和调试来源在生产边界不可滥用。
  • [ ] 老版本 App 调用的 code 仍兼容或有明确升级策略。

19.5 OpenAPI/MQ/任务

  • [ ] 相同 requestId 重复调用不会重复执行已完成请求。
  • [ ] status=0 的部分执行请求有人工判定和恢复路径。
  • [ ] MQ 重复投递、乱序、NACK 重试都验证。
  • [ ] 消费进程重启后业务幂等成立。
  • [ ] CLI 任务失败时调度平台能从输出或日志识别。
  • [ ] 补偿任务执行前后都有数量和状态核对。

20. 已确认风险与待环境验证项

20.1 静态代码已确认

结论证据
系统存在八类入口协议controllers、config、tasks 和基础 Controller
App 活动映射 190 行、唯一 code 189appapis.php 静态扫描
apphomePage 重复映射appapis.php 相邻两行
40 行 App 映射目标文件不存在映射到 service/api 的文件存在性审计
App verify=yes 可跳过签名比较OpenAppService::checkParams
App 设备检查后续代码不可达OpenAppService::checkDevice 的提前返回
R::bizError* 返回 success:trueapplication/Components/R.php
OpenAPI 使用 Redis 请求锁和 Mongo 完成记录OpenService
秒杀任务失败仅输出 JSONFlashSaleTask::runTask
渠道退货入库查询当前返回空成功inner/channel/Aftersale::get_return_stock_in

20.2 必须在目标环境确认

  • inner 路由的真实网络可达范围和网关鉴权规则。
  • InnerTokenAuth::isInnerServer() 在开发、预发、生产的判断结果。
  • 40 个缺失 App Service 是否仍有线上调用流量。
  • Carsteward::build、verify=yes、reqCode=debug 是否被网关阻断。
  • MQ destination、queue、routing key 的实际绑定和死信策略。
  • 消费者由何种进程管理器守护、失败如何告警。
  • OpenAPI Redis 锁 TTL、Mongo 索引和历史数据保留策略。
  • 文件导出在反向代理上的超时、大小和缓冲限制。

21. 证据来源

主题代码证据
PC 登录、参数和响应application/core/BaseController.php
inner 参数、请求头和 token 分支application/core/BaseController.php 中 BaseApiController
R 响应语义application/Components/R.php
App 网关application/controllers/Carsteward.php、application/service/OpenAppService.php
App code 映射application/config/appapis.php
直接 App/PDAapplication/core/BaseAppController.php、application/controllers/app、pda
App Session Hookapplication/hooks/AppSessionHook.php、application/config/hooks.php
老 OpenAPIapplication/controllers/Openapi.php、application/service/OpenService.php
老接口映射application/config/apis.php
allcarpart 路由和代理application/config/routes.php、application/controllers/allcarpart
OPS 秒杀接口application/controllers/inner/activity/FlashActivity.php
服务站秒杀接口application/controllers/inner/moveMall/FlashSale.php
渠道入口application/controllers/inner/channel/Order.php、Aftersale.php
支付 MQapplication/controllers/tasks/PayCenterNotify.php
秒杀补偿任务application/controllers/tasks/FlashSaleTask.php
MQ 枚举application/KzData/Enums/MqEventEnums.php

22. 一页式定位结论

看到普通 URL:先找 controllers,再看父类和 routes.php。
看到 tradeCode:查 appapis.php,再拼 service/api/app 文件。
看到 transCode:查 apis.php,再拼 service/api 文件。
看到 routing key:查 MqEventEnums 和 tasks 中 registryCallback。
看到定时任务:必须用 CLI,先确认 is_cli 和进程管理。
看到 success=true:仍要判断 code/status。
看到 HTTP 200:仍要核对主表、明细、库存/资金和 MQ 副作用。
改公共 Service:必须回归 PC、inner、App、OpenAPI、MQ 和补偿任务的实际调用方。

请求-日志-数据变更追踪卡

多入口请求链路

场景调用方与入口请求载荷/上下文Controller/ConsumerService/Provider汇合点最终业务事实
PC 路由/scm/*、/basedata/*、/reports/*session、query/form/JSON、sid对应 Controller + BaseControllerapplication/service/scm/* 或 Services/*领域 Service页面动作转换为业务表事实
Inner API/inner/*内部鉴权头、sid、用户头、JSONcontrollers/inner/* + BaseApiController领域 Service/Provider与 PC 共用 Service/Model内部系统调用形成同类业务事实
App API codeappapis.php 映射API code、App 签名/用户上下文、参数controllers/app/pda/服务映射application/service/api/*领域 ServiceApp/PDA 请求落到采购、销售、库存等领域
老 OpenAPIOpenapi.php + apis.phpappId、签名、外部单号、参数Openapi/OpenService老适配 Service来源单映射外部合同转换为内部表和状态
CLI/MQCLI 调度或 Brokertask 参数、destination、routing key、消息体controllers/tasks/*Consumer/补偿 Service业务键异步状态、数量或同步结果

日志证据矩阵

| 链路段 | 日志来源 | 可检索锚点 | 成功信号 | 失败信号 | 与下一段关联方式 | | --- | --- | --- | --- | --- | --- | --- | | 路由层 | Web 访问日志、routes.php/API code 配置 | URI、method、API code、request_id | 命中目标 Controller/method | 404、method 不符、code 未映射 | 配置映射到类方法 | | 鉴权层 | Base Controller/API/OpenAPI 日志 | session/appId/header、sid、request ID | 用户和站点上下文建立 | 401/403、签名/时间戳失败 | 上下文传入目标 Service | | 参数层 | Validate/Entry 异常 | 参数名、错误码、业务单号 | 标准参数对象生成 | JSON/form 形态不符、必填缺失 | 标准参数与 Service 入参对照 | | 业务层 | Controller/Service 日志 | 类方法、业务单号、来源单号 | commit 并返回业务结果 | 业务异常、rollback | 单号回查主明细和流水 | | 响应/异步层 | Provider/MQ/响应日志 | HTTP code、业务 code、message ID | 业务成功且 ACK/下游回执 | HTTP 200 但业务失败、NACK/超时 | request ID/业务键贯穿两端 |

环节数据变更台账

步骤代码位置事务读取事实写入表/缓存/MQ字段或数量变化回查证据
解析入口routes.php、apis.php、appapis.php事务外path/API code/method无外部入口 -> Controller/method配置行、访问日志
建立上下文BaseController/BaseApiController/OpenAPI事务外session/header/signature请求上下文补入用户、sid、来源;失败零业务写入鉴权日志、上下文快照
参数归一Validate/Entry/Controller事务外query/form/JSON无多种载荷 -> Service DTO/数组校验结果、Controller 入参
领域写入目标 Service本地事务当前状态和业务数据主表、明细、流水insert/update;状态/数量/金额 old -> new单号、事务结果、表记录
返回/通知Controller、MqSer、Providercommit 后已提交结果HTTP 响应、MQ/下游返回成功不等于异步完成HTTP/业务码、消息 ACK、下游状态

子模块追踪:pc-entry PC Controller 入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
请求处理浏览器 /scm/*、/basedata/*、/reports/*session、sid、query/form/JSON、业务单号application/core/BaseController.php -> application/controllers/scm/InvPo.php登录用户、菜单权限、站点上下文、当前业务态参数校验外零写入;领域 Service 事务内 insert/update old -> newaccess request ID + URI + sid + billNo401/403/校验失败零业务写入;超时按业务单回查是否已提交
响应回查Controller JSON/下载响应HTTP code、业务 code、返回单号application/core/BaseController.phpcommit 结果和异步任务 IDDB 已提交后返回;MQ/文件生成不属于同一事务request ID + response code + business IDHTTP 200 不等于业务成功;用返回单号查主表和异步状态

子模块追踪:inner-entry Inner 内部 API 入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
内部请求/inner/* 服务间调用内部鉴权头、sid、用户头、JSONapplication/controllers/inner/activity/FlashActivity.php身份上下文、字段规则、目标业务当前态鉴权/校验阶段不写;Service 本地事务写主明细与状态 old -> newrequest ID + URI + sid + activity/order ID鉴权失败零写入;调用超时按稳定业务键回查,不盲重试
统一响应R 组件封装返回success/code/data、业务 IDapplication/Components/R.phpService 返回和异常类型响应阶段 DB 不变;异步通知另有边界request ID + R code + business ID调用方必须判断业务 code;失败后仅补未完成环节

子模块追踪:app-entry App tradeCode 映射入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
code 路由App 网关提交 tradeCodetradeCode、签名/会话、sid、参数application/config/appapis.php -> application/core/BaseAppController.phpcode 映射、登录上下文、目标服务类路由和鉴权不写;命中 application/service/api/app/purchase/purOrderList.php 等目标request ID + tradeCode + user/sidcode 未映射或类不存在零写入;先修配置/文件一致性
业务执行App service API 方法来源单号、分页或业务动作参数application/service/api/app/purchase/purOrderList.php当前业务事实和权限范围查询类不写;动作类在领域事务内 old -> newrequest ID + tradeCode + bill/source ID响应成功后仍查业务主表;重复动作依赖来源键幂等

子模块追踪:pda-entry App、PDA 直接 Controller 入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
直接路由App/PDA URL 直接访问 Controllertoken/session、sid、扫码/单据参数application/controllers/Carsteward.php -> application/core/BaseAppController.php登录上下文、设备输入、业务状态校验阶段不写;领域事务写盘点/出入库等事实request ID + URI + sid + 单号/条码与 tradeCode 协议不同;404/参数形态错时不应切换接口猜测
结果核对PDA 扫码提交返回业务单、SKU、仓位、返回 codeapplication/core/BaseAppController.php受影响行和库存/单据结果commit 后返回;缓存/MQ 为异步边界request ID + billNo + SKU/location网络重试前按单号和 SKU 查流水,避免重复出入库

子模块追踪:openapi-entry 老 OpenAPI 入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
外部请求合作方提交 transCodeappId、签名、timestamp、requestId、来源单application/controllers/Openapi.php -> application/config/apis.php签名、时间窗、transCode 映射、幂等记录鉴权失败零写入;通过后调用 application/service/OpenService.phprequest ID + transCode + external orderNo同一 requestId 的语义按现有实现核实;超时先查来源单映射
合同适配OpenService 调具体 API外部字段、内部标准参数application/service/OpenAppService.php -> application/service/api/invoice/statusUpdate.php原外部单、内部关系、当前状态领域事务 insert/update old -> new;响应适配不再写requestId + 外部/内部单号 + result codeHTTP 200 仍判断业务码;重复回调保持单向状态和零重复副作用

子模块追踪:allcarpart-entry 全车件路由与代理入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
路由代理allcarpart 显式 route 请求URI、method、token、外部询价/订单号application/config/routes.php -> application/controllers/Carsteward.php路由目标、身份和外部请求上下文代理前不写;本地落单时由领域事务创建来源关系request ID + route + external orderNo路由错/上游超时先查代理日志和外部单,不重复创建本地订单
下游回查代理响应或异步状态查询外部/本地单号、状态application/controllers/Carsteward.php本地映射与外部最终态查询阶段 DB 不变;确认结果后按服务规则 old -> newrequest ID + 两端单号 + external code外部合同和生产日志需环境验证;不凭静态代码宣称已送达

子模块追踪:report-file-entry 报表、导出与文件入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
查询导出报表页面查询或导出按钮sid、时间窗、筛选、导出权限application/core/BaseController.php -> application/controllers/scm/InvPo.php权限、分表口径、状态/软删过滤查询只读 不写;异步导出仅写任务/文件元数据request ID + report/export type + filters查询和导出权限可分离;失败保留筛选与任务 ID 后重试
文件读取模板下载、结果文件访问file/task ID、文件名application/config/routes.php文件归属、状态、路径白名单文件读取 DB 不变;生成完成 pending -> success/failedrequest ID + task/file ID文件不存在先查生成任务;路径和对象存储事实需目标环境确认

子模块追踪:mq-cli-entry MQ Consumer 与 CLI Task 入口

环节入口/触发请求/业务键代码链路读取事实写入与字段变化日志证据异常与补偿
消费/任务Broker 投递或调度平台 CLIdestination、routing key、message/task 参数application/controllers/tasks/PayCenterNotify.php、application/controllers/tasks/FlashSaleTask.phpCLI 环境、事件注册、消息版本、当前业务态单消息/单记录事务更新 old -> new;ACK 不属于 DB 事务message/task ID + routing key + business key非 CLI/未知事件零写入;异常按 ACK/NACK 和任务重试策略处理
幂等回查Consumer 重投或补偿重跑原 message ID、稳定业务键、批次application/KzData/Enums/MqEventEnums.php当前状态、已有流水和副作用已完成则 DB new -> new 且新增流水 0;仅补缺失异步环节business key + retry/batch + row count不以随机 messageId 当幂等键;不确定先查事实再小批重放