12 KiB
12 KiB
External 系统 → 启航ERP(拼多多)商品上架网关:裁剪与改造方案
目标:在
qihang-ecom-erp-open基础上,仅保留“商品上架/商品同步(仅商品域)/接口鉴权”能力,作为单体服务提供给外部系统调用。
首期平台:拼多多。
调用方:外部系统(传入商品数据 +shopId+platform)。
店铺授权:由本服务维护(外部系统不传 appKey/appSecret/accessToken)。
鉴权:AK/SK 签名鉴权(system-to-system)。
1. 范围与非目标
1.1 In Scope(首期必须)
- 商品数据接入:外部系统推送商品(SPU + SKU)到本服务(创建/更新)。
- 拼多多上架全链路:
- A 创建商品(首次发布)
- B 更新商品信息(标题/主图/详情/属性等)
- C 更新 SKU(规格、价格等)
- D 更新库存
- E 上架/下架
- F 接收“已准备好的商品数据”(图片/详情为可访问 URL 或可上传的素材)并发起平台发布
- 最小商品同步:
- 从拼多多拉取商品(用于对账/状态回写/增量同步),保留
pull_goods能力即可 - 同步结果落库,供外部系统查询/校验
- 从拼多多拉取商品(用于对账/状态回写/增量同步),保留
- 接口鉴权:
- 调用方 → 本服务 API 必须签名验证(AK/SK)
- 失败拒绝(401/403),并记录审计日志
1.2 Out of Scope(首期明确不做/可后置)
- 订单/售后/发货/电子面单/仓库/采购等业务域
- 多平台(淘宝/京东/抖店/快手/小红书/微信小店等)
- 前端管理后台(Vue)与多租户/多商户能力
- AI-agent 相关能力
2. 现状评估(基于当前开源代码)
2.1 已具备的基础能力
- 商品库接入入口:
erp-api下存在POST /goods/add,并且模型存在outerErpGoodsId等外部标识字段,适合承接调用方商品数据。 - 拼多多商品拉取(同步):
oms-api下存在POST /pdd/goods/pull_goods,当前实现是“拉取列表并落库”。 - 安全模块线索:
core/security已存在并在erp-api/oms-api引用(但对调用方的 S2S 鉴权需要单独设计)。
2.2 关键缺口(必须改造/补齐)
- 当前拼多多侧
open-sdk-2.1.12.jar中公开的PddGoodsApiHelper仅暴露pullGoodsList(拉取),未暴露“创建/更新/上下架/库存更新”等发布能力。 - 因此,商品上架全链路需要新增拼多多发布适配层(可能复用已有签名/HTTP 基础设施,但要补齐 API)。
3. 目标架构(单体部署)
3.1 进程形态
单体 Spring Boot 应用(Java 17),对外提供 REST API:
external-api:外部系统调用入口(推送商品/触发上架/查询结果)admin-api(可选,首期可不暴露):用于运维/店铺授权维护/密钥配置
3.2 逻辑分层(建议)
- API 层:只做参数校验、鉴权、幂等键处理、调用 Service、统一响应
- Service 层:
- 统一商品模型校验与映射
- 上架编排(创建→更新→库存→上架状态)
- 与拼多多适配层交互
- 任务化(可选):异步发布/重试/死信
- Adapter 层(PDD):
- HTTP + 签名 + 请求/响应模型
- 平台错误码映射
4. 对外接口设计(External/外部系统 → 本服务)
说明:下面是建议接口。落地时以外部系统现有调用规范为准,可在后续命令下达后再对齐路径/DTO 命名。
4.0 已确认口径(冻结)
shopId:全平台唯一,可直接作为本服务店铺主键,不考虑跨平台撞号。platform:由外部系统显式传入,取值采用PDD/TAO/JD/DOU/WEIXIN/KWAI/XHS(后续平台新增再扩展枚举)。- AK/SK:一套即可(外部系统作为单一调用方)。
X-Timestamp:毫秒(ms)。X-Signature:Base64 编码(HMAC-SHA256 输出 bytes → Base64)。- 签名 body:使用原始请求体 raw bytes 计算 SHA-256(不做 JSON 重排/字段排序)。
- 参数形态:统一走 body(尽量避免 query;GET 若必须使用 query,则改为 POST 查询接口更一致)。
- 幂等:完全由本服务内部实现,不依赖调用方提供
X-Request-Id。 - 商品素材:首期按公网可访问 URL(不做素材代上传)。
- 接口形态:首期按同步接口(直接返回发布结果或明确错误)。
4.1 统一返回
code: 0 成功;非 0 失败msg: 错误信息data: 业务数据
4.2 鉴权(AK/SK 签名)
请求头
X-Api-Key: 分配给调用方的 AKX-Timestamp: 毫秒时间戳(例如1710000000000)X-Nonce: 随机串(建议 16~32)X-Signature: 签名串(Base64)Content-Type: application/json
签名串构造(推荐)
canonical string:
HTTP_METHOD(大写)PATH(不含域名,不含 query)timestampnoncebodySha256Hex(请求体 raw bytes 的 SHA-256,hex)
拼接方式:
METHOD + "\n" +
PATH + "\n" +
timestamp + "\n" +
nonce + "\n" +
bodySha256Hex
签名算法:
signature = HMAC-SHA256(secret, canonicalString)- 输出:对
signature的 bytes 做Base64。
校验规则
timestamp与服务端时间偏差 ≤ 300 秒(按 ms 计算)nonce在时间窗内不可重复(需要缓存,例如 Redis/本地 Caffeine,首期可先用 Redis)X-Api-Key必须存在且有效(数据库/配置中)X-Signature校验失败直接拒绝
错误码建议
- 401:缺少必要头/签名参数
- 403:签名错误、AK 无效、nonce 重放
- 429:频控(可选)
4.3 商品接入与上架接口(建议)
4.3.1 推送/更新商品(SPU + SKU)
POST /external/goods/upsert
入参:
shopId(必填)platform(必填,枚举,例如PDD/TAO/JD…;首期仅允许PDD)outGoodsId:调用方侧商品ID(用于幂等与映射)title、mainImages[]、detail(富文本/图片 URL 列表等)skus[]:outSkuId、spec、price、stock、barCode…category、attrs、brand、weight、shipping…
行为:
- 本地保存/更新商品库(以
shopId + outGoodsId幂等) - 返回本地
goodsId(内部ID)与当前状态
4.3.2 触发上架(编排)
POST /external/goods/listing/submit
入参:
shopIdplatform(必填,首期仅允许PDD)outGoodsIdmode:CREATE_OR_UPDATE(默认)
行为(同步/异步二选一,建议首期同步 + 超时控制,后续演进异步):
- 若平台商品不存在:创建商品 → 创建/更新 SKU → 设置库存 → 上架
- 若已存在:更新商品 → 更新 SKU → 库存 → 上架/保持
返回:
listingTaskId(若异步)- 或直接返回平台侧
goodsId/状态
4.3.3 上下架
POST /external/goods/listing/status
入参:
shopIdplatform(必填,首期仅允许PDD)outGoodsIdstatus:ON/OFF
4.3.4 库存更新(可被 submit 内部调用,也可单独暴露)
POST /external/goods/stock/update
入参:
shopIdplatform(必填,首期仅允许PDD)outGoodsIdskus[]:outSkuId+stock
4.3.5 查询发布状态/映射
GET /external/goods/listing/status?shopId=...&platform=...&outGoodsId=...
返回:
- 平台商品ID、上下架状态、最后一次错误、最后同步时间
5. 领域模型(最小集合)
5.1 本地核心表(建议最小)
shop:店铺基础信息(含平台类型=PDD)shop_auth:拼多多 appKey/appSecret/accessToken/refreshToken/过期时间goods:统一商品(承接调用方)goods_sku:统一 SKU(承接调用方)goods_platform_mapping:统一商品与平台商品映射(平台 goodsId、skuId 映射)listing_task(可选):异步发布任务、重试次数、状态机api_client:AK/SK、状态、权限范围、IP 白名单(可选)api_request_log:审计(签名校验结果、请求摘要、耗时)
5.2 幂等策略(必须)
shopId + outGoodsId:商品幂等键shopId + outSkuId:SKU 幂等键- 不依赖调用方幂等键:本服务内部需实现“请求去重/防重复上架”。
- 推荐:落库
idempotency_key = sha256Hex(platform + shopId + outGoodsId + operation + normalizedBodyHash) - 同一
idempotency_key在有效期内重复请求:直接返回第一次执行结果 - 对“提交上架”类接口:至少保证不会重复创建平台商品
- 推荐:落库
6. 拼多多适配(PDD Adapter)设计要点
6.1 适配层职责
- 拼多多 API 签名、请求发送、响应解析
- 平台错误码归一化
- “创建/更新/上下架/库存”接口封装为内部方法:
createGoods(...)updateGoods(...)updateSku(...)updateStock(...)setGoodsOnSale(...)/setGoodsOffSale(...)
6.2 依赖策略(重要)
当前 oms-api 通过 systemPath 引入 open-sdk-2.1.12.jar。
首期有两条路径(二选一):
- 路径 1(优先):在本仓库内新增
pdd-adapter(源码方式),不再依赖open-sdk-2.1.12.jar做发布能力(只保留 pull 同步可继续复用或也迁移)。 - 路径 2(备选):升级/替换
open-sdk,确保其暴露发布相关 API(需要确认是否可获得源码/维护成本)。
推荐路径 1:可控、可审计、便于后续扩展多平台。
7. 裁剪方案(保留/删除建议)
原项目是微服务结构(gateway/sys-api/erp-api/oms-api 等)。你的目标是单体优先,因此裁剪思路是:
- 保留商品域 + 拼多多域 + 鉴权
- 其它域模块不编译/不启动/不暴露接口
7.1 建议保留(首期)
core/common(通用工具、AjaxResult 等)core/security(复用登录/权限基础设施的同时,新增 S2S AK/SK 鉴权)model(实体/BO/VO)mapper(DB 访问)service、serviceImpl中与商品/店铺/拼多多相关的最小集合api/erp-api(商品库接入:/goods/add等入口可重构为/external/goods/*)api/oms-api中 拼多多商品拉取(同步)相关接口(可改为内部任务或保留对外)
7.2 建议禁用/后置
api/ai-agentapi/sys-api(如仅对调用方开放,不需要后台用户体系,可后置)api/gateway(若单体直连,不需要网关;若保留网关需把 TokenFilter 改为 AK/SK 校验)oms-api中非拼多多平台(dou/jd/tao/wei/kwai…)- 订单/售后/发货/库存出入库/采购等 Controller 与 Service
8. 安全与审计
- 所有外部系统接口强制 AK/SK
- 平台一致性校验(强制):
- 调用方传入
platform - 服务端根据
shopId查询数据库中的shopType/platformType - 若两者不一致:直接拒绝(建议 400 或 403),记录审计日志
- 目的:避免“串平台/串店铺”导致误上架
- 调用方传入
shopId必须存在且平台类型为 PDD- 店铺 accessToken 过期:返回明确错误码(例如
SHOP_TOKEN_EXPIRED),并支持后台刷新/重新授权流程(首期可人工) - 全链路日志:
requestId、shopId、outGoodsId、平台错误码、耗时
- 敏感信息保护:
- appSecret/accessToken 加密存储(KMS/本地对称加密;首期可用配置密钥 + AES)
- 严禁打印明文 token/secret
9. 验证与验收清单(首期)
- 外部系统推送商品 → 本地入库(幂等生效)
- 触发上架 → 拼多多创建/更新/库存/上下架成功(全链路)
- 上架失败可返回可读错误(含平台原始信息可追踪)
pull_goods同步可用(用于对账/状态回写)- AK/SK:
- 缺参拒绝
- 签名错误拒绝
- 超时拒绝
- nonce 重放拒绝
- 审计日志完整
10. 待你确认/后续落地前置
- 拼多多商品发布所需字段“最小集”(类目、属性、物流、售后承诺、资质等)需要你提供调用方侧现有字段映射或样例 payload。
- 是否需要“异步上架”(返回 taskId + 回调/轮询)。首期建议同步,但需要设定超时时间与重试策略。