技术架构
唯一技术主线:Go 后端 · 模块化单体 · 三进程部署 · Docker Compose / 单 VM · 不拆 K8s 微服务
架构结论
| 项目 | 决策 |
|---|---|
| 后端语言 | Go 1.22+,统一工具链 |
| 后端形态 | 模块化单体,不按业务拆微服务 |
| 部署单元 | api-server、worker、admin-api 三个 Go 进程 |
| HTTP 框架 | Gin |
| 主存储 | PostgreSQL 16 |
| 缓存/限流/短锁 | Valkey 8 |
| 文件存储 | 腾讯云 COS + CDN |
| 异步任务 | PostgreSQL outbox_events 表 + worker 轮询 |
| 生产部署 | Docker Compose / 单 VM |
| 暂不采用 | Rust 后端、gRPC、NATS/Kafka、K8s、Service Mesh、独立搜索、ClickHouse |
这版架构的目标不是技术炫技,而是让一个小团队能稳定交付交易闭环,并且能被 Agent Teams 按模块协作维护。
架构原则
| 原则 | 含义 |
|---|---|
| 单人可控 | 一个技术负责人能理解、部署、排障、回滚 |
| 交易链路优先 | 订单、支付、库存、配送、退款必须可追踪、可补偿、可审计 |
| 模块边界清晰 | 按业务模块拆代码,不按网络服务拆部署 |
| 运维成本低 | 不引入 K8s、服务发现、消息队列、链路追踪集群 |
| Agent 友好 | 一个仓库、统一语言、明确 owner 表和接口 |
| 数据事实优先 | PostgreSQL 是事实源,Valkey 只做可重建缓存和短锁 |
总体拓扑
三进程部署
| 进程 | 端口 | 职责 | 说明 |
|---|---|---|---|
api-server | 8080 | 用户端、配送端 API,业务主流程,JWT 验签 | 核心交易入口 |
admin-api | 8081 | 运营后台 API、RBAC、审计日志、后台数据管理 | 可复用 gin-vue-admin 的前端和权限思路 |
worker | 无 | Outbox 消费、订单超时、库存释放、通知、退款/支付对账 | 独立进程,避免阻塞 HTTP |
三个进程共享同一 Go 代码仓库、同一套领域模块、同一套数据库迁移。它们是部署进程,不是微服务边界。
代码结构
text
dingwei/
├── cmd/
│ ├── api-server/main.go # 用户端 + 配送端 HTTP API
│ ├── admin-api/main.go # 后台 HTTP API
│ └── worker/main.go # outbox / 延迟任务 / 通知
├── internal/
│ ├── auth/ # 微信登录、账号密码、JWT、权限
│ ├── user/ # 用户资料、地址、会员积分
│ ├── catalog/ # 商品、分类、溯源、图片引用
│ ├── inventory/ # 批次库存、锁定、扣减、流水
│ ├── order/ # 订单状态机、计价、Saga 编排
│ ├── payment/ # 微信支付、回调、退款、对账
│ ├── coupon/ # 优惠券模板、用户券、锁定释放
│ ├── delivery/ # 配送任务、骑手操作、脱敏信息
│ ├── asset/ # COS 预签名、文件元数据
│ └── shared/ # db、cache、config、logger、middleware、outbox、audit
├── pkg/
│ └── wechat/ # 微信登录/支付/订阅消息适配封装
├── migrations/ # golang-migrate SQL 脚本
├── deploy/
│ ├── docker-compose.yml
│ └── nginx.conf
├── Dockerfile
├── Makefile
└── go.mod模块边界
| 模块 | 数据 owner | 主要职责 |
|---|---|---|
auth | user_credentials, admin_accounts | 登录、JWT、权限、token version |
user | users, user_addresses, points_logs | 用户资料、地址、积分 |
catalog | products, categories, trace_records | 商品、分类、溯源展示 |
inventory | product_batches, inventory, inventory_locks, inventory_movements | 库存锁定、释放、扣减、流水 |
order | orders, order_items, after_sales | 订单状态机、计价、售后入口 |
payment | payments, payment_notifications, refunds | 支付、回调、退款、对账 |
coupon | coupon_templates, user_coupons | 券发放、锁定、核销、释放 |
delivery | delivery_tasks | 配送任务、认领、取货、送达 |
asset | assets | 文件上传凭证、COS key、CDN URL |
shared | outbox_events, idempotency_keys, audit_logs | 公共基础设施和审计 |
规则:
- 模块间通过 Go interface 调用,不通过 HTTP/gRPC。
- 非 owner 模块可以读别的模块表,但不能直接写。
- 跨模块写入必须调用 owner 模块的 service。
- 状态转换必须走模块内状态机函数。
- 所有核心写操作必须有幂等设计、错误上下文和测试。
交易链路
数据与一致性
| 场景 | 方案 |
|---|---|
| 订单创建 | 同进程 Saga:优惠券锁定 → 库存锁定 → 订单记录 → 支付单 |
| 支付回调 | 微信验签 + wechat_txn_id 唯一约束 + 状态条件更新 |
| 库存并发 | PostgreSQL 事务 + SELECT ... FOR UPDATE + version 乐观锁 + 库存流水 |
| 延迟任务 | outbox_events.scheduled_at + worker 轮询 + FOR UPDATE SKIP LOCKED |
| 接口幂等 | X-Idempotency-Key + Valkey 热缓存 + idempotency_keys 持久化 |
| 审计 | 后台敏感操作全部写 audit_logs,reason 必填 |
| 隐私 | 手机号/地址加密存储,查询用 hash,日志与配送端脱敏 |
PostgreSQL 是订单、支付、库存等事实数据的唯一来源。Valkey 丢失不能影响业务事实,只能影响缓存、限流窗口或短锁。
API 边界
外部 API 统一使用 HTTP JSON:
| 类型 | 示例 |
|---|---|
| 用户登录 | POST /api/auth/login/wechat |
| 商品 | GET /api/products, GET /api/products/:id/trace |
| 下单 | POST /api/orders/preview, POST /api/orders |
| 支付 | POST /api/payments/wechat/notify, GET /api/payments/:order_no |
| 配送 | GET /api/delivery/tasks, POST /api/delivery/tasks/:id/claim |
| 售后 | POST /api/after-sales, GET /api/after-sales/:id |
中间件顺序:Trace ID → 日志 → CORS/CSRF → 限流 → JWT 验签 → 权限 → Handler。
前端范围
| 端 | 技术 | 目标 |
|---|---|---|
| 用户小程序 | Taro 4 + React + TypeScript | 商品浏览、溯源、购物车、下单、支付、会员、售后 |
| 运营后台 | Vue 3 + Element Plus / gin-vue-admin 前端 | 商品、订单、库存、配送、退款、优惠券、审计 |
| 配送端 | Taro/H5 优先,后续可 RN | 任务列表、地图、认领、取货、送达 |
部署拓扑
yaml
services:
api-server:
image: dingwei/api-server:${APP_VERSION}
command: ["/app/api-server"]
ports: ["8080:8080"]
env_file: .env.production
depends_on: [postgres, valkey]
restart: unless-stopped
admin-api:
image: dingwei/api-server:${APP_VERSION}
command: ["/app/admin-api"]
ports: ["8081:8081"]
env_file: .env.production
depends_on: [postgres, valkey]
restart: unless-stopped
worker:
image: dingwei/api-server:${APP_VERSION}
command: ["/app/worker"]
env_file: .env.production
depends_on: [postgres, valkey]
restart: unless-stopped
postgres:
image: postgres:16
volumes: [pgdata:/var/lib/postgresql/data]
restart: unless-stopped
valkey:
image: valkey/valkey:8
volumes: [valkeydata:/data]
restart: unless-stopped
volumes:
pgdata:
valkeydata:初期生产环境按一台 4C8G 云服务器设计。增长后优先做垂直扩容、数据库备份恢复演练、读查询优化、缓存优化和多实例 HTTP 水平扩展;拆微服务和 K8s 不进入当前路线。
暂缓清单
| 暂缓项 | 当前替代方案 | 重新评估条件 |
|---|---|---|
| K8s / Helm | Docker Compose + systemd/脚本 | 团队具备专职运维,且多实例编排收益大于成本 |
| 微服务拆分 | Go 模块化单体 | 单模块负载、团队边界或发布频率明显分化,并完成 ADR |
| gRPC | Go interface + HTTP JSON | 出现跨进程服务且接口稳定 |
| NATS/Kafka | PostgreSQL Outbox | 事件量 > 100/s 或轮询延迟不可接受 |
| ClickHouse | PostgreSQL 报表 | 日订单 > 1000 或实时分析需求明确 |
| Meilisearch | PostgreSQL 查询 + 索引 | 商品 > 1 万且搜索 P95 > 200ms |
| WebSocket | 轮询 + 微信订阅消息 | 配送实时性成为核心体验 |
| 独立 Rust 服务 | Go 模块 | Go 无法满足支付/库存可靠性或性能要求 |
MVP 开发顺序
| 阶段 | 内容 | 验收产物 |
|---|---|---|
| 1 | 基础工程:配置、日志、错误码、DB、migration、CI | 服务可启动,健康检查可用 |
| 2 | 商品与后台:商品、分类、图片、上下架、溯源 | 用户可浏览商品 |
| 3 | 用户与地址:微信登录、手机号绑定、地址管理 | 用户可登录并选择地址 |
| 4 | 购物车与订单预览:价格快照、优惠券试算、配送时段 | 可预览价格 |
| 5 | 库存与下单:批次库存、锁定、订单创建、支付单创建 | 可创建待支付订单 |
| 6 | 微信支付:统一下单、回调验签、幂等、订单支付成功 | 可支付 |
| 7 | Worker:订单超时、库存释放、通知、对账 | 超时和通知闭环 |
| 8 | 配送:任务创建、认领、取货、送达 | 可配送完成 |
| 9 | 售后退款:退款申请、审核、微信退款、库存回滚 | 可退款 |
| 10 | 优惠券、积分、埋点、运营看板 | 可做基础增长 |
每个阶段只做一个垂直切片。支付、库存、订单状态机相关改动必须配套集成测试。
文档导航
| 文档 | 内容 |
|---|---|
| 🧠 逻辑架构 | 实体全景 × 服务目录 — 我们设计了什么,能对外提供什么 |
| 模块架构 | Go 模块边界、接口、调用规则 |
| API 设计 | 路由表、鉴权、幂等键、安全 |
| 数据存储 | 表 ownership、核心表、Outbox、审计、备份 |
| 状态机设计 | 订单、支付、库存、优惠券、配送、售后 |
| 前端架构 | 小程序、运营后台、配送端 |
| 可观测性 | 日志、指标、告警、运维排障 |
| 发布与部署 | CI、Docker Compose、migration、回滚 |
| 工程规范 | 本地开发、代码规范、安全、Runbook |
| Agent Teams 规范 | Agent 分工、任务模板、验收规则 |