小程序接口(lunar.neatcn.com)与商业版 Web(kepo.net)此前共用一个 二进制,导致小程序域名暴露商业后台与 Stripe Webhook,商业站点也 暴露了许愿树等小程序接口。现拆为两个入口: - cmd/mini:微信登录、生辰档案、许愿树、百科、版本号 - cmd/web:邮箱登录、commerce、报告/订单、/admin 后台、商业前端 静态托管与 SPA 回退 - internal/app 承载共用启动与路由注册;图片资源移至 internal/assets CI:server-deploy.yml 改构建 cmd/mini 并随包移除后台静态资源; 新增 web-deploy.yml 构建 cmd/web + web-commercial 前端,发布 web-v* Release;deploy-watch.sh 支持 TAG_PREFIX/ASSET_NAME 变量; 新增 deploy-web.sh(systemd 版)与 kepo 一次性配置文档 .gitea/docs/PULL_DEPLOY_WEB.md。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
126 lines
5.5 KiB
Markdown
126 lines
5.5 KiB
Markdown
# 知命 / 祈福后端服务
|
||
|
||
基于 Go、Gin、GORM 的后端仓库,包含两个部署入口:
|
||
|
||
- `cmd/mini`:小程序接口(lunar.neatcn.com)——微信登录、生辰档案、许愿树、百科。
|
||
- `cmd/web`:商业版 Web(kepo.net)——邮箱验证码登录、Stripe / Binance Pay、订单权益、报告快照、管理后台与商业前端静态站点。
|
||
|
||
两侧共用 `internal/` 下的配置、数据库、模型与中间件,但路由互不暴露。
|
||
|
||
## 功能模块
|
||
|
||
- 微信小程序登录与生辰档案。
|
||
- QQ 邮箱 SMTP 验证码登录,支持 465 隐式 TLS 或 587 STARTTLS;Postmark 可选备用。
|
||
- Stripe `4.99 USD` 报告支付。
|
||
- Binance Pay `5 USDT` 报告支付。
|
||
- 签名 Webhook、幂等事件、退款权益撤销。
|
||
- 随机报告恢复码与不可变报告快照。
|
||
- 用户订单与报告权益查询。
|
||
- 数据库驱动的 PC 商业版订单列表和收入统计。
|
||
- PC 商业版后台只查询 `type=bazi_report`,与小程序许愿等旧业务订单逻辑隔离。
|
||
- 许愿树与百科数据。
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
cp .env.example .env.local
|
||
go mod download
|
||
go run ./cmd/mini # 小程序接口
|
||
go run ./cmd/web # 商业版 Web(本地需 ../web-commercial/dist 与 ./web 静态资源)
|
||
```
|
||
|
||
默认地址:`http://localhost:8080`。
|
||
|
||
生产部署:
|
||
|
||
- **小程序接口**(doc79):CI 构建 `server-v*` Release,服务器 watcher 自动拉取,Docker 容器运行。见 `.gitea/docs/PULL_DEPLOY.md`。
|
||
- **商业版 Web**(kepo.net):CI 构建 `web-v*` Release(含 `cmd/web` 二进制 + `frontend/` 商业前端 + `web/` 后台静态资源),systemd 运行。一次性配置见 `.gitea/docs/PULL_DEPLOY_WEB.md`。
|
||
|
||
商业前端静态文件放在服务目录的 `frontend/`,根路径 `/` 为商业站点,`/admin/orders` 为管理后台,`/api/*` 为后端接口。
|
||
|
||
## 测试
|
||
|
||
项目包含 HTTP API 测试,覆盖未认证拦截、Webhook 拒绝、Stripe 模拟下单、签名回调、权益发放、恢复码和快照读取。
|
||
|
||
```bash
|
||
go test ./...
|
||
```
|
||
|
||
本地测试配置使用 `server/.env.test`。如果文件包含 SMTP 凭证,必须保持 Git 忽略并限制文件权限,绝不提交到仓库。真实发信测试需显式运行 `RUN_QQ_SMTP_LIVE_TEST=1 SMTP_TEST_TO=收件地址 go test ./internal/handler -run '^TestRequestEmailLoginCodeLiveQQSMTP$' -count=1`;该命令会实际发送邮件。
|
||
|
||
## 商业支付 API
|
||
|
||
### 邮箱登录
|
||
|
||
- `POST /api/auth/email/request`
|
||
- `POST /api/auth/email/verify`
|
||
|
||
### 支付与报告
|
||
|
||
- `POST /api/commerce/checkout` — 创建 Stripe 或 Binance Pay 订单。
|
||
- `POST /api/commerce/webhooks/stripe` — Stripe 签名通知。
|
||
- `POST /api/commerce/webhooks/binance-pay` — Binance Pay 签名通知。
|
||
- `GET /api/commerce/orders/:orderNo` — 查询本人订单。
|
||
- `GET /api/commerce/reports/:reportId/access` — 查询报告权益。
|
||
- `GET /api/commerce/reports` — 本人已购报告。
|
||
- `GET /api/commerce/reports/recover/:accessCode` — 使用恢复码读取购买时快照。
|
||
- `POST /api/commerce/charts` — 用户主动同意后保存免费排盘记录;接口限流并记录同意版本与时间。
|
||
|
||
除 Webhook 和需同意的公开排盘记录接口外,商业接口都要求 `Authorization: Bearer <JWT>`。
|
||
|
||
免费排盘默认不上传。创建付费订单时,报告快照会发送并保存在服务端,用于生成、交付和恢复已购报告。
|
||
|
||
## 管理后台
|
||
|
||
- `/admin/orders` — 真实订单列表。
|
||
- `/admin/api/orders` — 按渠道、状态、订单号、邮箱、报告号查询。
|
||
- `/admin/api/orders/stats` — 订单和收入统计。
|
||
|
||
后台使用 `ADMIN_PASSWORD` 登录并写入 HttpOnly Cookie。
|
||
|
||
## 支付安全
|
||
|
||
- 金额只从 `report_products` 读取。
|
||
- Stripe 使用 Checkout Session 和 `Idempotency-Key`。
|
||
- Stripe Webhook 校验 HMAC 签名与 5 分钟时间窗口。
|
||
- Binance Pay 下单使用 HMAC-SHA512。
|
||
- Binance Pay Webhook 使用商户证书 RSA 公钥验签。
|
||
- Webhook 同时校验服务商订单号、金额与币种。
|
||
- `payment_events` 唯一索引保证重复回调不会重复发放权益。
|
||
- 支付、事件、恢复码和权益在数据库事务中完成。
|
||
- 退款后报告权益自动撤销。
|
||
|
||
## 数据库
|
||
|
||
新安装由 GORM AutoMigrate 创建表。商业排盘记录新增同意版本和时间字段,服务启动时通过 AutoMigrate 增量添加;已有 MySQL 数据库应先备份再升级,不要执行数据库 fresh 或 refresh。商业表结构初始化脚本仍为:
|
||
|
||
```bash
|
||
mysql < migrations/002_commerce.sql
|
||
```
|
||
|
||
## 环境变量
|
||
|
||
完整模板见 `.env.example`。邮箱登录配置 QQ SMTP:
|
||
|
||
- `SMTP_HOST=smtp.qq.com`
|
||
- `SMTP_PORT=465`(或 587)
|
||
- `SMTP_USERNAME`:完整 QQ 邮箱地址
|
||
- `SMTP_PASSWORD`:QQ 邮箱生成的 SMTP 授权码,不是邮箱登录密码
|
||
- `SMTP_FROM_EMAIL`:发件地址。生产使用 `z@kepo.net`(`kepo.net` 已通过 QQ 域名邮箱绑定,MX 为 `mxdomain.qq.com`);需在 DNS 添加 SPF 记录 `v=spf1 include:spf.mail.qq.com ~all`,否则 Gmail 等可能拒收或判为垃圾邮件
|
||
- `SMTP_TLS_MODE=implicit`(465)或 `starttls`(587)
|
||
- `SMTP_TLS_CA_FILE`:可选的自定义 CA 文件路径
|
||
|
||
QQ 邮箱需先在账户设置中开启 SMTP 服务。SMTP 配置有效时优先使用 SMTP;未配置时才尝试 Postmark。生产环境还需要:
|
||
|
||
- `JWT_SECRET`
|
||
- `ADMIN_PASSWORD`
|
||
- `PUBLIC_BASE_URL`
|
||
- `WEB_APP_URL`
|
||
- `STRIPE_SECRET_KEY`
|
||
- `STRIPE_WEBHOOK_SECRET`
|
||
- `BINANCE_PAY_API_KEY`
|
||
- `BINANCE_PAY_SECRET_KEY`
|
||
- `BINANCE_PAY_WEBHOOK_PUBLIC_KEY`
|
||
|
||
所有支付与邮件密钥必须通过部署环境注入,禁止提交到 Git。
|