8.8 KiB
萌芽小店 · 后端(mengyastore-backend-go)
基于 Go + Gin + GORM 的 REST API:商品与发货方式、订单、SproutGate 用户校验、站点设置、聊天、收藏夹;可选 RabbitMQ 发送订单邮件、可选 Redis;管理端提供 系统状态 聚合接口。
技术依赖(核心)
| 包 | / 用途 |
|---|---|
| gin | HTTP 路由 |
| gorm.io/gorm + driver/mysql | MySQL |
| gin-contrib/cors | CORS |
| google/uuid | 订单 ID |
| github.com/rabbitmq/amqp091-go | RabbitMQ(可选) |
| github.com/redis/go-redis/v9 | Redis 探测(可选) |
| github.com/joho/godotenv | .env.development(或 ENV_FILE)加载 |
目录结构(与仓库一致)
mengyastore-backend-go/
├── main.go # 路由注册、MQ 生命周期
├── docker-compose.yml
├── init.sql # 可选:建库参考
├── cmd/migrate/main.go # JSON → MySQL 历史数据迁移
├── internal/
│ ├── auth/sproutgate.go
│ ├── cache/ # Redis 等扩展
│ ├── config/config.go # 环境变量与默认值(APP_ENV、DSN、MQ、Redis…)
│ ├── database/db.go # Open + AutoMigrate
│ ├── database/models.go # GORM 表模型
│ ├── email/
│ ├── mq/ # 连接、拓扑、Publish、Consumer、断线重连
│ ├── models/ # JSON 业务模型
│ ├── storage/ # Product / Order / Site / Wishlist / Chat
│ └── handlers/
│ ├── public.go
│ ├── order.go
│ ├── stats.go
│ ├── wishlist.go
│ ├── chat.go
│ ├── admin.go
│ ├── admin_product.go
│ ├── admin_orders.go
│ ├── admin_site.go
│ ├── admin_chat.go
│ └── admin_status.go # GET /api/admin/system-status
API 路由一览
公开
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/health |
健康检查(可含 rabbitmq 状态) |
| GET | /api/products |
上架商品列表(无卡密、无 fixedContent) |
| POST | /api/products/:id/view |
记录浏览 |
| GET | /api/stats |
订单数、访问量等 |
| POST | /api/site/visit |
站点访问计数 |
| GET | /api/site/maintenance |
维护状态 |
| POST | /api/checkout |
创建订单:paymentMethod 默认 mengya,见下文「萌芽支付」 |
| GET | /api/orders/:id/payment-status |
结账轮询:status、paymentExpiresAt(不回卡密) |
| POST | /api/webhooks/mengya-pay |
到账通知 Webhook:X-Webhook-Secret 与配置一致时可省略 |
| GET | /api/orders |
当前用户订单(Bearer) |
| POST | /api/orders/:id/confirm |
确认订单(返回发货内容等) |
收藏夹(Bearer)
| GET | /api/wishlist |
| POST | /api/wishlist |
| DELETE | /api/wishlist/:id |
聊天(Bearer)
| GET | /api/chat/messages |
| POST | /api/chat/messages |
管理端(X-Admin-Token / Authorization / ?token=)
| POST | /api/admin/verify | 校验 token,返回 valid |
| GET/POST | /api/admin/products … | 商品 CRUD(见 payload 含 fulfillmentType、fixedContent) |
| PUT | /api/admin/products/:id |
| PATCH | /api/admin/products/:id/status |
| DELETE | /api/admin/products/:id |
| POST | /api/admin/site/maintenance |
| GET/POST | /api/admin/site/smtp |
| GET | /api/admin/orders |
| DELETE | /api/admin/orders/:id |
| GET … POST … DELETE | /api/admin/chat… | 会话与回复 |
| GET | /api/admin/system-status | backend / mysql / redis / rabbitmq 摘要 |
文档中若出现已废弃的
GET /api/admin/token,以仓库main.go为准。
数据库表(字段摘要)
products
| 字段 | 说明 |
|---|---|
| fulfillment_type | card 卡密逐条;fixed 固定内容(不限库存) |
| fixed_content | 固定发货正文(网盘链接、说明等);公开接口不返回 |
| payment_qr_urls | JSON 数组:paymentQrUrls,萌芽支付收款码图片直链(最多 10),管理端填写 |
| delivery_mode | 订单维度习惯字段:auto / manual(与 fulfillment 独立) |
| 其余 | name, price, discount_price, tags, cover_url, screenshot_urls, description, active, require_login, max_per_account, total_sold, view_count, show_note, show_contact … |
product_codes
卡密一行一条;fulfillment_type = fixed 时可为空。
orders
含 delivered_codes(JSON)、notify_email、delivery_mode、支付方式字段 payment_method、payment_expected_total、payment_expires_at。status 含:pending、pending_payment(萌芽待到账)、completed、cancelled(超时未付释放库存)等。
site_settings
KV:如 totalVisits、maintenance、smtpHost、smtpPassword 等;缺失键时 sitestore.get 不报错(不向日志刷 ErrRecordNotFound:Find 替代 First)。
配置说明
配置由 config.Load() 从进程环境变量读取。未设置 ENV_FILE 时,会在当前工作目录尝试加载 ./.env.development(文件不存在则跳过,不报错)。生产或其它环境请用 ENV_FILE=/path/to/.env.production 等方式显式指定文件。
要点:
DATABASE_DSN为空时按APP_ENV使用内建测试/生产默认 DSN(仅开发便利)。- RabbitMQ、Redis 开关与地址见
internal/config/config.go注释。 HTTP_LISTEN_ADDR、PUBLIC_API_BASE_URL供系统状态 JSON 展示。WEBHOOK_MENGYA_SECRET:若设置,到账 Webhook 须在请求头带相同X-Webhook-Secret。PAYMENT_PENDING_SECONDS:萌芽支付待支付窗口(秒,默认 60)。
API 文档(Swagger UI)开关
OpenAPI 规范由 swag 从代码注释生成(docs/swagger.json;重生成见仓库根目录 Makefile 的 swagger 目标)。运行期是否挂载 UI 由配置决定:
| 变量 | 说明 |
|---|---|
ENABLE_SWAGGER |
为 1 / true / yes / on(不区分大小写)时,注册 GET /swagger/*,浏览器打开 /swagger/index.html。 |
GIN_DEBUG |
为真时除 Gin Debug 模式外,也会开启 Swagger UI(与 ENABLE_SWAGGER 二选一满足即可)。 |
生产环境若未设置上述变量,默认不暴露 Swagger,减少接口探测面。
萌芽支付(Webhook 核销)
- 结账
paymentMethod: mengya(默认)且非免费:预留卡密或固定交付内容,status=pending_payment,写入payment_expected_total、payment_expires_at(UTC);此时不计销量,到账后再completed并IncrementSold+ 邮件。 POST /api/webhooks/mengya-pay:JSON 体与test/server.py打印结构兼容,从body.notice/notice等字段抽取到账¥x.xx金额,与待支付订单快照匹配(FIFO,ABS容差)。- 等额归因:多笔同额待支付可能被核销到最早一单,需业务规避或后续增强。
- 超时:后台定时扫描将订单
cancelled并退回卡密库存(固定内容类仅清空订单预留)。 - 旧版
paymentMethod=legacy_manual等请求已停用(返回 400)。
发货与订单逻辑
fulfillment_type = card(默认)
POST /api/checkout校验库存 ≥ 购买数量(萌芽支付下为预留待付,见上文)。- 从
product_codes取出对应条数写入订单delivered_codes,并Update商品去掉已发码。 - 销量
IncrementSold(免费单在结账时计入;付费萌芽支付在 Webhook 核销后IncrementSold);邮件/MQ 通知。
fulfillment_type = fixed
- 不校验卡密条数;不修改
product_codes。 - 将
fixed_content复制quantity次填入delivered_codes(与多件购买展示一致)。 - 仍
IncrementSold(规则同 card);邮件/MQ 同自动发货路径。
delivery_mode(订单)
业务上仍可区分用户确认后展示「等待人工发货」等;与 fulfillment_type 正交。
RabbitMQ 说明
- 启用时声明交换机/队列/绑定;订单邮件可
Publish,失败降级直发 SMTP。 - 504 channel closed 等可回收错误:客户端会 重连 并在成功后 重启消费协程(见
internal/mq/client.go)。
本地开发
在 mengyastore-backend-go 目录放置 .env.development(可被 git 忽略),或导出环境变量后再启动。
go run .
go build -o mengyastore-backend.exe .
go run ./cmd/migrate/main.go # 按需迁移旧 JSON;同样读取 .env.development 或 ENV_FILE
维护时请以 main.go 与 internal/database/models.go 为最终准据;本文随版本迭代更新。