对标 Shopify Plus(含 Online Store 2.0、Admin/Storefront API、Checkout Extensibility)的全量电商系统需求规格说明书
文档版本:v1.0
编写日期:2026-07-21
适用技术栈:Python 3.11 + Django 5.x + Django REST Framework + Celery + PostgreSQL + Redis
本文档以 Shopify Plus(含 Online Store 2.0 主题体系、Admin GraphQL API、Storefront API、Checkout Extensibility)为功能对标基准,落地到 Python + Django 技术栈,形成一份覆盖全量电商业务的功能需求规格说明书。
文档面向以下读者:
- 产品经理 / 业务负责人:用于确认功能范围、字段口径与业务规则
- 后端开发工程师:用于理解 Django app 切分、数据模型、API 设计
- 前端 / 主题开发工程师:用于理解模板系统、Storefront 数据契约
- 测试工程师:用于逐条拆解验收点
| 对标来源 |
覆盖范围 |
Shopify Admin API (GraphQL) |
商品、订单、客户、库存、折扣、营销、分析、文件、Fulfillment 等后台能力 |
Shopify Storefront API |
商城前台(商品检索、购物车、Checkout、客户查询)数据契约 |
Online Store 2.0 |
主题架构(sections / blocks / JSON templates / theme settings) |
Checkout Extensibility |
可扩展结账(Web Pixel、Checkout UI Extensions、Shop Pay 类支付体验) |
Shopify Markets |
多市场(多币种、多语言、多区域定价、关税) |
Shopify Inbox / Email / Audiences |
营销自动化与触达 |
Shopify Flow / Functions |
业务自动化与可编程折扣逻辑(用 Django 信号 + Celery + 自定义脚本引擎替代) |
- 不复刻 Shopify 的 SaaS 控制台(不提供”商家注册即开店”的多租户入驻流程,本期默认单商户私有部署,但底层数据结构预留
shop_id 字段以支持未来扩展)
- 不实现 Shopify App Store 应用市场机制(仅支持以 Django app 方式插件化扩展)
- 不复刻 Shopify 系、Shop Pay、Shop App 等品牌专属封闭能力,用通用的快捷支付、钱包方案替代
- 不自建支付网关(接入第三方:Stripe / 支付宝 / 微信支付 / 银联等)
| 术语 |
含义 |
Shopify 对应 |
| 店铺(Shop) |
一个独立的电商站点实例 |
Shop |
| 商品(Product) |
可售实物或数字品 |
Product |
| 多属性(Variant) |
商品的 SKU 维度组合(颜色×尺码等) |
Product Variant |
| 收藏(Collection)/集合 |
商品的分组(手动 / 自动规则) |
Collection |
| 元字段(Metafield) |
业务对象上的自定义扩展字段 |
Metafield |
| 履约(Fulfillment) |
订单出库、发货、物流分配 |
Fulfillment |
| 多渠道(Channel) |
销售渠道:在线店、POS、Facebook、手动等 |
Sales Channel |
| 草稿订单(Draft Order) |
由商家手工创建的订单 |
Draft Order |
| 放弃结账(Abandoned Checkout) |
客户进入结账但未完成付款 |
Abandoned Checkout |
| 主题(Theme) |
前端展示模板集合 |
Theme |
| 元对象(Metaobject) |
业务侧自定义结构化数据类型 |
Metaobject |
系统采用 前后端分离 + 服务端渲染混合 架构(对标 Shopify 由 Liquid 服务端渲染 + Hydrogen 客户端的混合策略)。
┌────────────────────────────────────────────────────────────────────┐
│ 客户端层 (Clients) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Online Store │ │ Headless 站点│ │ 第三方渠道 │ │ Admin 后台│ │
│ │ (Django 模板)│ │ (React/Vue 等│ │ (POS/社交/Mk│ │ (Django+JS│ │
│ │ │ │ 走Storefront│ │ 走Admin API│ │ Admin) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘ │
└────────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Storefront │ │ Admin API │ │ Webhook / │
│ API (DRF) │ │ (DRF/Graph │ │ Event Bus │
│ 只读+下单 │ │ ql via │ │ (Celery+ │
│ │ │ strawberry)│ │ Redis pubsub)│
└──────────────┘ └──────────────┘ └──────────────┘
└─────────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ 核心业务领域层 (Domain Apps) │
│ products │ inventory │ orders │ payments │
│ checkout │ customers │ discounts │ marketing│
│ themes │ content │ analytics │ channels │
│ shops │ settings │ metafields│ users │
└─────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────┐
│ 基础设施层 (Infrastructure) │
│ PostgreSQL │ Redis │ Celery │ Storage(S3) │
│ Search(Postgres FTS/Elastic) │ Cache │ MQ │
└─────────────────────────────────────────────┘
| 层次 |
技术 |
选型原因 |
| Web 框架 |
Django 5.x |
成熟 ORM、Admin、权限、i18n、模板系统一站到位 |
| API 框架 |
Django REST Framework + strawberry-graphql-django |
REST 用于第三方 Admin API 对接;GraphQL 复刻 Shopify Storefront 数据契约 |
| 异步任务 |
Celery + Redis broker |
放弃结账提醒、邮件发送、报表生成、库存同步等异步场景 |
| 缓存 |
Redis (django-redis) |
商品列表、变体解析、限流、Session |
| 全文检索 |
PostgreSQL FTS(Phase 1)→ Elasticsearch/Meilisearch(Phase 2) |
商品搜索、筛选、聚合 |
| 数据库 |
PostgreSQL 15+ |
支持 JSONB(metafields)、btree_gin、分区表(orders) |
| 对象存储 |
S3 兼容(MinIO / OSS / COS) |
商品图、主题资源、导出文件 |
| 任务调度 |
Celery Beat |
定时任务(每日对账、库存阈值告警) |
| 前端模板 |
Django Template + TailwindCSS / HTMX(兼容 Liquid 思路) |
服务端渲染对标 Shopify Liquid |
| 头部电商前端 |
React + Hydrogen-like(Phase 3) |
通过 Storefront API 实现 Headless,对标 Shopify Hydrogen |
| 鉴权 |
django-allauth + JWT (djangorestframework-simplejwt) |
客户端账户、社交登录 |
| 权限 |
django-guardian + 自定义对象级权限 |
商家员工分对象授权 |
| Webhook |
django-restframework + 自签校验 + HMAC SHA256 |
对外推送事件 |
| 可观测 |
Sentry + Prometheus + Grafana |
错误/性能监控 |
| 容器 |
Docker + docker-compose / k8s |
部署 |
| CI/CD |
GitHub Actions + 蓝绿/滚动 |
自动发布 |
采用 DDD 限界上下文 切分,每个 app 内含 models.py / services.py / api.py / admin.py / signals.py / migrations。
project/
├── apps/
│ ├── shops/ # 店铺、店铺设置、域名
│ ├── accounts/ # 员工、权限、客户账户
│ ├── products/ # 商品、变体、收藏、图片
│ ├── inventory/ # 库存、库位、调拨、库存事件
│ ├── pricing/ # 价格、多市场定价、汇率
│ ├── cart/ # 购物车、运费预估
│ ├── checkout/ # 结账会话、地址、运费、税额、订单生成
│ ├── orders/ # 订单、履约、退款、取消、退货
│ ├── payments/ # 支付意图、支付凭证、对账、网关适配
│ ├── customers/ # 客户档案、地址簿、积分
│ ├── discounts/ # 折扣码、自动折扣、购物车规则
│ ├── marketing/ # 邮件/SMS 触达、自动化、Audience 分群
│ ├── analytics/ # 销售分析、漏斗、留存、报表
│ ├── themes/ # 主题、模板、sections、blocks、资源
│ ├── content/ # 页面、博客、文章
│ ├── catalog/ # 导航、菜单、Shopify Metaobject
│ ├── metafields/ # 通用元字段
│ ├── seo/ # SEO 模板、 redirects、URL 别名
│ ├── channels/ # 多渠道(POS / Online / 手动 / Facebook 等)
│ ├── tax/ # 税率、税务计算引擎
│ ├── shipping/ # 运费策略、承运商适配
│ ├── webhooks/ # Webhook 订阅、推送、重试
│ ├── notifications/ # 通知模板(邮件/SMS/站内)
│ └── web/ # 商城前台视图(Liquid-like 渲染入口)
├── core/ # 公共:BaseModel、混入、枚举、错误码
├── infra/ # 基础设施接入:storage、cache、mq、observability
├── config/ # settings、urls、wsgi/asgi
└── tests/
- Shopify 的 Liquid + Sections architecture → 在 Django 中以”主题资源 + 模板引擎 JSON schema + 区块组件类” 实现,见第 13 章
- Shopify 的 Admin/Storefront 双 API → 同样拆分两套 endpoint:Admin API 走
/api/admin/*(店铺员工鉴权),Storefront API 走 /api/storefront/*(Public Token 鉴权,对应 Shopify 的 Storefront Access Token)
- Shopify 的 Metafields → 通用
apps/metafields/,所有主业务模型 mixin HasMetafieldsMixin,以 JSONB 列存储 + schema 校验
- Shopify 的 Functions / Flow → 用
apps/discounts + services/script_engine.py 实现基于 Python 的可执行折扣/运费/税脚本(受控沙箱,禁用 import)
按业务对象划分共 17 个一级模块,每个模块下若干功能点(FP,Function Point)。
| 编号 |
模块 |
主要功能点数 |
优先级 |
章节 |
| M01 |
商品与目录 |
28 |
P0 |
第 4 章 |
| M02 |
库存与履约 |
16 |
P0 |
第 5 章 |
| M03 |
购物车与结账 |
22 |
P0 |
第 6 章 |
| M04 |
订单管理 |
26 |
P0 |
第 7 章 |
| M05 |
支付与结算 |
18 |
P0 |
第 8 章 |
| M06 |
客户与会员 |
17 |
P1 |
第 9 章 |
| M07 |
折扣与促销 |
19 |
P1 |
第 10 章 |
| M08 |
营销与触达 |
14 |
P1 |
第 11 章 |
| M09 |
数据分析 |
16 |
P1 |
第 12 章 |
| M10 |
主题与模板 |
21 |
P0 |
第 13 章 |
| M11 |
页面与博客 |
9 |
P1 |
第 14 章 |
| M12 |
SEO 与域名 |
11 |
P1 |
第 15 章 |
| M13 |
多渠道销售 |
8 |
P2 |
第 16 章 |
| M14 |
权限/多语言/税务 |
15 |
P1 |
第 17 章 |
优先级说明:P0 = MVP 必须具备;P1 = 首个大版本必须具备;P2 = 后续迭代。
每个功能模块的章节统一格式:
1. 业务目标
2. 角色与流程
3. 功能点清单(按 FR 编号)
4. 关键业务规则
5. 数据要点
6. 接口要点(Admin / Storefront / Webhook)
7. Shopify 对标说明
8. 验收要点
对标 Shopify 的 Products / Variants / Collections / Inventory / Metafields,提供从商品建模、多属性管理、商品分组、自动集合规则到自定义字段扩展的完整能力,支撑实物 / 数字 / 服务三类商品。
- 商品编辑员:建商品、配变体、配图、配元字段、配 SEO
- 商品管理员:批量上下架、调价、归类、调库存
- 主题开发者:通过 sections 渲染商品数据
- 客户:浏览、搜索、加入购物车
关键流程示例:商品创建→变体生成→库存初始化→上架
编辑员新建 Product (draft)
↓ 配置 Option(颜色/尺码)→ 自动生成 Variant 笛卡尔积
↓ 为每个 Variant 维护 SKU / Barcode / Price / Weight / Inventory Policy
↓ 绑定 Image(多图,可设主图)
↓ 加入 Collection 或建立自动集合规则
↓ 设置 Status = active → 商城可见
| FR 编号 |
功能点 |
说明 |
| FR-4.1.1 |
商品基础字段 |
标题、描述(富文本)、Handle(URL slug)、状态(draft/active/archived)、商品类型、厂商、模板后缀(用于模板路由) |
| FR-4.1.2 |
商品状态管理 |
draft → active → archived;archived 商品不出现在前台与管理统计中但仍可访问明细 |
| FR-4.1.3 |
商品 Tag 标签 |
多对多自由标签,用于搜索筛选与 automatic collection 规则匹配 |
| FR-4.1.4 |
商品选项(Options) |
最多 3 个选项维度(颜色/尺码/材质等);每个选项最多 100 个取值;变体数 ≤ 1000 |
| FR-4.1.5 |
商品多图管理 |
支持多张图片,每张可指定变体归属,主图置顶;图片走对象存储;自动生成多规格缩略图(200/400/800/1600/2400) |
| FR-4.1.6 |
商品 SEO 字段 |
meta_title、meta_description、og_image、handle 别名 |
| FR-4.1.7 |
商品元字段(Metafield) |
业务对象挂自定义结构化数据,支持 namespace.key、类型(string/integer/json/boolean/color/date/file/reference),支持列表型 |
| FR-4.1.8 |
商品模板后缀(template_suffix) |
指定专题模板文件名,前端按 product.<suffix>.liquid 渲染,未指定走默认 product.liquid |
| FR-4.1.9 |
商品礼品卡/数字类型 |
标记为 digital,下单后触发文件/卡密发放;标记 gift_card 类型走礼品卡逻辑 |
| FR-4.1.10 |
商品重量与海关编码 |
weight、weight_unit、hs_code、country_of_origin,用于运费与关税计算 |
| FR 编号 |
功能点 |
说明 |
| FR-4.2.1 |
单变体默认 |
仅一个变体 = 单品;至少保留一个默认变体 |
| FR-4.2.2 |
变体属性 |
SKU、Barcode(EAN/UPC/GTIN)、价格(含税价/不含税价)、对比价(划线价)、重量、税费类目、图片关联 |
| FR-4.2.3 |
变体库存策略 |
inventory_policy = deny(缺货停售)/ continue(继续售卖)/ oversell(限量超卖);与库位库存数量联动 |
| FR-4.2.4 |
变体调价与多币种 |
价格可按市场(Market)覆盖定义;与 M14 多市场定价打通 |
| FR-4.2.5 |
变体成本字段 |
cost 字段对客户不可见,用于毛利分析 |
| FR-4.2.6 |
变体重量计算 |
用于前端按重量配运费,可继承自父商品 |
| FR-4.2.7 |
变体条码 |
同 SKU 允许多条码;条码唯一性可选(按店铺设置) |
| FR 编号 |
功能点 |
说明 |
| FR-4.3.1 |
手动集合 |
人工挑选商品;支持排序(best_selling/price_asc/manual/created_desc/title_asc) |
| FR-4.3.2 |
自动集合 |
规则引擎:条件 = tag / price / type / vendor / stock / metafield,逻辑 AND/OR;规则变更触发 Celery 重算 |
| FR-4.3.3 |
集合层级 |
不支持多级嵌套(与 Shopify 一致),通过 menu + handle 模拟分层 |
| FR-4.3.4 |
集合图片与描述 |
用于集合页 SEO 与首图 |
| FR-4.3.5 |
集合模板后缀 |
collection.<suffix>.liquid,可分集合定制专属展示 |
| FR-4.3.6 |
集合商品数量与分页 |
默认 24/48/96 每页;支持 faceted 过滤 facet(按选项) |
| FR-4.3.7 |
Smart 集合规则预览 |
在保存前预览将匹配到的商品列表 |
| FR-4.3.8 |
集合排序同步 |
修改集合内商品顺序需 Redis 缓存失效并广播 channel 事件 |
| FR 编号 |
功能点 |
说明 |
| FR-4.4.1 |
Metafield 定义 |
由管理员预先定义 namespace + key + type,前端可引用 |
| FR-4.4.2 |
Metafield 引用类型 |
list.metaobject、file_reference、product_reference,建立弱关联 |
| FR-4.4.3 |
Metaobject 类型 |
自定义实体类型,如”品牌故事”、”门店信息”、”规格参数组”,含字段定义 |
| FR-4.4.4 |
Metaobject CRUD |
商家后台可视化编辑、批量导入导出 |
| FR-4.4.5 |
Metafield 权限 |
区分 PUBLIC(前台可读)与 PRIVATE(仅后台),防止敏感字段泄露 |
- R-4.1:商品至少一个变体,且变体价格、库存策略均可独立设置。删除父商品须级联归档所有变体,不物理删除(保留 90 天软删除以兼容历史订单)。
- R-4.2:
Handle 在店铺内唯一,自动根据标题生成(中文走 pinyin slugify 或拼音首字母),手动改后保留 301 重定向至新 handle。
- R-4.3:自动集合规则匹配采用”快照+定时刷新”双策略——保存即时快照匹配一次,之后每 15 分钟由 Celery 周期重算一次以保证新上架商品被收录。
- R-4.4:变体数 > 1000 时禁止前端”加载全部变体”,须改为按选项展开懒加载(与 Shopify 后台一致)。
- R-4.5:商品图片上传单文件默认上限 20MB,超过自动 WebP 转码并保留原图链接。SVG 须校验无
<script>。
- R-4.6:
Metafield 删除时记录 deleted_metafield 审计表,便于回滚。
- R-4.7:商品库存可见性 =
is_published AND status='active' AND inventory_policy != 'deny' OR inventory > 0,三重判断。
Product、ProductVariant、Collection、CollectionProduct(排序表)、Image、Metafield 等。详见 第 18 章 数据模型设计。关键约束:
Product.handle 联合 shop_id 唯一索引
ProductVariant.sku 联合 shop_id 唯一索引(可配置为可空非唯一)
CollectionProduct 用 (collection_id, product_id, position) 复合索引支撑分页与排序
Metafield.owner_type + owner_id + namespace + key 组合唯一
- 商品搜索:
Product.search_vector(PostgreSQL tsvector + GIN 索引,由 title/tags/description 拼接构建)
| Method |
Path |
用途 |
| GET |
/api/admin/products.json |
商品列表(支持 limit/page/ids/collection_id/published_status/updated_at_min 等过滤) |
| GET |
/api/admin/products/{id}.json |
商品详情 |
| POST |
/api/admin/products.json |
创建商品(含变体) |
| PUT |
/api/admin/products/{id}.json |
更新商品 |
| DELETE |
/api/admin/products/{id}.json |
归档商品 |
| POST |
/api/admin/products/{id}/metafields.json |
添加元字段 |
| GET/POST/PUT |
/api/admin/variants/* |
变体 CRUD |
| GET/POST/PUT |
/api/admin/collections/* |
集合 CRUD |
| GET/POST |
/api/admin/collections/{id}/products.json |
集合内商品管理 |
| POST |
/api/admin/inventory_levels/set.json |
设置库位库存(见库存模块) |
| GET |
/api/admin/products/count.json |
计数(用于仪表盘) |
query productByHandle($handle: String!) {
productByHandle(handle: $handle) {
id title description handle
featuredImage { url altText width height }
images(first: 20) { edges { node { url altText } } }
variants(first: 50) {
edges { node { id title sku priceV2 { amount currencyCode }
availableForSale selectedOptions { name value } } }
}
options { id name values }
metafields(namespace: "custom") { edges { node { key value } } }
}
}
| 事件 |
触发时机 |
Payload |
products/create |
商品创建后 |
商品对象 |
products/update |
任意字段更新 |
商品对象 |
products/delete |
归档后 90 天物理删除 |
{id} |
collections/create、collections/update、collections/delete |
集合变更 |
集合对象 |
inventory_levels/update |
库存数量变更(详见第 5 章) |
库位库存对象 |
- 字段粒度上完整对齐 Shopify
Product / ProductVariant / Collection / Image / Metafield 模型
automatic collection 规则引擎实现 Shopify 的 5 类条件 + AND/OR 组合
template_suffix 等同 Shopify 的”模板后缀”机制
- 缺省不实现的 Shopify 功能:
Product.media(视频/3D 模型),标注为 P2 后续迭代
Product.quoted_price、priceV2 等价格对象对标 Storefront API 的多币种价格结构
- [ ] 单个商品 100 个变体在管理后台可在 1.5s 内完成列表渲染
- [ ] 删除商品后历史订单仍可查询到SKU 与商品名(软删除生效)
- [ ] 自动集合规则修改后 15 分钟内新匹配商品可见
- [ ] Metafield PRIVATE 类型不出现在 Storefront API 响应中
- [ ] 商品搜索 1 万商品库下 p95 < 200ms
对标 Shopify Inventory Locations / Inventory Levels / Inventory Adjust / Fulfillment / FulfillmentService,提供多仓多库位的库存跟踪、调拨、出库履约。
- 库存管理员:建库位、调拨、盘点
- 履约运营:订单分仓、生成发货单、对接物流
- 系统自动:库存阈值告警、超卖拦截、跨库位分配
订单支付完成 → inventory engine 按"就近+充足"算法选库位 → 锁库存 →
履约:拣货 → 包装 → 称重 → 生成物流面单 → 发出 → 库存递减 →
完成履约,订单状态进入 shipped
| FR 编号 |
功能点 |
说明 |
| FR-5.1.1 |
库位 CRUD |
名称、地址、是否活跃、是否兼作发货点 |
| FR-5.1.2 |
库位类型 |
physical(自仓)/ fulfillment_service(第三方履约服务,对接口回传库存) |
| FR-5.1.3 |
多库位库存 |
同 SKU 在多库位维护不同库存数量 |
| FR 编号 |
功能点 |
说明 |
| FR-5.2.1 |
库存级别(InventoryLevel) |
location_id + variant_id + available 三元组 |
| FR-5.2.2 |
库存调整 |
手工调整 + 备注原因(损益、盘点、退货入库);写 inventory_adjustment 日志表 |
| FR-5.2.3 |
库存事件流 |
所有变动(售出、履约扣减、退款回库、调整)写入 inventory_event 不可变事件表 |
| FR-5.2.4 |
安全库存阈值 |
每库位单独配,低于阈值触发 Celery 邮件 + 站内通知 |
| FR-5.2.5 |
库存预留(reserved) |
进入结账 5 分钟内预留库存,过期释放;预留数量计入 committed,不可再次售卖 |
| FR-5.2.6 |
入库预期(incoming) |
采购单字段,可见但不可售;到达后转换为 available |
| FR-5.2.7 |
多店统一视图 |
商家后台一屏查看所有库位某 SKU 的总库存与分布 |
| FR 编号 |
功能点 |
说明 |
| FR-5.3.1 |
履约单创建 |
订单按 line_item 与库位拆出 FulfillmentOrder,可拆单履约 |
| FR-5.3.2 |
履约状态机 |
unfulfilled → in_progress → fulfilled / on_hold / cancelled |
| FR-5.3.3 |
物流面单集成 |
支持顺丰/京东/德邦/中通/UPS/FedEx 等承运商 API 自动下单取单号 |
| FR-5.3.4 |
手动填单 |
允许运营手工填写运单号与公司,触发客户通知 |
| FR-5.3.5 |
履约事件回写 |
客户在订单详情页可查询物流轨迹(轨迹异步拉取并缓存) |
| FR-5.3.6 |
部分履约 |
一单可拆多次履约,每笔履约分别关闭对应 line_item |
| FR-5.3.7 |
履约取消 |
履约未发出前可取消,库存重新入库;发出后只能走退货反向流程 |
| FR-5.3.8 |
履约服务回调 |
fulfillment_service 类型库位通过回调接口反向回传状态 |
- R-5.1:库存 =
available(可售)+ committed(预留/已售未发)+ incoming(在途);available 是前端可见可购买的库存,不允许超卖除非 inventory_policy=continue 或 oversell。
- R-5.2:跨库位库存同步必须使用 Redis 分布式锁防并发扣减竞争。
- R-5.3:退货入库必须走人工审核,自动入库仅限未发出的履约取消。
- R-5.4:库位发货能力受限于店铺设置:商家可指定仅某些库位对外发货。
- R-5.5:每个 SKU 在每个库位保留独立的安全库存,触发阈值告警必须包含库位名、当前库存、阈值、商品名/SKU。
Location / InventoryLevel / InventoryAdjustment / InventoryEvent / FulfillmentOrder / Fulfillment / FulfillmentEvent。详细字段见第 18 章。
| Method |
Path |
用途 |
| GET/POST |
/api/admin/locations.json |
库位 CRUD |
| GET |
/api/admin/inventory_levels.json |
查库存 |
| POST |
/api/admin/inventory_levels/set.json |
设置库位库存(覆盖式) |
| POST |
/api/admin/inventory_levels/adjust.json |
调整库存(delta) |
| POST |
/api/admin/inventory_levels/connect.json |
变体激活到某库位 |
| GET/POST |
/api/admin/fulfillment_orders.json |
履约单查询/状态流转 |
| POST |
/api/admin/fulfillments.json |
创建履约(含跟踪号) |
| POST |
/api/admin/fulfillment_events.json |
物流轨迹事件 |
query variantAvailability($id: ID!) {
node(id: $id) {
... on ProductVariant { availableForSale quantityAvailable }
}
}
inventory_levels/update
fulfillment_orders/create、/fulfilled、/cancelled
fulfillments/create、/update
- 完整对齐 Shopify 的 Location / InventoryLevel / InventoryAdjustment / FulfillmentOrder / Fulfillment 抽象
quantity_available 字段定义、committed/incoming 三态语义复用 Shopify Inventory API 1:1
- 缺省不实现 Shopify 配套的”FulfillmentService 应用市场”机制,仅支持本地配置的履约服务
- [ ] 100 并发下单同一 SKU 不出现超卖(基于行级锁 + Redis 锁双保障)
- [ ] 库存调整日志可追溯到操作员、时间、原因、前后值
- [ ] 部分履约后的订单状态与库存数据自洽
- [ ] 物流轨迹自动拉取,缓存 30 分钟,超时回源
对标 Shopify Cart API + Checkout(结合 Checkout Extensibility),实现商品入车、改数量、加备注、估算运费税额,最终生成订单前完整的地址+运费+税额+支付方式选择会话。
- 客户:访问商城 → 加购物车 → 进入结账 → 填地址 → 选运费 → 选支付 → 完成下单
- 系统自动:结账会话创建后倒计时 30 分钟,过期清空预留库存
核心状态机:
[GUEST/LOGGED_IN]
↓ add-to-cart
[CART] ── 持久化 (Session + DB 行)
↓ enter-checkout (校验商品 still for_sale)
[CHECKOUT_SESSION] 预留库存 5~15 分钟
↓ submit_shipping_address
[SHIPPING_VALIDATED]
↓ select_shipping_rate
[RATES_LOCKED]
↓ submit_payment_intent
[PAYMENT_AUTHED]
↓ complete (原子事务)
[ORDER_CREATED] → release/persist reserved stock
| FR 编号 |
功能点 |
说明 |
| FR-6.1.1 |
多 line item |
同购物车可包含多个不同变体 |
| FR-6.1.2 |
同变体合并 |
重复 add 同一变体默认累加数量,可设置为替换 |
| FR-6.1.3 |
数量修改 |
支持增减、直接覆盖,0 表示删除 |
| FR-6.1.4 |
购物车备注 |
客户可填购物车备注(如包装要求),写入 order.note 而非 line item |
| FR-6.1.5 |
购物车属性(attributes) |
key-value 用作渠道来源、AB 测试 cookie 等隐藏元数据,写入 order.attributes |
| FR-6.1.6 |
优惠码预览 |
在购物车输入折扣码可即时计算预估优惠,但实际优惠应用发生在结账阶段 |
| FR-6.1.7 |
持久化与归属 |
登录用户合并匿名购物车(按 variant 重新计算),存入 DB;匿名用户存 Session/Redis,30 天有效 |
| FR-6.1.8 |
主题 / API 双写 |
模板里 {{ cart.items }} 渲染,等同 Storefront API cart 对象 |
| FR-6.1.9 |
购物车行级属性 |
line item 可挂自定义属性(如刻字内容),保留展示与不重复计费 |
| FR-6.1.10 |
礼品卡 / 数字处理 |
行内显示”礼品卡将于付款后自动发送至收件人邮箱” |
| FR 编号 |
功能点 |
说明 |
| FR-6.2.1 |
结账会话创建 |
由 cart 派生,独立 checkout_token,5 分钟无操作自动回收,最长 30 分钟 |
| FR-6.2.2 |
地址表单 |
收件人姓名、电话、邮箱、地址行 1/2、城市、省、邮编、国家;自动填充已登录用户默认地址 |
| FR-6.2.3 |
地址校验 |
调外部地址服务(如阿里云邮政编码/顺丰地址校验);校验失败给提示但仍允许继续 |
| FR-6.2.4 |
账单地址 |
默认同收件地址,可分开填写;账单地址用于发票 |
| FR-6.2.5 |
运费策略计算 |
由 apps/shipping 返回可用 rate 列表(条件 = 重量/订单金额/地区/承运商);默认锁定 24 小时 |
| FR-6.2.6 |
税额计算 |
由 apps/tax 计算,按客户收货地+商品税类;含税/不含税显示由店铺设置 |
| FR-6.2.7 |
折扣码应用 |
单结账会话最多 5 个折扣码,冲突由 services/discount_engine.py 解决 |
| FR-6.2.8 |
礼品卡核销 |
输入礼品卡码扣减余额,多次可叠加 |
| FR-6.2.9 |
支付方式选择 |
基于订单/账单地址过滤可用支付渠道;信用卡/借记卡/支付宝/微信/银联/银行转账/PayPal/Apple Pay |
| FR-6.2.10 |
完成结账 |
原子事务:建订单 + 支付凭证上链 + 库存预留转扣减 + 触发 webhook + 转入 paid/authorized 状态 |
| FR-6.2.11 |
放弃结账判定 |
会话过期未完成 → 写入 abandoned_checkout,按配置时间发送 1~2 次挽回邮件 |
| FR-6.2.12 |
多步/单页切换 |
商家后台可切换”多步结账”或”单页结账” |
| FR-6.2.13 |
字段自定义 |
商家可启用/禁用”公司名”“备注”“电话必填”等开关 |
| FR-6.2.14 |
Webhook 与扩展点(Checkout Extensibility 对标) |
在结账关键步骤支持注入自定义 UI 与跟踪 Pixel:page_view/add_payment_info/checkout_complete 等 |
- R-6.1:购物车中已下架 / 断货变体加入购物车时返回”无法购买”提示并保留其他项;进入结账时强制重新校验,不通过则回退购物车并提示。
- R-6.2:结账会话 5 分钟无操作释放库存预留;保留 30 分钟内可继续(地址等已填信息不变)。
- R-6.3:运费 rate 列表必须包含”运费金额+预估时效(天)+承运商名+是否免税”四要素。
- R-6.4:税额由
apps/tax 集中计算,单一来源;前端任何展示都必须来自 tax_lines 字段。
- R-6.5:当
inventory_policy=deny 且库存不足时,结账前调整数量并提示客户。
- R-6.6:完成结账用
transaction.atomic() 包裹:”建订单 → 锁定 line_items → 扣减库存 → 记录 payment_intent”。任一步骤异常整体回滚。
- R-6.7:放弃结账挽回邮件默认 1 小时 + 24 小时各一封,模板可配;同一 checkout_token 不重复发送。
- R-6.8:商家可后台查询”放弃结账”列表,手动重发挽回邮件或一键创建草稿订单。
Cart / CartItem(line item 的购物车态)
CheckoutSession:状态 IN_PROGRESS / COMPLETED / EXPIRED,记录快照化字段(避免后续商品价格变化导致金额混乱)
CheckoutAddress(收件/账单)
CheckoutShippingRate(rate 快照,含金额、时效、承运商 ID)
CheckoutTaxLine(每行税目)
AbandonedCheckout:checkout_token + email + created_at + abandoned_at + line_items_snapshot
mutation cartCreate($input: CartInput!) {
cartCreate(input: $input) {
cart { id totalQuantity cost { totalAmount { amount currencyCode } }
lines(first: 50) { edges { node { id quantity merchandise { ... on ProductVariant { id sku } } } } } }
}
}
mutation cartLinesAdd / cartLinesUpdate / cartLinesRemove
mutation checkoutCreate($input: CheckoutCreateInput!)
mutation checkoutShippingAddressUpdateV2
mutation checkoutShippingLineUpdate
| Method |
Path |
用途 |
| GET |
/api/admin/abandoned_checkouts.json |
放弃结账列表 |
| POST |
/api/admin/abandoned_checkouts/{id}/reclaim.json |
重发挽回邮件 |
carts/create、carts/update(仅 API 购物车)
checkouts/create、checkouts/update、checkouts/delete
abandoned_checkouts/create
- 完全采用 Shopify 的
Cart + Checkout 拆分:Cart 是无身份会话态,Checkout 是产生 Order 必经的”已分配库存且校验通过”过渡态
Checkout Extensibility 通过 apps/checkout/extensions.py 加插件机制实现(hooks: address_step、shipping_step、payment_step、summary_widget、thank_you_page),与 Shopify 的 UI Extensions 语义对齐
- 实现 Web Pixel 接口:可注册 Pixel 监听
add_to_cart / begin_checkout / add_payment_info / purchase 等事件
- [ ] 50 并发同一变体加购物车,库存不超卖
- [ ] 结账会话过期机制 5 分钟内不可下单(释放后再次完成会重派库存)
- [ ] 运费 rate 改变后前端实时校准
- [ ] 支付完成原子性:支付凭证与订单 1:1,无孤立支付凭证
对标 Shopify Order / Draft Order / Refund / Return / Cancel / Order Edit,提供完整订单生命周期管理。
- 客户:下单 → 查订单 → 申请退款/退货
- 客服:编辑订单、改地址、退款、换货、手动改状态
- 仓库:履约(详见第 5 章)
- 系统:订单状态机自动推进
订单状态机(financial_status × fulfillment_status):
financial_status:
pending → authorized → paid → partially_paid → refunded → partially_refunded → voided
fulfillment_status:
null → unfulfilled → partial → fulfilled → restocked
order status:
open → closed (90 天自动 closed) / cancelled
| FR 编号 |
功能点 |
说明 |
| FR-7.1.1 |
订单 ID 与编号 |
数据库自增 ID + 店铺前缀 + 年月生成的可读编号 #1001-BJ-2026-000721 |
| FR-7.1.2 |
订单客户 |
关联 Customer(含游客下单创建轻量客户对象) |
| FR-7.1.3 |
收件/账单地址 |
快照式存储,姓名/单位/地址/邮编/电话/邮箱 |
| FR-7.1.4 |
line_items 快照 |
含 variant_id/sku/title/variant_title/已售数量、单价(含税不含税均保留)、税费、折扣分摊、税费分摊 |
| FR-7.1.5 |
折扣分摊 |
discount_allocations:每条 line item 分摊到的折扣金额 |
| FR-7.1.6 |
运费行 |
shipping_lines[]:title + price + tax_lines + code |
| FR-7.1.7 |
税费行 |
tax_lines[]:rate + price + title + channel;含 line item 与运费税款 |
| FR-7.1.8 |
总额对象 |
subtotal / total_shipping / total_tax / total_discounts / total_price / total_paid |
| FR-7.1.9 |
订单备注与标签 |
note(内部备注)+ tags(标签筛选)+ attributes(KV 来自结账) |
| FR-7.1.10 |
下单渠道 |
source_name:web/pos/api/手动(POS 借助 channel) |
| FR 编号 |
功能点 |
说明 |
| FR-7.2.1 |
财务状态 |
自动跟踪:支付授权→paid;部分付款→partially_paid;全退款→refunded |
| FR-7.2.2 |
履约状态 |
与 fulfillment 模块联动 |
| FR-7.2.3 |
取消订单 |
取消原因枚举(库存/欺诈/客户改单/其他),自动归还库存,按需发退款 |
| FR-7.2.4 |
关闭订单 |
90 天自动关闭,可手动重新打开 |
| FR-7.2.5 |
订单编辑(Order Edit) |
已下单未发货可编辑:增删 line item、改数量、改地址、调运费;编辑版本存档可回滚,差额走二次支付或退款 |
| FR-7.2.6 |
草稿订单转正 |
draft → confirmed 触发客户付款邮件;不直接扣库存,待客户付款完成 |
| FR 编号 |
功能点 |
说明 |
| FR-7.3.1 |
退款单(Refund) |
一订单可多次退款,含 line items、运费、调整金、税额分摊 |
| FR-7.3.2 |
退货流程(Return) |
客户申请 → 客服审核 → 收货确认 → 入库 → 退款;RMA 单号对接 |
| FR-7.3.3 |
退货运费承担 |
配置退货规则:商家承担/客户承担/按金额阈值 |
| FR-7.3.4 |
库存归还策略 |
退款时按 restock flag 决定是否回库;默认 true |
| FR-7.3.5 |
退款来源 |
自动退回原支付渠道;原渠道不可用走礼品卡或人工入账 |
| FR-7.3.6 |
部分退款 |
一笔订单允许多笔退款,总额不可超订单实付总额 |
| FR-7.3.7 |
退款与履约解耦 |
即使已发货也可退款(仅退款不退货),由客服人工审核 |
| FR 编号 |
功能点 |
说明 |
| FR-7.4.1 |
手工创建 |
客服代客下单,支持自定义价格、备注、客户邮箱 |
| FR-7.4.2 |
邮件付款链接 |
生成付款链接发客户,客户付款后转为正式订单 |
| FR-7.4.3 |
发票创建关联 |
草稿可关联发票模板,付款前发送 |
| FR-7.4.4 |
转 POS 直接收款 |
POS 渠道可直接收银将草稿订单转正式订单 |
- R-7.1:所有金额以”最小货币单位 ×10^decimal_places”整数保存(防浮点),与 Shopify cents 模型一致。
- R-7.2:取消订单产生
cancel_reason 与 cancelled_at,触发 orders/cancelled webhook。
- R-7.3:line_items 在订单生成时深度快照,原商品/变体删除不影响已存订单查询。
- R-7.4:order_edit 产生新版本,旧版本可查询;编辑差额生成
OrderAdjustment。
- R-7.5:退款必须遵循”先发支付再退款”原则,未付款订单不存在退款。
- R-7.6:自动同步 tags 至客户记录(如
wholesale),便于后续营销分群。
Order / OrderLineItem / OrderAddress(收件 + 账单)/ OrderShippingLine / OrderTaxLine / OrderAdjustment / Refund / RefundLineItem / Return / DraftOrder / DraftOrderLineItem
- 订单按月分区表
orders_2026_07,历史归档冷库
| Method |
Path |
用途 |
| GET |
/api/admin/orders.json?status=any&financial_status=paid&fulfillment_status=shipped |
多维过滤订单 |
| GET |
/api/admin/orders/{id}.json |
订单详情 |
| POST |
/api/admin/orders.json |
手动创建订单 |
| POST |
/api/admin/orders/{id}/cancel.json |
取消订单 |
| POST |
/api/admin/orders/{id}/close.json |
关闭订单 |
| POST |
/api/admin/orders/{id}/edit.json |
编辑订单 |
| POST |
/api/admin/orders/{id}/refunds.json |
创建退款 |
| GET/POST |
/api/admin/returns.json |
退货 CRUD |
| GET/POST/PUT |
/api/admin/draft_orders.json |
草稿订单 CRUD |
| POST |
/api/admin/draft_orders/{id}/send_invoice.json |
发付款邮件 |
query customerOrders {
customer {
orders(first: 20) {
edges { node { orderNumber processedAt fulfillments(first: 5) {
edges { node { trackingInfo { number url } } } }
totalPrice { amount currencyCode } } }
}
}
}
orders/create、orders/updated、orders/paid、orders/cancelled、orders/fulfilled、orders/partially_fulfilled、orders/deleted
refunds/create
draft_orders/create、draft_orders/update、draft_orders/delete
- 订单字段、状态、退款结构 1:1 对齐 Shopify Order REST API
- DraftOrder 与 Shopify 行为完全一致(先草稿后客户付款链接)
- Order Edit 机制对标 Shopify 2022 起开放的 editing API
- Return 流程对标 Shopify Returns API(含 RMA)
- [ ] 已下单商品删除后订单查询历史价/名 SKU 无损
- [ ] 部分退款再部分退款,最终退款金额不超过订单实付
- [ ] 取消订单后库存正确归还
- [ ] 草稿订单付款邮件链接 24 小时有效
对标 Shopify Payments / 第三方支付网关 / 礼品卡 / 支付网关适配层,提供统一的支付意图管理、清算对账、防欺诈。
- 客户:选支付方式 → 跳转网关 or 站内支付 → 回跳确认
- 系统:支付意图 → 凭证上链 → 订单状态推进
- 财务:日终对账
CheckoutSession → 创建 PaymentIntent(多条候选支付方式)
↓ 选定方式
[EXTERNAL_AUTH] 第三方托管 / iframe 内嵌
↓ 用户完成授权
[AUTHORIZED] payment_id 返回 + 3DS 校验通过
↓ capture(即时/延后)
[CAPTURED] 财务 paid
↓ 对账日终核对
[RECONCILED]
| FR 编号 |
功能点 |
说明 |
| FR-8.1.1 |
PaymentIntent 对象 |
关联订单 / checkout,存储 amount、currency、status、provider、processor_response |
| FR-8.1.2 |
多支付方式并存 |
一订单允许多笔支付凭证(如礼品卡 + 信用卡) |
| FR-8.1.3 |
authorize/capture 分离 |
支持延时扣款(预授权 + 货发后 capture) |
| FR-8.1.4 |
凭证上链日志 |
所有网关响应原文落库(敏感字段脱敏),用于争议处理 |
| FR-8.1.5 |
凭证幂等键 |
客户端 Idempotency-Key,避免双扣 |
| FR 编号 |
功能点 |
说明 |
| FR-8.2.1 |
抽象 PaymentGateway |
统一 authorize / capture / void / refund 接口 |
| FR-8.2.2 |
内置适配器 |
Stripe、Adyen、PayPal、支付宝、微信支付、银联、Apple Pay、Google Pay |
| FR-8.2.3 |
自定义网关 |
apps/payments/gateways/custom/ 允许商家后台填入 endpoint+签名规则,热插拔 |
| FR-8.2.4 |
测试与生产模式 |
shop 设置切换;测试凭证不写真实对账表 |
| FR-8.2.5 |
网关配置加密 |
API Key 用 cryptography.Fernet 加密落库 |
| FR 编号 |
功能点 |
说明 |
| FR-8.3.1 |
礼品卡产品类型 |
商品类型 = gift_card,下单触发自动生成礼品卡码 |
| FR-8.3.2 |
礼品卡 CRUD |
客服可手动创建/作废;余额变更审计 |
| FR-8.3.3 |
礼品卡核销 |
结账阶段输入卡号 + PIN,核销优先于其他支付方式 |
| FR-8.3.4 |
礼品卡余额退回 |
部分退款时礼品卡支付优先按原卡退回 |
| FR 编号 |
功能点 |
说明 |
| FR-8.4.1 |
每日对账任务 |
拉取各网关日流水,与 PaymentCapture 落账比较,差异入”对账异常”队列 |
| FR-8.4.2 |
对账报告 |
月度日维度出报表,含成功/失败/退款笔数金额 |
| FR-8.4.3 |
风控规则 |
基于规则(高金额/IP/同卡多次失败)拦截;外接风控引擎 |
| FR-8.4.4 |
3DS 强制 |
商家可按金额/IP 风险强制启用 3DS |
| FR-8.4.5 |
支付链接(Pay by Link) |
客服可对草稿订单生成支付链接发客户 |
- R-8.1:所有支付凭证必须可凭
(shop_id, transaction_id) 唯一定位;网关侧 ID 与本地 transaction_id 双向存储。
- R-8.2:金额必须以”整数最小货币单位”在前后端流转,仅在展示时按
currency.decimal_places 格式化。
- R-8.3:退款金额累计不得超过实付金额;礼品卡退款不可超过原核销金额。
- R-8.4:网关响应原文保留 90 天后归档冷库。
- R-8.5:所有 capture 失败必须有
failure_code + failure_message + next_retry_at 三元日志。
PaymentIntent、PaymentTransaction(authorize / capture / void / refund 各一笔)、GiftCard、GiftCardTransaction、ReconciliationReport、ReconciliationLine、FraudFlag
- 敏感字段(卡号、CVV)不入库;仅存 masked_pan(
4242****4242)
| Method |
Path |
用途 |
| GET |
/api/admin/orders/{id}/transactions.json |
订单支付凭证 |
| POST |
/api/admin/orders/{id}/transactions.json |
手工 capture 或 void |
| POST |
/api/admin/orders/{id}/refunds.json |
创建退款(含退款支付凭证) |
| GET/POST |
/api/admin/gift_cards.json |
礼品卡 CRUD |
| GET |
/api/admin/gift_cards/lookup.json?code=XXX |
查礼品卡余额 |
mutation checkoutCompleteWithCreditCardV2
mutation checkoutGiftCardApply
mutation giftCardCredit
payment_intent/payment_failed、payment_intent/payment_authorized、payment_intent/payment_captured
gift_cards/create、/update
- 抽象层与 Shopify
Transaction API 字段(kind = authorization / capture / sale / void / refund)一一对齐
- 礼品卡对标 Shopify GiftCard 资源(含 balance、initial_value、currency、code、disabled_at)
Shop Pay 不实现,用”快捷钱包”插件抽象留扩展位
- [ ] 同卡同金额两个相同请求只生成一笔支付凭证
- [ ] 网关失败重试不超过 3 次,且单笔订单 24 小时内最多 10 次
- [ ] 对账任务异常自动告警,财务人员在 24h 内确认
- [ ] 敏感字段(如卡号)一律不入库
对标 Shopify Customer / Customer Address / Customer Saved Search / Customer Group / Customer Tags / Customer Metafields,提供客户档案、地址簿、客户分群、消费历史、积分会员成长体系。
- 客户:访问商城 → 注册/游客下单 → 自动建档 → 查询订单/地址 → 申请退货
- 客服:合并/拆分客户档案、调标签、发分群邮件
- 营销:基于分群发起新一批营销活动
| FR 编号 |
功能点 |
说明 |
| FR-9.1.1 |
客户基本字段 |
first_name/last_name/email/phone(email 或 phone 至少一项)、accepts_marketing、note、tags |
| FR-9.1.2 |
自动建档 |
游客下单后订单完成时自动创建/合并客户档案(按 email 或 phone 匹配) |
| FR-9.1.3 |
客户账户激活 |
商家可邀请客户开账户;账户激活链接 7 天有效 |
| FR-9.1.4 |
账户字段(password / 身份) |
Django auth.User + 自定义 Customer,密码强度策略与双因素(TOTP)可选 |
| FR-9.1.5 |
社交账号关联 |
Google/Apple/Facebook/微信,通过 django-allauth 实现 |
| FR-9.1.6 |
客户删除请求 |
GDPR 删除请求 → 14 天宽限 → 真实删除(订单保留但客户字段脱敏) |
| FR-9.1.7 |
客户合并 |
客服发现两份档案指向同一人时合并(保留创建时间最早者);历史订单关联迁移 |
| FR 编号 |
功能点 |
说明 |
| FR-9.2.1 |
多地址 |
客户可管理多个收件/账单地址,每条地址含详情+是否默认 |
| FR-9.2.2 |
地址软删除 |
删除地址但保留 90 天关联订单地址快照可查 |
| FR-9.2.3 |
地址校验冗余 |
客户保存地址时验证国家+邮编格式 |
| FR 编号 |
功能点 |
说明 |
| FR-9.3.1 |
保存搜索(Saved Search) |
客服保存查询条件,复用过滤 |
| FR-9.3.2 |
静态分群(Segment) |
手工圈选客户,可发邮件 |
| FR-9.3.3 |
动态分群 |
规则 = 订单数/累计消费/标签/城市/最后下单时间/会员等级 等条件;按日重算 |
| FR-9.3.4 |
分群与营销联动 |
营销活动可选目标分群,支持过滤排除某些子集 |
| FR 编号 |
功能点 |
说明 |
| FR-9.4.1 |
会员等级规则 |
等级与累计消费挂钩,自动升降,跨级回退有 90 天宽限 |
| FR-9.4.2 |
积分获取 |
下单支付完成按比例计算积分;可设置不同品类不同倍率 |
| FR-9.4.3 |
积分核销 |
结账可使用积分抵扣;过期策略 1 年 |
| FR-9.4.4 |
积分流水 |
积分增减均写 point_ledger(earn/spend/expire/adjust) |
| FR-9.4.5 |
等级权益 |
不同等级不同折扣码、不同运费、不同免邮门槛、礼品生日礼 |
- R-9.1:客户唯一性 =
shop + email 或 shop + phone(phone 仅在主短信登录场景作为唯一键)
- R-9.2:客户合并必须经财务/合规确认;订单归属变更需记录
customer_merge_audit
- R-9.3:积分有效期由”获赠日期 + 店铺设置”决定;过期日 Cron 自动清零并记录
- R-9.4:会员等级每次订单完成后即时判定,但降级延迟生效(保护客户体验)
- R-9.5:删除客户时其订单保留为
guest_order,仅客户可识别信息脱敏
Customer、CustomerAddress、CustomerMetafield、CustomerSegment、CustomerSegmentMember、CustomerSavedSearch、MembershipTier、PointLedger、CustomerMergeAudit
Customer.summary 字段(last_order_at、orders_count、total_spent)由 Celery 任务异步更新
| Method |
Path |
用途 |
| GET/POST/PUT |
/api/admin/customers.json |
客户 CRUD + 字段过滤 |
| GET |
/api/admin/customers/{id}/orders.json |
客户订单列表 |
| GET |
/api/admin/customers/search.json?query=email:test@x.com |
Lucene 风格查询(简化版) |
| POST |
/api/admin/customers/{id}/account_activation_url.json |
生成账户激活链接 |
| POST |
/api/admin/customers/{id}/merge.json |
客户合并 |
query customer {
customer { id displayName email firstName lastName defaultAddress { ... }
orders(first: 10) { edges { node { orderNumber } } } }
}
customers/create、customers/update、customers/delete、customers/merge、customers/disable、customers/enable
- Customer 主表字段与 Shopify 一致;Segment 模块对标 Shopify Audiences(静态+动态)
- 客户合并是 Shopify Plus 增强,本系统完整实现以适应中国市场对客档合并的强需求
- 引入 Shopify 未提供的会员等级/积分体系(中国市场标配)
- [ ] 同 email 在 30 秒内连续两次游客下单只生成一个客户档案
- [ ] 客户合并后订单历史可追溯
- [ ] GDPR 删除 14 天后真实删除验证
对标 Shopify DiscountCode / AutomaticDiscount / PriceRule,提供折扣码、自动折扣、限时活动、买赠、阶梯优惠、组合购物优惠、可编程折扣函数。
- 营销:定义 PriceRule → 生成 Discount Code(批量)或 Automatic Discount
- 客户:结账输入折扣码 / 自动应用满足条件的折扣
- 系统:折扣引擎在结账阶段计算并分摊至 line_items
| FR 编号 |
功能点 |
说明 |
| FR-10.1.1 |
折扣类型 |
固定金额 / 百分比 / 免运费 / 买X送Y / 阶梯总价折扣 |
| FR-10.1.2 |
适用范围 |
全店 / 指定集合 / 指定商品 / 指定客户分组 |
| FR-10.1.3 |
最低消费门槛 |
全单金额门槛 OR 指定商品累计 |
| FR-10.1.4 |
数量门槛 |
“满 3 件”、”满 500g”等数量阈值规则 |
| FR-10.1.5 |
时间窗口 |
起止时间 + 每日循环窗口(如仅工作日) |
| FR-10.1.6 |
使用次数上限 |
总次数 + 单客户次数 + 单订单次数 |
| FR-10.1.7 |
叠加策略 |
是否允许多码叠加 / 是否与自动折扣叠加 / 与礼品卡是否叠加 |
| FR-10.1.8 |
市场范围 |
是否仅适用某 Market(市场) |
| FR 编号 |
功能点 |
说明 |
| FR-10.2.1 |
折扣码生成 |
单码 or 批量(CSV 导入 / 随机生成 + 长度/前缀) |
| FR-10.2.2 |
唯一性 |
店铺内码唯一,大小写不敏感(可配) |
| FR-10.2.3 |
客户绑定 |
单 code 绑定单客户(一对一邮件发放) |
| FR-10.2.4 |
使用记录 |
每码记录 usage_count,超额拒绝 |
| FR-10.2.5 |
过期时间 |
code 自身过期时间可短于 rule |
| FR 编号 |
功能点 |
说明 |
| FR-10.3.1 |
自动应用 |
满足条件自动应用,客户无需输入码 |
| FR-10.3.2 |
多档自动 |
同规则可多档阶梯,按最高档执行 |
| FR-10.3.3 |
突出展示 |
前端在购物车/商品页展示”已为您优惠 ¥X” |
| FR 编号 |
功能点 |
说明 |
| FR-10.4.1 |
脚本引擎 |
apps/discounts/script_engine.py,Python 子集沙箱执行(基于 RestrictedPython) |
| FR-10.4.2 |
输入契约 |
输入 = cart + customer + market + config;输出 = 修改后的 line_items 价格 |
| FR-10.4.3 |
版本管理 |
脚本版本化,部署需灰度(5%→50%→100%) |
| FR-10.4.4 |
性能上限 |
单次执行 < 100ms;超时降级至默认 PriceRule |
- R-10.1:折扣金额不可超过 line_item 小计;免运费仅作用于已选定 shipping_line
- R-10.2:折扣分摊按”价格比例”分配至各 line_item,写入
discount_allocations,便于按行退款
- R-10.3:折扣与已应用礼品卡的优先级:先礼品卡再折扣码、再自动折扣
- R-10.4:折扣码使用日志
discount_usage 表记录 code/rule/cart_snapshot/customer/order_id,用于审计
- R-10.5:自动折扣与折扣码冲突时,按 rule 配置选择”最大优惠” or “禁用”
PriceRule、DiscountCode、AutomaticDiscount、DiscountUsage、DiscountAllocation(写在 order_line_item 上)、DiscountScript、DiscountScriptVersion、DiscountScriptRun
| Method |
Path |
用途 |
| GET/POST |
/api/admin/price_rules.json |
PriceRule CRUD |
| GET/POST |
/api/admin/price_rules/{id}/discount_codes.json |
折扣码 CRUD |
| GET |
/api/admin/discount_codes/lookup.json?code=NEWYEAR |
折扣码查询 |
| POST |
/api/admin/discount_codes/batch.json |
批量生成 |
| GET/POST |
/api/admin/automatic_discounts.json |
自动折扣 CRUD |
mutation checkoutDiscountCodeApplyV2($discountCode: String!)
query discountByCode($code: String!) { discountByCode(code: $code) { ... } }
discounts/create、discounts/delete、discounts/redeem
- 字段完全对齐 Shopify
PriceRule + DiscountCode + AutomaticDiscount
- Discount Functions 用 RestrictedPython 复刻 Shopify Functions 思路(WASM/Rust 不引入)
- 不可叠加策略支持 Shopify 全部场景
- [ ] 折扣分摊后所有 line_item 折扣金额之和等于折扣总金额
- [ ] 折扣码达到使用上限后立即失效
- [ ] 折扣脚本性能 < 100ms,超时降级
对标 Shopify Email / SMS / Marketing Campaign / Audience / Automation,提供邮件 / 短信 / 站内信多渠道营销、活动效果归因、自动化工作流。
- 营销:选目标分群 → 设计邮件 → 设置发送时间 → 发送 → 监控效果
- 系统:弃单挽回 / 生日问候 / 库存到货提醒等场景化自动化触发
| FR 编号 |
功能点 |
说明 |
| FR-11.1.1 |
邮件/短信模板 |
可视化拖拽 sections + MJML 渲染 HTML + 文本版双发 |
| FR-11.1.2 |
模板变量 |
{{customer.first_name}}、{{order.number}} 等 Liquid-like 占位 |
| FR-11.1.3 |
邮件预览 |
测试邮箱 + 多客户真实预览 |
| FR-11.1.4 |
发件人配置 |
店铺自定义发件域名 + DKIM/SPF/DMARC 校验提示 |
| FR 编号 |
功能点 |
说明 |
| FR-11.2.1 |
单次活动 |
选目标 Segment + 选模板 + 投放渠道和时刻 |
| FR-11.2.2 |
退订管理 |
每封营销邮件含退订链接,自动维护 customer.accepts_marketing |
| FR-11.2.3 |
触达限流 |
单客户单日最多 N 封;硬弹退订永不发送 |
| FR-11.2.4 |
渠道配额 |
邮件用 SES / 阿里云 DM;短信用阿里云 / 腾讯云;账户配额耗尽降级或排队 |
| FR 编号 |
功能点 |
说明 |
| FR-11.3.1 |
触发器类型 |
弃单留存、新客户欢迎、订单完成、生日、库存到货、价格降低、加入心愿单 |
| FR-11.3.2 |
步骤编排 |
触发 → 等待 → 邮件/短信 → 条件判断 → 分支跳转 → 结束 |
| FR-11.3.3 |
进入与退出条件 |
客户中途完成转化自动退出弃单流;硬弹触发出流 |
| FR-11.3.4 |
多分支并发 |
同客户可同时进入多个自动化,但同流程不可重复进入 |
| FR 编号 |
功能点 |
说明 |
| FR-11.4.1 |
UTM 自动注入 |
邮件/短信链接自动注入 utm_medium=email&campaign=xxx |
| FR-11.4.2 |
归因窗口 |
投放 → 客户点击 → 7 天内下单记一笔归因 |
| FR-11.4.3 |
多触点归因 |
首次触点 / 末次触点 / 线性归因三种模型可切 |
- R-11.1:所有营销触达必须基于
accepts_marketing=True 客户;交易性邮件(订单确认、退款)不受此限制
- R-11.2:硬弹邮件地址自动加入
email_suppression 表永不重发;软弹 3 次后加入
- R-11.3:自动化工作流执行使用 Celery + 编排引擎(轻量状态机),单客户同一工作流不并发
- R-11.4:营销效果统计延迟 1 小时聚合,未触达实时告警
EmailTemplate / SmsTemplate / Campaign / CampaignSend(单客户单发送)/ Automation / AutomationStep / AutomationEnrollment / MarketingAttribution / EmailSuppression
| Method |
Path |
用途 |
| GET/POST |
/api/admin/marketing/campaigns.json |
活动 CRUD |
| POST |
/api/admin/marketing/campaigns/{id}/send.json |
立即/定时发送 |
| GET/POST |
/api/admin/automations.json |
自动化流程 CRUD |
| POST |
/api/admin/automations/{id}/enroll.json |
手工加入客户 |
| GET |
/api/admin/marketing/attribution.json |
归因报表 |
marketing/campaign_sent、marketing/email_delivered、marketing/email_opened、marketing/email_clicked
- Shopify Email + Shopify Audiences + Shopify Automation 三合一,对标其字段与触发器
- 自动化工作流节点设计基于 Shopify Flow 的 Trigger / Condition / Action 三段式
- 与外部 ESP(如 Mailchimp / Klaviyo / 阿里云 DM)可通过 webhook + API 实现对接
- [ ] 退订链接点击后立即更新客户档案,30 分内不再发送
- [ ] 硬弹地址永不重发
- [ ] 自动化工作流并发数稳定(同客户不重复触发)
对标 Shopify Analytics / Live View / Reports / Cohorts / LTV,提供实时业务看板、销售分析、客户行为分析、可自定义报表。
- 老板/CEO:每日看核心 KPI、Live View、经营趋势
- 营销:分析活动 ROI、分群表现
- 运营:分析品类、渠道、退货率
- 财务:导出对账与税务报表
| FR 编号 |
功能点 |
说明 |
| FR-12.1.1 |
今日会话/订单/销售额 |
秒级延迟(基于 Redis 计数器) |
| FR-12.1.2 |
地图分布 |
客户分布与下单热点(按国家/省/市) |
| FR-12.1.3 |
实时订单流 |
最新订单流式滚动 |
| FR 编号 |
功能点 |
说明 |
| FR-12.2.1 |
销售概览 |
总销售额、退款额、净销售额、订单数、客单价、转化率 |
| FR-12.2.2 |
按时段分析 |
时/日/周/月/季/年维度 |
| FR-12.2.3 |
品类 / 商品 TopN |
销售量、销售额、毛利、退货率 |
| FR-12.2.4 |
渠道分析 |
各 Channel 销售贡献与转化 |
| FR-12.2.5 |
折扣分析 |
各折扣码使用次数与核销金额、ROI |
| FR 编号 |
功能点 |
说明 |
| FR-12.3.1 |
同期群分析(Cohort) |
按首单月份分群,跟踪回访率与人均消费 |
| FR-12.3.2 |
RFM 模型 |
R/F/M 三维度评分,自动归类为”高价值”、”沉睡”、”流失”等 |
| FR-12.3.3 |
客户 LTV |
基于历史与留存算法预测 LTV |
| FR-12.3.4 |
复购分析 |
复购率、复购周期、跨品类复购 |
| FR 编号 |
功能点 |
说明 |
| FR-12.4.1 |
漏斗定义 |
访问 → 商品详情 → 加车 → 开始结账 → 完成下单 |
| FR-12.4.2 |
多维度过滤 |
按渠道、设备、地区、商品、客户分层 |
| FR 编号 |
功能点 |
说明 |
| FR-12.5.1 |
自定义列与过滤 |
维度 + 度量交叉,存为模板 |
| FR-12.5.2 |
调度与导出 |
报表定时邮件 + Excel/CSV 导出 |
- R-12.1:报表数据来自专用 ETL(每晚从 OLTP 同步至 OLAP,Postgres 可用 crosstab / 物化视图或独立 DuckDB)
- R-12.2:所有金额按订单时点币种与汇率折算
- R-12.3:退款与售后金额以负数计入销售维度
- R-12.4:实时看板允许 ±5% 误差(异步聚合),日报/月报必须 100% 精确
- 物化视图:
mv_order_daily、mv_customer_cohort、mv_product_sales_monthly
- 报表元数据:
Report / ReportColumn / ReportFilter / ReportSchedule、ReportSnapshot
- 实时计数器:Redis 自增键 + SETEX TTL
| Method |
Path |
用途 |
| GET |
/api/admin/analytics/live_view.json |
实时看板 |
| GET |
/api/admin/reports/sales_over_time.json |
销售概览 |
| GET |
/api/admin/reports/cohort.json |
同期群 |
| GET |
/api/admin/reports/custom/{id}.json |
自定义报表 |
| POST |
/api/admin/reports/export.json |
导出任务 |
- 完整覆盖 Shopify Analytics 五大块:Live View、Sales、Customer、Conversion、Reports
- 引入 RFM / Cohort / LTV 三种中国市场习惯的分析模型
- 自定义报表对标 Shopify Custom Reports
- [ ] 实时看板数据延迟 ≤ 5 秒
- [ ] 月报数据与财务对账误差 0
- [ ] 自定义报表可在 10s 内返回结果
对标 Shopify Online Store 2.0 的 sections + blocks + JSON templates + theme settings 架构,提供可视化拖拽的主题编辑器、模板文件系统和主题资源管理,让商家在不改代码前提下完整定制店铺外观。
- 主题开发者:通过本地开发工具链开发并打包
.zip 主题包
- 商家:上传主题 → 选择模板 → 在 sections 中添加/移动 blocks → 实时预览 → 发布
- 前端访客:访问店铺 → Django 模板引擎按 “Liquid-like” 渲染
主题目录结构(复刻 Shopify 2.0):
my-theme/
├── assets/ # CSS/JS/图片等静态资源
├── config/ # settings_schema.json + settings_data.json
├── layout/ # theme.liquid 主布局
├── locales/ # en.default.json / zh.json 多语言
├── sections/ # 可复用的 section(含 schema)
│ ├── header.liquid
│ ├── product-card.liquid
│ └── ...
├── snippets/ # 可复用片段
└── templates/
├── index.liquid # 首页
├── product.liquid / product.<suffix>.liquid
├── collection.liquid / collection.<suffix>.liquid
├── cart.liquid
├── page.liquid / page.<suffix>.liquid
├── blog.liquid
├── article.liquid
├── list-collections.liquid
├── 404.liquid
├── password.liquid
├── search.liquid
├── gift_card.liquid
├── customers/
│ ├── account.liquid
│ ├── login.liquid
│ ├── register.liquid
│ ├── order.liquid
│ ├── addresses.liquid
│ └── reset_password.liquid
└── *.json # 模板配置(持久化 section 顺序与 block 实例)
| FR 编号 |
功能点 |
说明 |
| FR-13.1.1 |
主题上传 |
支持 .zip 上传;解压校验目录结构必含 8 个固定目录 |
| FR-13.1.2 |
主题激活 |
同一店铺可有多个主题,但只有一个 active;切换前做”准发布预览”链接 |
| FR-13.1.3 |
主题预览 |
通过特殊 token 访问未激活主题 |
| FR-13.1.4 |
主题下载 |
当前主题可一键打包下载 |
| FR-13.1.5 |
主题版本 |
主题更新记录版本号、最后修改时间、修改者 |
| FR-13.1.6 |
市场主题库 |
内置若干模板供商家免费使用 |
| FR 编号 |
功能点 |
说明 |
| FR-13.2.1 |
Section schema |
JSON schema 声明:name、tag、class、settings、blocks、max_blocks、presets |
| FR-13.2.2 |
Section 类型 |
全局 section(如 header/footer)+ 模板 section(动态加入) |
| FR-13.2.3 |
Block 类型 |
section 内可重复挂载的小组件,如图片、轮播、富文本、视频 |
| FR-13.2.4 |
Block 实例化 |
每个 block instance 序列化到模板 JSON 文件中(settings + order) |
| FR-13.2.5 |
拖拽排序 |
商家在主题编辑器拖拽 section / block 实时调整顺序 |
| FR-13.2.6 |
Section settings |
单 section 全局配置,类型支持 text/range/select/radio/checkbox/image_picker/url/rich_text/color/font_picker |
| FR-13.2.7 |
Block settings |
在每个 block 实例上独立配置,schema 同 section settings |
| FR-13.2.8 |
Section group |
header / footer / aside 等不随模板变化的 section 集合 |
| FR 编号 |
功能点 |
说明 |
| FR-13.3.1 |
模板 JSON 持久化 |
资源(如 product)的某模板对应一份 JSON 文件,记录 sections 顺序+block 配置 |
| FR-13.3.2 |
资源专属模板 |
单商品可绑定自己的模板 JSON(覆盖默认 product.json) |
| FR-13.3.3 |
模板数量上限 |
单店铺每类资源最多 50 个模板 JSON |
| FR-13.3.4 |
默认模板 |
必须存在 default,否则该资源不可访问 |
| FR 编号 |
功能点 |
说明 |
| FR-13.4.1 |
settings_schema.json |
全局设置:店铺 logo、字体、配色、社交链接等 |
| FR-13.4.2 |
settings_data.json |
全局设置的回填值,分为 current + preset |
| FR-13.4.3 |
字体加载 |
仅允许主题预设字体子集,避免性能问题 |
| FR 编号 |
功能点 |
说明 |
| FR-13.5.1 |
Liquid 子集 |
实现 Liquid 关键 tag:{% for %}、{% if %}、{% assign %}、{% capture %}、{% include %}、{% section %}、{% render %}、{% schema %}、{% style %}、{% javascript %} |
| FR-13.5.2 |
对象注入 |
模板上下文中可访问 product / collection / cart / customer / shop / page / blog / article / search / template / request / linklists / settings / snippets 等 drop 对象 |
| FR-13.5.3 |
过滤器 |
价格 money、money_with_currency、date、truncate、escape 等 40+ 过滤器 |
| FR-13.5.4 |
安全沙箱 |
禁用 import/os/sys/subprocess;模板编译失败给前端兜底页 |
| FR-13.5.5 |
模板缓存 |
编译产物按 (theme_id, version, file_hash) 缓存至 Redis,请求时按 hash 命中 |
| FR 编号 |
功能点 |
说明 |
| FR-13.6.1 |
资源 CDN |
assets/ 资源上传 S3,URL 由 CDN 域名生成,自动带版本 hash |
| FR-13.6.2 |
图片处理 |
支持动态缩放/裁剪/webp 转码的 URL 参数 ?width=400&height=400&format=webp |
- R-13.1:schema 校验不通过的 section 不会被加载,且在主题编辑器中置灰;模板 JSON 必须能通过 schema 校验
- R-13.2:所有渲染基于”已发布主题 + 当前模板 JSON”,未发布预览主题需
?preview_token=xxx
- R-13.3:模板编译错误必须降级到”简化 error page”,绝不向访客暴露 500
- R-13.4:theme settings 的图片必须落到店铺的 CDN bucket,禁止外链图片
- R-13.5:Liquid 模板执行时长上限 500ms,超时降级到 cached HTML
Theme(name/version/status/active_at/preview_token)
ThemeAsset(path/type/content/checksum)
ThemeTemplate(template_type/handle/json_content)
ThemeSettings(theme_id + value JSON)
- 资源静态文件落对象存储
| Method |
Path |
用途 |
| GET/POST |
/api/admin/themes.json |
主题上传/列表 |
| PUT |
/api/admin/themes/{id}.json |
主题元数据更新 |
| POST |
/api/admin/themes/{id}/activate.json |
激活 |
| GET/PUT |
/api/admin/themes/{id}/assets.json |
资源操作 |
| POST |
/api/admin/themes/{id}/preview.json |
预览链接生成 |
对标 Shopify Pages / Blogs / Articles / Menus / Navigation,提供企业页面(关于我们/联系/政策)、博客内容、店铺导航菜单管理。
| FR 编号 |
功能点 |
说明 |
| FR-14.1 |
页面 CRUD |
标题、handle、富文本 body_html、模板后缀、SEO 元字段、作者、可见性(公开/私密/密码保护) |
| FR-14.2 |
博客 CRUD |
一个店铺可多个 blog;每个 blog 单独 feed RSS |
| FR-14.3 |
文章 CRUD |
标题、handle、body_html、作者、标签、封面、发布时间、状态(draft/published)、SEO 元字段 |
| FR-14.4 |
评论 |
可选开启;审核模式(先审后显/先显后审/关闭);防 Spam |
| FR-14.5 |
菜单(Menu / Linklist) |
导航菜单层级最多 3 级;菜单项可指向 page/collection/product/blog/url 手动填 |
| FR-14.6 |
主菜单 / Footer 菜单 / Mobile 菜单 |
内置固定 handle(main-menu / footer / mobile),主题直接引用 |
| FR-14.7 |
重定向 |
任意路径走 redirect 表(详见 SEO) |
- R-14.1:page/article 的 handle 在店铺内唯一;修改保留 301 redirect
- R-14.2:博客发布文章采用 future-dated 调度(Celery Beat 按时发布)
- R-14.3:私密页面访问需密码或登录
Page / Blog / Article / ArticleComment / Menu / MenuItem(自引用实现层级)
| Method |
Path |
用途 |
| GET/POST |
/api/admin/pages.json、/api/admin/blogs.json、/api/admin/blogs/{id}/articles.json |
CRUD |
| GET/POST |
/api/admin/menus/{id}/items.json |
菜单项 |
对标 Shopify 的内置 SEO(meta 标签、URL handle、canonical、redirect、sitemap、robots.txt)与多域名绑定能力。
| FR 编号 |
功能点 |
说明 |
| FR-15.1 |
每个 SEO 对象 |
商品/集合/页面/文章均含 meta_title、meta_description、og_image、handle |
| FR-15.2 |
自动生成 |
模板字段留空时根据规则回退(如 product.meta_title = title) |
| FR-15.3 |
canonical URL |
商品/集合/分页 canonical 自动生成;商品多变体页面对应同一 canonical |
| FR-15.4 |
sitemap.xml |
自动生成 index + per-type sitemap;按 50000 条/50MB 切分;每日刷新缓存 |
| FR-15.5 |
robots.txt |
可在后台直接编辑,覆盖默认 |
| FR-15.6 |
redirect 表 |
任意路径 → 目标路径 + 状态码(301/302),优先级匹配 |
| FR-15.7 |
多域名 |
一个店铺可绑多个域名(主域 + 别名),所有别名 301 到主域;支持二级路径子站 |
| FR-15.8 |
HTTPS |
强制 HTTPS;自动管理 Let’s Encrypt 证书(开发期)或对接 ACME 服务 |
| FR-15.9 |
hreflang 多语言 |
与多语言标识符配合输出 hreflang 标签 |
| FR-15.10 |
structured data |
自动输出 Product / BreadcrumbList / Article / Organization schema.org JSON-LD |
| FR-15.11 |
搜索引擎抓取日志 |
简版爬虫日志(按 UA),用于 SEO 诊断 |
SeoTemplate(按类型组合模板如 {{product.title}} - {{shop.name}})、Redirect(from_path/to_path/status/priority)、DomainBinding
对标 Shopify Sales Channels(Online Store、POS、Manual、Facebook/Instagram、Google、TikTok、Wholesale 等),抽象统一的渠道适配层,让同一商品池与订单池服务多渠道。
| FR 编号 |
功能点 |
说明 |
| FR-16.1 |
渠道抽象 |
Channel 含 id/name/type/status;所有订单、商品发布都挂 channel_id |
| FR-16.2 |
Online Store 渠道 |
默认存在的渠道;商品可见性默认开 |
| FR-16.3 |
POS 渠道 |
实体店收银;订单本地缓存离线创建,联网同步;支持会员、礼品卡、扫码 |
| FR-16.4 |
Manual 渠道 |
客服代客下单或外部销售渠道登记订单的来源 |
| FR-16.5 |
Facebook/Instagram/TikTok/Google |
通过适配器将商品发布到对应平台(目录同步)+ 订单回流 |
| FR-16.6 |
集成开放 |
通过 apps/channels/adapters/ 抽象,支持自定义渠道 |
| FR-16.7 |
商品渠道发布状态 |
单商品可启/停某些渠道;价格/库存可按渠道覆盖 |
| FR-16.8 |
多渠道对账 |
平台侧费用/退货对账按渠道出表 |
- R-16.1:每个订单必有 channel_id;缺省 = Online Store
- R-16.2:渠道适配失败不应阻塞主订单流程,回退到
manual,留日志
- R-16.3:产品目录与外部平台同步频率可配置(默认 1 小时)
Channel / ChannelProduct(商品配置覆盖)/ ChannelAdapter / ChannelSyncLog
| FR 编号 |
功能点 |
说明 |
| FR-17.1.1 |
员工(Staff Account) |
每个 shop 下多员工账号,关联 Django auth.User,归属 shop |
| FR-17.1.2 |
角色与权限 |
预设角色:Owner / Admin / Manager / Staff / Developer;可自定义权限集 |
| FR-17.1.3 |
权限粒度 |
模块级(如订单读/写/退款)+ 对象级(如仅看到自己客服的客户) |
| FR-17.1.4 |
二次验证 TOTP |
关键操作(退款、删除商品、改支付凭证)强制 TOTP |
| FR-17.1.5 |
操作日志 |
所有改动写 audit_log(用户/IP/操作/前后值) |
| FR-17.1.6 |
API Token |
每员工可生成 Access Token + scope + 过期;轮转支持 |
| FR 编号 |
功能点 |
说明 |
| FR-17.2.1 |
内容多语言 |
商品标题/描述、页面、文章、邮件模板均多语言;i18n 用 django-modeltranslation |
| FR-17.2.2 |
翻译工作流 |
自动翻译(对接云翻译 API)+ 人工润色状态机 |
| FR-17.2.3 |
Markets 概念 |
一个 Market = 区域 + 默认币种 + 域名/子目录 + 税率 + 价格表 |
| FR-17.2.4 |
多币种定价 |
价格可按 Market 覆盖;未覆盖走基础价 × 汇率 |
| FR-17.2.5 |
自动货币识别 |
按 IP / 浏览器语言识别市场并切换币种 |
| FR-17.2.6 |
汇率源 |
每日 from ECB / 中央银行;人工可锁定汇率 |
| FR-17.2.7 |
Rounding 规则 |
商家可设置每个币种圆整规则(如 JPY 取整百) |
| FR 编号 |
功能点 |
说明 |
| FR-17.3.1 |
税率配置 |
按国家+省+邮编+商品税类配置;支持免税/含税切换 |
| FR-17.3.2 |
自动计算 |
结账阶段 → 地址 → 税率 → 行级税款 |
| FR-17.3.3 |
税务引擎 |
内嵌简单引擎 / 接入外部(Avalara、TaxJar) |
| FR-17.3.4 |
免税客户 |
B2B 客户可设免税 ID,下单 0 税 |
| FR-17.3.5 |
税务报告 |
按时段按地区导出销售税报表(增值税/消费税) |
| FR-17.3.6 |
关税与 DDP |
对标 Shopify Markets Duties,支持 DDP(送达付税)选项 |
- R-17.1:所有面向客户的字段变更走”翻译工作流”流程;非默认语言缺省回退默认语言
- R-17.2:税率以结算时点为准;订单 line_item tax_lines 快照锁定
- R-17.3:员工删除/降权需 Owner 同意审签
- R-17.4:API Token 不可读取 owner 与 staff 完整列表,避免越权
- 所有业务表继承
core.models.TimeStampedOwnerModel,包含统一字段:id (BigAutoField)、shop_id (FK)、created_at、updated_at、deleted_at(软删除,默认 NULL)
- 金额一律存 整数最小货币单位(如人民币:分);展示时按
Shop.currency.decimal_places 格式化
- 所有”国际化名称”字段使用
django-modeltranslation 注册翻译,DB 多列 name_en / name_zh 自动生成
- 所有”对外 ID”用
gid://shop/<Type>/<numeric_id> 格式(对标 Shopify GraphQL Global ID),Admin/Storefront API 输出统一转 base64
- 多租户预留:所有表带
shop_id,单店铺部署写在配置 DEFAULT_SHOP_ID
- 使用枚举:枚举值定义在
core/enums.py,模型字段统一用 django-enumchoice 或自定义 CharField + choices
| 字段 |
类型 |
说明 |
| id |
BigAutoField |
主键 |
| name |
CharField(120) |
店铺名 |
| slug |
SlugField |
URL 友好标识,店铺内部使用 |
| email |
EmailField |
主联系邮箱 |
| default_currency |
CharField(3) |
默认币种 ISO 4217 |
| timezone |
CharField(40) |
店铺时区 |
| weight_unit |
CharField(8) |
g/kg/lb/oz |
| domain |
CharField(255) |
主域名 |
| is_password_protected |
BooleanField |
全店密码保护 |
| password |
CharField(60) |
全店访问密码(哈希) |
| money_format |
CharField(60) |
Liquid-like 价格显示模板 |
| tax_included |
BooleanField |
商品价是否含税 |
| settings |
JSONField |
其他店铺级配置 |
| created_at / updated_at |
DateTimeField |
时间戳 |
| 字段 |
类型 |
说明 |
| shop |
FK(Shop) |
归属店铺 |
| name |
CharField(120) |
库位名 |
| address1/address2/city/province/zip/country |
CharField |
地址 |
| active |
BooleanField |
是否活跃 |
| fulfills |
BooleanField |
是否对外发货 |
| location_type |
CharField |
physical / fulfillment_service |
| legacy |
BooleanField |
历史数据,只读不删 |
StaffAccount.user FK → auth.User;shop FK;role FK
StaffRole 预设记录:owner/admin/manager/staff/developer
Permission 表 (role_id, module, action, scope):action ∈ read/create/update/delete/refund;scope ∈ all/owned/warehouse
| 字段 |
类型 |
说明 |
| shop |
FK(Shop) |
|
| title |
CharField(255) |
模板翻译 |
| body_html |
TextField |
富文本 |
| vendor |
CharField(100) |
厂商 |
| product_type |
CharField(100) |
商品类型 |
| handle |
SlugField |
店铺内唯一 |
| status |
CharField |
draft/active/archived |
| tags |
ArrayField(CharField) |
PG array 或多对多 |
| template_suffix |
CharField(60) |
模板后缀 |
| options |
JSONField |
[{name:'Color', values:[...]}, ...],最多 3 个 |
| published_at |
DateTimeField |
上架时间 |
| published_scope |
CharField |
web/global |
| search_vector |
SearchVectorField |
GIN 索引 |
| metafields |
GenericRelation(Metafield) |
反向 |
| created_at / updated_at / deleted_at |
|
|
索引:(shop_id, handle) unique、(shop_id, status)、search_vector GIN
| 字段 |
类型 |
说明 |
| product |
FK(Product, related_name=’variants’) |
|
| title |
CharField(255) |
|
| sku |
CharField(64) |
店铺内唯一可配 |
| barcode |
CharField(64) |
EAN/UPC/GTIN |
| price |
BigIntegerField |
不含税价(分) |
| compare_at_price |
BigIntegerField |
划线价 |
| cost |
BigIntegerField |
成本(仅后台) |
| taxable |
BooleanField |
|
| tax_code |
CharField(64) |
|
| weight |
DecimalField |
|
| weight_unit |
CharField(8) |
|
| requires_shipping |
BooleanField |
|
| inventory_policy |
CharField |
deny/continue/oversell |
| inventory_management |
CharField |
shopify → ‘system’ |
| image |
FK(Image) |
主图 |
| position |
IntegerField |
显示顺序 |
| option1/option2/option3 |
CharField |
与父商品 options 顺序对应 |
| metafields |
GenericRelation(Metafield) |
|
索引:(shop_id, sku)、(product_id, position)
shop, product(FK), variant(FK nullable), src(url), alt, width, height, position ;图片实体存 S3
shop, title, body_html, handle, sort_order(char Enum: manual/best_selling/...), disjunctive(bool: True=OR, False=AND), rules(JSONArray of {column, relation, condition}), template_suffix, published_at, image(FK)
collection(FK), product(FK), position(Integer),索引 (collection_id, product_id) unique, (collection_id, position)
Metafield: shop, owner_type, owner_id, namespace, key, value(JSON), type(CharField Enum), description, is_public(Boolean)
Metaobject: shop, type(CharField), handle, fields(JSONField: {name: value}), display_name
MetaobjectDefinition: shop, name, type, field_definitions(JSONArray)
| 字段 |
类型 |
说明 |
| variant |
FK(ProductVariant) |
|
| location |
FK(Location) |
|
| available |
IntegerField |
可售 |
| committed |
IntegerField |
预留/已售未发 |
| incoming |
IntegerField |
在途 |
| safety_stock |
IntegerField |
安全库存阈值 |
唯一索引 (variant_id, location_id)
id, variant(FK), location(FK), delta(Integer), previous_available, after_available, reason(Enum: correction/cycle_count/received/cancelled_order/return), note, staff(FK nullable), created_at
不可变事件表:event_type(Enum), variant_id, location_id, delta, source(refund_id/order_id/...), created_at
FulfillmentOrder: order(FK), location(FK), status(unfulfilled/in_progress/on_hold/cancelled), assigned_location.location, line_items(JSON of order_line_item ids + quantity), fulfill_at, deadline
Fulfillment: fulfillment_order(FK), status(open/success/cancelled/error), tracking_company, tracking_number, tracking_url, receipt(JSON), notify_customer, created_at
Cart: shop, customer(FK nullable), token(UUID UNIQUE), note, attributes(JSON), created_at, updated_at, expires_at
CartLine: cart(FK), variant(FK), quantity, properties(JSON), attributes(JSON);唯一索引 (cart_id, variant_id)
shop, customer(FK), cart(FK), token(UUID UNIQUE),
status(Enum: in_progress/completed/expired),
shipping_address(JSON), billing_address(JSON),
shipping_rate(JSON snapshot), tax_lines(JSON),
discount_codes(Array), gift_cards(Array),
total_price, total_tax, total_shipping, total_discount,
payment_provider(CharField),
expires_at, completed_at, abandoned_at
shop, checkout_session(FK), email, line_items_snapshot(JSON), created_at, abandoned_at, recovery_email_sent_at
| 字段 |
类型 |
说明 |
| shop |
FK |
|
| order_number |
CharField(20) |
可读编号 |
| name |
CharField(60) |
显示名 #1001 |
| customer |
FK(Customer) |
可为 NULL(脱敏) |
| email / phone |
CharField |
|
| financial_status |
CharField |
pending/authorized/paid/partially_paid/refunded/partially_refunded/voided |
| fulfillment_status |
CharField |
null/unfulfilled/partial/fulfilled/restocked |
| status |
CharField |
open/closed/cancelled |
| currency |
CharField(3) |
|
| subtotal_price |
BigIntegerField |
|
| total_shipping |
BigIntegerField |
|
| total_tax |
BigIntegerField |
|
| total_discounts |
BigIntegerField |
|
| total_price |
BigIntegerField |
|
| total_paid |
BigIntegerField |
|
| taxes_included |
BooleanField |
|
| cancel_reason |
CharField |
|
| cancelled_at |
DateTimeField |
|
| closed_at |
DateTimeField |
|
| processed_at |
DateTimeField |
|
| note |
TextField |
|
| tags |
ArrayField |
|
| attributes |
JSONField |
|
| source_name |
CharField(40) |
web/pos/api/manual |
| shipping_address / billing_address |
JSONField |
|
| channel |
FK(Channel) |
|
| created_at / updated_at |
|
|
按月分区 pg_partman:orders_YYYY_MM
order(FK), variant_id_snapshot, sku_snapshot, title, variant_title, quantity, price(price_each), total_discount, tax_lines(JSON), discount_allocations(JSON), requires_shipping, taxable, fulfillment_status, fulfillable_quantity, properties(JSON), position
- ShippingLine:
order(FK), title, code, price, tax_lines(JSON), carrier_identifier, requested_fulfillment_service_id
- TaxLine:
order(FK), price, rate, title, channel
OrderAdjustment: order(FK), amount, kind(order_edit/discount/refund_diff), note
Refund: order(FK), created_at, note, restock, amount, transactions(GenericRelation), refund_line_items
RefundLineItem: refund(FK), line_item(FK), quantity, restock_type, subtotal, total_tax, subtotal_set
Return: order(FK), status(requested/approved/received/cancelled), line_items(JSON), restocking_fee
DraftOrder: shop, customer(FK nullable), line_items, shipping_address, billing_address, total, invoice_url, status(open/invoice_sent/completed), completed_at
shop, order(FK nullable), checkout_session(FK nullable), amount, currency, status(None/requires_payment_method/requires_confirmation/requires_action/processing/requires_capture/canceled/succeeded), provider, provider_data(JSON), metadata(JSON), created_at
payment_intent(FK), kind(Enum: authorization/capture/sale/void/refund), gateway, amount, currency, status(success/pending/failure/error), provider_transaction_id, failure_code, failure_message, response_raw(JSON), masked_pan, created_at
shop, code(CharField UNIQUE), initial_value, balance, currency, customer_id(FK nullable), disabled_at, expires_on, note, template_suffix
gift_card(FK), order(FK nullable), amount, action(Enum: debit/credit/expire), created_at
shop, first_name, last_name, email, phone, accepts_marketing, accepts_marketing_updated_at, marketing_opt_in_level, note, tags, last_order_at, orders_count, total_spent,verified_email, state(enabled/disabled/invited/declined), tax_exempt, tax_exemptions(Array), currency, default_address(FK nullable), created_at, updated_at, deleted_at(软删除时 email 改为 deleted_<id>@removed.local)
唯一索引 (shop_id, email);(shop_id, phone) 软唯一
customer(FK), first_name, last_name, company, address1, address2, city, province, province_code, zip, country, country_code, phone, default(Boolean)
CustomerSegment: shop, name, kind(static/dynamic/saved_search), definition(JSON rule expression), last_evaluated_at
CustomerSegmentMember: segment(FK), customer(FK), joined_at
- 动态分群由 Celery Beat 每日重算
MembershipTier: shop, name, threshold_amount, multiplier(Decimal), benefits(JSON), active
PointLedger: customer(FK), action(earn/spend/expire/adjust), delta, balance_after, expires_on, ref(order_id/coupon_id), note, created_at
shop, title, target_type(line_item/shipping_line), target_selection(all/entitled),
allocation_method(each/across), value_type(fixed_amount/percentage),
value, once_per_customer(Boolean), usage_limit(Integer nullable),
once_per_order(Boolean), starts_at, ends_at, prerequisite_subtotal_range,
prerequisite_quantity, prerequisite_to_entitlement_quantity_ratio(JSON),
entitled_product_ids, entitled_collection_ids, entitled_country_ids,
prerequisite_product_ids, prerequisite_collection_ids, prerequisite_customer_segment_ids,
prerequisite_to_entitlement_purchase, allocation_method, market_ids
price_rule(FK), code(CharField shop_unique), usage_count(Integer default 0), usage_limit(Integer nullable), customer_id(FK nullable for bound code), created_at, expires_at(nullable)
AutomaticDiscount: price_rule(FK), title, status(active/expired/scheduled), starts_at, ends_at
DiscountUsage: discount_code(FK nullable), automatic_discount(FK nullable), customer(FK nullable), order(FK nullable), used_at
DiscountScript: title, type(Enum: discount/shipping/payment), source_code, version, status(draft/active/archived), active_version
DiscountScriptVersion: script(FK), version, source_code, published_by, published_at, gray_percent
shop, name, version, status(unpublished/published/deleted), active_at, preview_token, processing, created_at
theme(FK), key(CharField, e.g. 'templates/product.liquid'), content(Text), checksum(CharField), attachment(URL for binary), content_type, size, updated_at,索引 (theme_id, key) unique
theme(FK), template_type(Enum: product/collection/page/...), handle, json_content(JSON), published_scope(web/global), created_at, updated_at
theme(FK), data(JSON) 单条记录
Page: shop, title, handle, body_html, template_suffix, author(FK), published_at, published_scope,seo_title, seo_description, admin_graphql_api_id, visible(public/private/password), password
Blog: shop, title, handle, template_suffix, feed_url, commentable
Article: blog(FK), title, handle, body_html, author(FK), tags(Array), image(FK), published_at, status, summary, seo_title, seo_description
ArticleComment: article(FK), author, email, body, status(unapproved/published/spam), ip, user_agent, created_at
Menu: shop, handle, title,内置 handle main-menu, footer, mobile
MenuItem: menu(FK), parent(FK self nullable), title, link_type(page/collection/product/blog/url/manual), link_value, position
Channel: shop, name, type(online_store/pos/manual/facebook/instagram/google/tiktok/wholesale/custom), status, configuration(JSON), created_at
ChannelProduct: channel(FK), product(FK), published(Boolean), price_override(BigInteger nullable), inventory_override(Integer nullable), external_id
Redirect: shop, path(CharField), target(CharField), status(301/302), priority(Integer)
SeoTemplate: shop, content_type(product/collection/article/page), title_template, description_template
DomainBinding: shop, domain(CharField unique), primary(Boolean), ssl_enabled, ssl_expires_at, subdirectory_prefix
shop, topic(CharField), address(URL), format(json/xml), api_version, fields(Array), metafield_namespaces(Array), secret, created_at, status(active/disabled)
webhook_subscription(FK), payload(Text), headers(JSON), status(success/failure/queued), attempts(Integer), last_attempt_at, response_code, response_body
shop, type(CharField Enum: order_confirmation/order_cancelled/refund_issued/...), channel(email/sms), subject, body_html, body_text, active
Shop ── Location
Shop ── Product ── ProductVariant ── InventoryLevel ── Location
Shop ── Collection ──< CollectionProduct >── Product
Shop ── Customer ── CustomerAddress
Shop ── Order ──< OrderLineItem >── ProductVariant (snapshot)
Order ── Customer
Order ──< FulfillmentOrder ──< Fulfillment
Order ──< Refund ──< RefundLineItem >── OrderLineItem
Order ──< PaymentIntent ──< PaymentTransaction
Shop ── PriceRule ──< DiscountCode ──< DiscountUsage >── Order
Shop ── Theme ──< ThemeAsset ; Theme ──< ThemeTemplate
Shop ── Page / Blog ──< Article
Shop ──< Channel ──< ChannelProduct >── Product
Shop ──< Menu ──< MenuItem
详细 Model 代码生成另出《Django 模型实现规范》(v1.0 落地版本)。
本系统开放三套对外接口,对标 Shopify:
| API |
路径前缀 |
用途 |
鉴权 |
| Admin REST API |
/api/admin/*.json |
后台与 ERP/WMS/CRM 集成 |
OAuth2 Access Token / API Token |
| Admin GraphQL API |
/api/admin/graphql |
富查询场景(strawberry) |
同上 |
| Storefront API |
/api/{year}-{month}/graphql.json |
商城前端 / Headless 客户端 |
公共 Storefront Token(Public) |
| Webhook |
商家自定义 URL |
系统主动推送 |
HMAC SHA256 签名 |
| Partner / App API |
/api/partner/* |
应用市场适配(预留) |
OAuth2 |
- API 版本以
YYYY-MM 命名(如 2026-07),写在 URL 或 Header X-API-Version
- 每年发布 4 个稳定版本;旧版本至少保留 12 个月
- 弃用字段在响应中标
"deprecated": true,并在响应头 X-Shopify-API-Deprecated-Reason 解释
- 列表默认每页 50 条,最大 250 条;分页使用
page_info cursor 令牌
- 创建/更新接口要求
Content-Type: application/json
- 所有时间字段 UTC ISO 8601 字符串;金额按各模型说明字段类型在响应中输出
{amount, currency_code} 结构对象
- 错误响应统一结构:
{
"errors": {
"title": "Resource Not Found",
"code": "NOT_FOUND",
"message": "Product#gid://shop/Product/999 not found",
"status": 404
}
}
- Admin API:每 App 40 req/s(leaky bucket);超限 HTTP 429 +
Retry-After
- Storefront API:每 Token 100 req/s
- 写操作(POST/PUT/DELETE)额外每 5 秒 2 次/资源
- Burst:最多 2× 平均速率
- 写操作支持请求头
Idempotency-Key: <uuid>,5 分钟内同 key 重复请求复用原响应
- 幂等键记录表
IdempotencyRecord(key, response, created_at)
下表仅列核心资源(细分 fields/relations 见 API 详设文档):
| 资源 |
路径 |
主要操作 |
| Shop |
/api/admin/shop.json |
GET |
| Location |
/api/admin/locations.json |
GET/POST/PUT/DELETE |
| Product |
/api/admin/products.json |
GET/POST/PUT/DELETE |
| ProductVariant |
/api/admin/variants/{id}.json |
GET/POST/PUT |
| Collection |
/api/admin/custom_collections.json、/api/admin/smart_collections.json |
GET/POST/PUT/DELETE |
| Collect |
/api/admin/collects.json |
GET/POST/DELETE(关联表) |
| InventoryLevel |
/api/admin/inventory_levels.json |
GET/POST(set/adjust/connect) |
| InventoryAdjustment |
/api/admin/inventory_adjustments.json |
GET |
| FulfillmentOrder |
/api/admin/fulfillment_orders.json |
GET/POST(cancel/hold/move) |
| Fulfillment |
/api/admin/fulfillments.json |
GET/POST/PUT |
| FulfillmentEvent |
/api/admin/fulfillment_events.json |
GET/POST |
| Order |
/api/admin/orders.json |
GET/POST/PUT/DELETE |
| OrderRisk |
/api/admin/orders/{id}/risks.json |
GET/POST/PUT |
| Refund |
/api/admin/orders/{id}/refunds.json |
GET/POST |
| Return |
/api/admin/returns.json |
GET/POST/PUT |
| DraftOrder |
/api/admin/draft_orders.json |
GET/POST/PUT/DELETE |
| Transaction |
/api/admin/orders/{id}/transactions.json |
GET/POST |
| GiftCard |
/api/admin/gift_cards.json |
GET/POST/PUT |
| Customer |
/api/admin/customers.json |
GET/POST/PUT/DELETE |
| CustomerAddress |
/api/admin/customers/{id}/addresses.json |
GET/POST/PUT/DELETE |
| CustomerSavedSearch |
/api/admin/customer_saved_searches.json |
GET/POST/PUT/DELETE |
| CustomerSegment |
/api/admin/customer_segments.json |
GET/POST/PUT/DELETE |
| PriceRule |
/api/admin/price_rules.json |
GET/POST/PUT |
| DiscountCode |
/api/admin/price_rules/{id}/discount_codes.json |
GET/POST/PUT/DELETE |
| AutomaticDiscount |
/api/admin/automatic_discounts.json |
GET/POST/PUT |
| MarketingCampaign |
/api/admin/marketing/campaigns.json |
GET/POST |
| Automation |
/api/admin/automations.json |
GET/POST |
| Page |
/api/admin/pages.json |
GET/POST/PUT/DELETE |
| Blog / Article |
/api/admin/blogs.json、/api/admin/blogs/{id}/articles.json |
GET/POST/PUT/DELETE |
| Menu / MenuItem |
/api/admin/menus.json、/api/admin/menus/{id}/items.json |
GET/POST/PUT |
| Theme / Asset |
/api/admin/themes.json、/api/admin/themes/{id}/assets.json |
GET/POST/PUT/DELETE |
| Metafield |
/api/admin/{resource}/{id}/metafields.json |
GET/POST/PUT/DELETE |
| Metaobject |
/api/admin/metaobjects.json |
GET/POST/PUT/DELETE |
| Webhook |
/api/admin/webhooks.json |
GET/POST/PUT/DELETE |
| Redirect |
/api/admin/redirects.json |
GET/POST/PUT/DELETE |
| Domain |
/api/admin/domains.json |
GET/POST/PUT |
| Report |
/api/admin/reports.json、/api/admin/analytics/*.json |
GET/POST |
type Query {
shop: Shop!
productByHandle(handle: String!): Product
product(id: ID!): Product
products(first: Int, after: String, query: String, sortKey: ProductSortKeys, reverse: Boolean): ProductConnection!
collectionByHandle(handle: String!): Collection
collection(id: ID!): Collection
collections(first: Int, after: String): CollectionConnection!
node(id: ID!): Node
nodes(ids: [ID!]!): [Node]!
cart(id: ID!): Cart
customer: Customer
pageByHandle(handle: String!): Page
blogByHandle(handle: String!): Blog
articleByHandle(blogHandle: String!, articleHandle: String!): Article
search(query: String!, first: Int, after: String): SearchResultConnection!
publicMetafields(identifiers: [MetafieldIdentifier!], ownerType: String): [Metafield]
}
type Mutation {
cartCreate(input: CartCreateInput!): CartCreatePayload
cartLinesAdd(cartId: ID!, lines: [CartLineInput!]!): CartLinesAddPayload
cartLinesUpdate(cartId: ID!, lines: [CartLineUpdateInput!]!): CartLinesUpdatePayload
cartLinesRemove(cartId: ID!, lineIds: [ID!]!): CartLinesRemovePayload
cartDiscountCodesUpdate(cartId: ID!, discountCodes: [String!]): CartDiscountCodesUpdatePayload
cartGiftCardApply ...)
cartBuyerIdentityUpdate(...)
checkoutCreate(input: CheckoutCreateInput!): CheckoutCreatePayload
checkoutShippingAddressUpdateV2(...)
checkoutShippingLineUpdate(...)
checkoutDiscountCodeApplyV2(...)
checkoutEmailUpdate(...)
checkoutCompleteWithCreditCardV2(...)
checkoutCompleteWithTokenPayment(...)
customerAccessTokenCreate(input: CustomerAccessTokenCreateInput!): ...
customerCreate(input: CustomerCreateInput!): ...
customerUpdate(input: CustomerUpdateInput!): ...
customerAddressCreate/Update/Delete(...)
customerRecover/Reset/Activate(...)
}
Product:title handle description featuredImage variants(first:Int) options priceRange metafields
ProductVariant:id sku title priceV2 {amount currencyCode} compareAtPriceV2 availableForSale selectedOptions image weight
Collection:title handle description image products(first,after,filters:ProductFilters)
Cart:id totalQuantity cost{subtotalAmount totalAmount} lines(first){edges{node{id quantity merchandise{…on ProductVariant{id}} cost{…}}}}
Checkout:id ready webUrl lineItemsShippingAddress shippingLine taxLines totalPriceV2 appliedGiftCards discountApplications
Customer:id displayName email firstName lastName defaultAddress orders(first){edges}
POST /api/admin/webhooks.json:
{ "webhook": { "topic": "orders/create", "address": "https://erp.demo/hook/orders", "format": "json" } }
- HMAC-SHA256 请求头:
X-TeleAgent-Signature: sha256=<hex> + X-TeleAgent-Topic + X-TeleAgent-Hmac-Sha256
- 推送为 HTTP POST,body 为 JSON
- 失败重试:指数退避(10s/1m/10m/1h/3h/12h/24h/48h),共 8 次;超过 24h 仍失败标记 disabled 并发邮件告警
- 重放:商家可在 Admin API 触发
POST /webhooks/{id}/replay 手动重推最近 30 天任意事件
products/create|update|delete
collections/create|update|delete
inventory_levels/update、inventory_items/update
carts/create|update
checkouts/create|update|delete
abandoned_checkouts/create
orders/create|updated|paid|cancelled|fulfilled|partially_fulfilled|delete
orders/edited、transactions/create
refunds/create
draft_orders/create|update|delete
fulfillment_orders/create|fulfilled|cancelled
fulfillments/create|update
customers/create|update|delete|disable|enable|merge
discounts/create|delete|redeem
gift_cards/create|update
payment_intent/payment_authorized|payment_captured|payment_failed
themes/publish、themes/update
marketing/campaign_sent|email_delivered|email_opened|email_clicked
reports/export_completed
app/uninstalled(OAuth 应用卸载)
OAuth2 流程(用于第三方集成):
GET /admin/oauth/authorize?client_id=XXX&scope=read_products,write_orders&redirect_uri=...
↓ 商家同意
GET /admin/oauth/redirect?code=AAAA&hmac=BBB&shop=xxx
POST /admin/oauth/access_token {client_id, client_secret, code}
↓
{ access_token, scope }
API Token 流程(员工自建):
- 在 Admin 后台生成 Token,绑定 ShopStaff;可指定 scope 与过期时间
- 请求头
X-TeleAgent-Access-Token: <token>
- 权限校验:scope 必须覆盖资源(
read_products、write_orders 等)
- 每个 Theme / Channel 生成一个 Public Storefront Token
- 请求头
X-TeleAgent-Storefront-Access-Token: <public_token>
- Public Token 不可读 Admin 资源,只能读已发布商品 + 创建购物车/结账
- 后台可禁用某 Token,30 秒内全球生效(Redis 失效广播)
| Scope |
含义 |
read_products / write_products |
商品/变体/集合 |
read_inventory / write_inventory |
库存 |
read_orders / write_orders |
订单 |
read_customers / write_customers |
客户 |
read_discounts / write_discounts |
折扣 |
read_draft_orders / write_draft_orders |
草稿订单 |
read_locations |
库位 |
read_fulfillments / write_fulfillments |
履约 |
read_marketing_events / write_marketing_events |
营销 |
read_themes / write_themes |
主题 |
read_content / write_content |
页面博客 |
read_analytics |
分析只读 |
read_price_rules / write_price_rules |
折扣规则 |
read_gift_cards / write_gift_cards |
礼品卡 |
- Admin REST 通过
drf-spectacular 自动生成 OpenAPI 3.0 文档,访问 /api/admin/openapi.json、/api/admin/docs/
- GraphQL 通过
strawberry-django 输出 schema,访问 /api/admin/graphql/schema.graphql
| 指标 |
目标 |
| 首页(10万 SKU 库)TTFB |
p95 ≤ 200ms |
| 商品详情页 TTFB |
p95 ≤ 250ms(含 Liquid 渲染) |
| 集合页带过滤器 TTFB |
p95 ≤ 400ms |
| 加购物车(单次) |
p95 ≤ 150ms |
| 结账页生成 |
p95 ≤ 800ms |
| Admin 商品列表 50 行 |
p95 ≤ 500ms |
| Admin 订单详情(含交易/履约) |
p95 ≤ 600ms |
| API Webhook 推送延迟 |
p95 ≤ 1s |
| 主题 Liquid 模板编译缓存命中后渲染 |
p95 ≤ 300ms |
| 单实例 QPS(4C8G) |
≥ 500 商品/集合类只读 |
- 可用性 SLA 99.9% / 月(电商旺季 99.95%);数据库主从 + Read replica;多 AZ 部署
- 读扩展:商品/集合读流量 100% 走 Read replica,写流量走主库
- 写扩展:订单写高峰按
shop_id 分片(Phase 3 引入),第一阶段单库分区表
- 水平扩展:Web + Celery 无状态、可水平扩;Redis Cluster;对象存储天然多副本
- 缓存策略:商品详情(10 分钟 + 主动失效)+ 集合列表(5 分钟)+ 主题渲染(编译缓存 + 内容 hash)+ 用户 session
- 降级预案:搜索服务不可用 → 降级到 PG like 搜索;推荐服务不可用 → 降级到时序热门;支付网关熔断 → 暂用其他网关
- 熔断:所有外部网关(支付、物流、短信)走
circuitbreaker 包
- 传输:全站 HSTS + TLS 1.3;API 仅 HTTPS
- 存储:API Key 用 Fernet 加密;密码 BCrypt;DB 字段级加密敏感信息
- CSRF:DRF SessionAuthentication + SameSite=Strict;Admin 表单 {% csrf_token %}
- XSS:富文本 body_html 经
bleach 白名单清洗,禁用 iframe/script
- SQL 注入:ORM 强制参数化;禁止 raw query 拼接
- IDOR:所有对象级查询带
shop_id + owner_id 过滤,靠 BaseShopQuerySet 强制
- 限流:基于 IP + Token 双维度,按 API 与 IP 双重阈值
- 审计:敏感操作(退款、删除、Token 生成、权限变更)写
audit_log,保留 ≥ 3 年
- GDPR / 个保法:客户删除请求 → 14 天宽限 → 真实删除(订单客户字段脱敏);客户可导出全部个人数据
- PCI DSS:不落地卡号;用 Stripe/AliPay 等已认证网关;不追求独立过 PCI
- WAF:接 Cloudflare / 阿里云 WAF,规则 OWASP Top 10
- DDoS:CDN 前置;管理后台强制 IP allowlist / VPN
| 维度 |
工具 |
| 错误 |
Sentry(前后端) |
| 性能 |
Prometheus + Grafana + Django Silk(开发) |
| 日志 |
结构化 JSON 日志 → ELK / Loki |
| 链路 |
OpenTelemetry → Jaeger / Tempo |
| 业务 |
自建埋点:订单、结账、关键 CTA |
| 告警 |
Alertmanager + 钉钉/企业微信通知 |
- 数据库:每日全量 + 每小时增量,保留 30 天;PITR 支持
- 对象存储:跨区复制
- 异地灾备:异地热备 RPO ≤ 1h,RTO ≤ 4h
- 定期演练:每季度一次恢复演练
- 后端 i18n:
django.utils.translation + DB 翻译
- 前端 i18n:主题
locales/*.json 文件
- 时区:服务端全 UTC,展示按店铺时区
- 货币:所有金额多币种支持,符合 ISO 4217
- 文字排布:支持 LTR/RTL(预留)
- 主流浏览器:Chrome/Edge/Safari/Firefox 最近 2 个大版本;移动端 iOS Safari/Android Chrome 最近 2 个大版本
- 主题默认符合 WCAG 2.1 AA;图片 alt、按钮 ARIA 标签
- 视图组件预留 Lighthouse ≥ 90 分要求
| 模块 |
单月数据量 |
一年累计 |
备注 |
| products/variants |
10 万 / 50 万 |
静态 |
|
| orders |
5 万行 / 30 万行 line_items |
600 万 |
按月分区 |
| customers |
3 万 |
35 万 |
|
| page_view 与 cart_event |
5000 万 |
6 亿 |
独立 OLAP |
| audit_log |
50 万 |
600 万 |
|
建议 Phase 1 用 PG 单库 + 主从,Phase 2 引入只读库分库 + OLAP ClickHouse/DuckDB。
| 阶段 |
周期 |
交付目标 |
章节覆盖 |
| Phase 0 基础设施 |
W1~W3 |
项目脚手架、CI/CD、环境、Docker、监控 |
整体 |
| Phase 1 MVP 顶配 |
W4~W16 |
P0 模块上线、可走通完整购买闭环 |
M01/M02/M03/M04/M05/M10 |
| Phase 2 商家增强 |
W17~W28 |
P1 模块、营销与分析、客户体系 |
M06/M07/M08/M09/M11/M12/M14 |
| Phase 3 多渠道与生态 |
W29~W40 |
多渠道适配 + Headless 前端 + 开放平台 |
M13、Hydrogen-like、App 体系 |
- 仓库结构、Docker Compose 一键启动
- CI:lint(ruff/black/mypy)+ pytest + 安全扫描(pip-audit、trivy)
- 基础设施层:PostgreSQL、Redis、MinIO、Celery、Sentry、Prometheus 接入示例
- 公共
core 模型基类、错误码、JWT/OAuth 框架
| 里程碑 |
周次 |
模块 / 任务 |
| M1 |
W4-W5 |
shops、accounts、products 模型与 Admin API |
| M2 |
W6-W7 |
variants、images、collection(含自动集合)+ Storefront 商品 API |
| M3 |
W8 |
inventory + location 模块 |
| M4 |
W9-W10 |
cart、checkout 核心 + 多步结账流程 |
| M5 |
W11 |
orders、payment adapter(Stripe/支付宝/微信)+ order 状态机 |
| M6 |
W12 |
themes 渲染引擎 + 默认主题样式(参考 Shopify 默认主题 Dawn) |
| M7 |
W13-W14 |
内部集成测试 + E2E(Playwright)+ 限流、Webhook |
| M8 |
W15-W16 |
内测、Bug Bash、文档化 |
Phase 1 完成 = 冷启动可用:商家可上架、前台搜索购物、完成下单、看到订单。
| 里程碑 |
周次 |
模块 / 任务 |
| M9 |
W17-W18 |
draft orders、order edit、returns、refunds 闭环 |
| M10 |
W19-W20 |
customers + customer segments + admin 全文搜索 |
| M11 |
W21-W22 |
price_rules + discount_codes + automatic + discount functions sandbox |
| M12 |
W23-W24 |
gift cards + 多支付凭证 + 对账 |
| M13 |
W25-W26 |
marketing:邮件/SMS/自动化工作流 |
| M14 |
W27-W28 |
analytics:live view、销售报表、cohort、自定义报表 |
| M15 |
W29 |
多语言多币种 + Markets |
| M16 |
W30 |
SEO 全套 + 域名多绑 |
| M17 |
W31-W32 |
性能调优 + 压力测试 |
| 里程碑 |
周次 |
模块 / 任务 |
| M18 |
W33-W34 |
channels adapter 框架 + Online Store + Manual |
| M19 |
W35-W36 |
POS 适配器(含离线模式与同步) |
| M20 |
W37-W38 |
外部渠道(Facebook/Meta/TikTok)适配 |
| M21 |
W39-W40 |
Headless Storefront SDK(React + Hydrogen-like) |
| M22 |
W41-W44 |
开放平台 / 应用市场适配(OAuth2、Embedded App) |
| 角色 |
建议人数 |
关键产出 |
| 产品经理 |
1 |
需求拆解、原型、验收 |
| 后端 |
3 |
Django app 开发、API、性能 |
| 前端 |
2 |
Admin UI + 主题模板引擎 |
| DevOps/SRE |
1 |
CI/CD、监控、部署 |
| 测试 |
1 |
E2E 与回归 |
| UI/UX |
1 |
默认主题设计 |
gantt
title Django 电商平台开发节奏
dateFormat YYYY-MM-DD
section Phase0
基础设施 :p0, 2026-08-01, 21d
section Phase1
MVP 核心模块 :p1, 2026-08-22, 91d
section Phase2
商家增强 :p2, 2026-11-21, 84d
section Phase3
多渠道生态 :p3, 2027-02-13, 84d
| ID |
风险分类 |
描述 |
影响 |
缓解 |
| R-1 |
技术 |
Liquid 模板引擎自研成本高 |
高 |
限制子集;引入 liquidpy / python-liquid 开源实现 |
| R-2 |
技术 |
主题 schema 校验与可视化编辑器前端复杂 |
中 |
第一版降级到表单编辑,第二版再上拖拽 |
| R-3 |
业务 |
多币种汇率与关税边界复杂 |
中 |
仅做主流币种;接入外部 Avalara |
| R-4 |
性能 |
订单月分区 + 写入热点 |
中 |
主键设计避开同 shop 单库写热点,考虑 sharding |
| R-5 |
支付 |
第三方网关 SLA 与跨境合规 |
高 |
多网关冗余;按地区 routing |
| R-6 |
数据 |
客户数据合规(GDPR / 个保法) |
高 |
法务参与设计;删除链路提前打通 |
| R-7 |
团队 |
关键工程师流动 |
中 |
双盲交接 + 高测试覆盖 + 文档化 |
| R-8 |
质量 |
第三方对接回归工作量大 |
中 |
适配器契约测试 + mocking 框架 |
- 《个人信息保护法》/ GDPR 数据字段最小化;同意弹窗;删除权
- 《电子商务法》商家资质存档;订单保存 3 年
- 《网络安全法》等级保护 2.0(建议三级);日志保留 ≥ 6 个月
- PCI DSS:通过使用合规第三方网关规避直接获取卡数据
- 海关/进口:跨境订单按平台/集货/直报模式分别对接
- 税务:增值税开票系统集成(电子发票 / 数电票)
- 招投标与商业条款相关留痕审计
- 数据分类:公开 / 内部 / 机密 / 受限
- 数据脱敏:开发与测试环境强制脱敏;生产数据访问需 ticket + 双审
- 数据传输:内部服务 mTLS
- 数据导出:所有大表导出走审批;导出文件加水印与有效期 24 小时
- 文档体系:本功能需求 → 接口规约(OpenAPI/GraphQL)→ 数据模型详设 → 设计决策记录 (ADR) → 运维手册
- 变更管理:所有破坏性 API 改动走 RFC,需 2 人 review + 1 周 window
- 版本:使用 SemVer;每次 Release 配 CHANGELOG
| Shopify 概念 |
本系统实现 |
章节 |
| Shop |
Shop model + shop_id 多租户预留 |
18.2 |
| Admin API |
/api/admin/*.json REST + /api/admin/graphql GraphQL |
19.3-19.4 |
| Storefront API |
/api/{ver}/graphql.json GraphQL |
19.4 |
| Webhook |
apps/webhooks/ HMAC 签名 + 重试 + 重放 |
19.5 |
| Liquid |
自研 Python 沙箱子集(参考 python-liquid) |
13.3.5 |
| Online Store 2.0 / Sections |
apps/themes/ + JSON templates schema |
13 |
| Cart |
apps/cart/ + Storefront cartCreate 等 mutation |
6.3.1 |
| Checkout |
apps/checkout/ + Checkout Extensibility |
6.3.2 |
| Order / DraftOrder |
apps/orders/ |
7 |
| Fulfillment / Location |
apps/inventory/ |
5 |
| Product / Variant / Collection / Image |
apps/products/ |
4 |
| Metafield / Metaobject |
apps/metafields/ |
4.3.4 |
| Customer / SavedSearch / (Audiences) |
apps/customers/ + 自定义 segments |
9 |
| Discount / PriceRule / AutomaticDiscount |
apps/discounts/ + RestrictedPython script |
10 |
| Functions / Flow |
apps/discounts/script_engine.py + Celery 编排 |
11.3 |
| GiftCard |
apps/payments/giftcard.py |
8.3.3 |
| Shop Pay / Wallet |
抽象 WalletProvider(预留) |
8 |
| Markets(多市场) |
apps/pricing/market.py + 域名/币种/税率 |
17.2 |
| Markets Duties / DDP |
apps/tax/ |
17.3.6 |
| Plus Apps / App Bridge |
第三方 OAuth + Embedded App(Phase 3) |
21.5 |
| Analytics / Live View |
apps/analytics/ + 物化视图 |
12 |
| Custom Reports |
apps/analytics/reports/ |
12.3.5 |
| Audiences |
客户 Segment + 营销自动化 |
9.3.3 + 11 |
| Email / SMS |
apps/marketing/ |
11 |
| Robots.txt / Sitemap / Redirects |
apps/seo/ |
15 |
| Sales Channels |
apps/channels/ adapter |
16 |
| POS |
Offline-first 适配器 |
16.2 |
| Theme App Extension / UI Extensions |
ThemeExtension 抽象(Phase 3) |
13.3 |
| Web Pixel |
WebPixel 注册表 + JS SDK |
6.3.2 |
文档结束。
本文档为对标 Shopify Plus 全量电商系统的 Django 实现需求规格说明书。各模块 API 字段细则、OpenAPI 文档、数据迁移规范将在独立交付物中以工程化形式输出。本文作为功能基线供产品评审与开发对接使用。
AI生成