4a76134ca9
「付完刷新等十几秒」的服务端主因:GetOrder 的 activated 只认本地 row=paid,而 row 只有 webhook 到账才翻;webhook 投递+退避重投正是那十几秒。GetOrder 其实早已调 pay 网关查单(st),却只当 pay_status 展示、没用来开通。 改法(仅 pangolin,pay 无需改):GetOrder 拿到网关 st 后,若 st.Status=="paid" 但本地 row 未 paid → 用 st 拼 webhookEvent 就地调 settle(复用 webhook 同一段幂等开通逻辑), 把「等 webhook」压成「付完下一拍查单即开通」。webhook 保留作兜底。 - Handler 加可选 settler(orderSettler 接口,*WebhookHandler 已满足)+ SetSettler; main.go 装配时 payHandler.SetSettler(payWebhook)。 - 幂等双保险:row.Status!="paid" 守卫 + settle 内锁行/已 paid 短路 → 重复轮询/并发查 不二次开通、不二次发奖。settle 失败仅记日志,退回旧展示由下一拍或 webhook 兜。 - channel 查单不返回 → 回退 row.Method(仅影响渠道显示)。成功状态词 "paid" 已对齐 pay 仓 model.OrderStatusV2,提为 payOrderPaid 常量并注释「改前对齐 pay 契约」。 - 信任模型一致:主动调 pay 自有接口(server→server,order_no 持有凭据),与现有把 st.Status 当 pay_status 透传同源,非接收外部推送,不需 webhook 那样验签。 测试:新增端到端 sqlite——网关 paid→就地开通(activated + 台账翻 paid + 真授予订阅) 且重复轮询幂等(仍 1 条订阅);网关 pending→不开通。go test ./... 全绿、vet 干净。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEVUXAbFT6bF1Qw27RHWoD
Pangolin Server
Go 后端控制面,负责账户、套餐、激活码、设备与节点目录管理。架构详见 ../design/server/ARCHITECTURE.md。
目录结构
server/
├── cmd/
│ ├── server/ # HTTP 服务入口(chi router,/healthz,/v1 挂载归 1d)
│ └── migrate/ # 数据库迁移 CLI 入口(实现归 1e)
├── internal/
│ ├── config/ # 配置加载(env + 文件,归 1e)
│ ├── store/ # 数据库访问层 Postgres(归 1e)
│ ├── apierr/ # 统一错误体 {code, message_zh, message_en}(归 1f)
│ ├── idgen/ # UUID + Crockford Base32 激活码(归 1f)
│ ├── auth/ # 验证码、argon2id、JWT RS256(归 1c/1d)
│ ├── codes/ # 激活码批次、兑换、审计(归 1d)
│ ├── devices/ # 设备管理(归 1d)
│ ├── nodes/ # 节点目录、connect/disconnect(归 1d)
│ ├── usage/ # 用量统计(归 1d)
│ └── admin/ # 内部管理端(归 1d)
├── Makefile
├── go.mod
├── go.sum
├── tools.go # //go:build tools — 锁定 oapi-codegen / migrate 版本
└── .golangci.yml
常用命令
make build # go build ./...
make test # go test ./...
make vet # go vet ./...
make lint # golangci-lint run ./...
make generate # oapi-codegen 代码生成(1d 填充)
make migrate-up # 执行迁移(1e 填充)
make migrate-down # 回滚迁移(1e 填充)
# 快速启动(默认监听 :8080)
go run ./cmd/server
# 指定地址
go run ./cmd/server -addr :9090
# 或通过环境变量
ADDR=:9090 go run ./cmd/server