# 01 系统总览与架构（for AI Agents）

> 关联代码：cmd/server/main.go、internal/router/router.go、internal/middleware/、internal/config/、internal/response/
> 本文档描述系统全貌与横切机制；各业务功能的细节见 llms/ 目录其他文档。

====================================================================
1. 功能概述
====================================================================

鲸彩好运（lottery-mp）是微信小程序抽奖营销平台，一个 Monorepo 包含三端：

- Go 后端（internal/）：Gin HTTP 框架 + GORM ORM，SQLite/MySQL 双驱动（环境变量/配置切换），可选 Redis（启用后：命运盒子计数、限流、L2 风控滑窗、分布式锁、Stream 异步队列、签名 nonce 全部切到 Redis）。所有路由集中在 internal/router/router.go 单文件。
- Vue 3 管理后台（web/）：TypeScript + Vite + Pinia + Naive UI。生产模式经 web/embed.go（go:embed）把 dist/ 嵌入 Go 二进制，单进程部署：/api 走接口、/assets 与 / 走后台 SPA（NoRoute fallback 到 index.html）、/static/uploads 是上传文件。
- 微信小程序（miniprogram/）：原生小程序，全部 68 页在主包，TabBar 四个（首页/福利街/任务/我的）+ 中间悬浮「发起」按钮。

请求分组（internal/router/router.go）：
- 公开组 /api：/health、两端登录（/api/admin/auth/login、/api/mp/auth/login）、微信支付/转账/退款回调、/metrics（Prometheus）。
- 管理组 /api/admin/*：JWT(kind=admin) + Audit 审计中间件；几乎每个端点再挂 RequirePerm(db, "权限码")。
- 小程序组 /api/mp/*：JWT(kind=mp)；无 RBAC，资源属主校验（creator_id/user_id 匹配）在 service 层。
- 开放接口 /api/open/v1/*：OpenAPIAuth（AK/SK + HMAC + 订阅特性校验），见 19。

====================================================================
2. 底层逻辑
====================================================================

2.1 启动与装配
- 唯一入口 cmd/server/main.go（约 737 行）：加载配置 → 初始化 logger/db → AutoMigrate（internal/model/migrate.go）→ 装配各 service（依赖注入，接口便于单测 fake）→ 挂路由 → 启动全部后台定时任务 → 优雅关停（SIGINT/SIGTERM，10s 超时）。
- 启动时幂等种子：超管账号 EnsureAdmin（用户名 admin；密码=ADMIN_INIT_PASSWORD 环境变量或随机 16 位，首次建号在启动日志打印一次）；RBAC 权限点与 3 个预置角色（operations/finance/risk）EnsurePresetRoles（一次性种子，configs 表标记 rbac.preset_roles_seeded，删除不复活）。

2.2 认证体系（三套，token 不跨端）
- 管理端：账号密码（bcrypt）→ JWT HS256，Claims{UID, Username, Kind=admin}，默认 24h。中间件 JWT 校验后每请求回查账号 status（禁用即时失效）。
- 小程序端：POST /api/mp/auth/login {code, nickname?, avatar?} → 微信 jscode2session（internal/wechat/miniprogram/client.go）→ findOrCreateUser（open_id 唯一索引兜底并发首登）→ JWT Kind=mp 默认 720h。新用户赠送 drawbox 新人次数 + points.newuser_grant 心愿值（best-effort）。
- 资损接口二次防护：SignMW（HMAC-SHA256 + timestamp 300s 窗口 + nonce 防重放，middleware/sign.go）挂在订单 confirm/repay、钱包 withdraw；security.sign_secret 未配置时降级为 noop（仅开发态）。
- Open API：Header X-Access-Key + HMAC 签名（method+path+body+timestamp+nonce），密钥表 OpenAPIKey 可吊销/过期，且要求商户订阅含 api_access 特性。

2.3 响应信封与错误码（internal/response/）
- 统一 {code, msg, data}；业务错误 HTTP 恒 200；HTTP 401 = 未认证（后台前端收到即清 token 跳 /login）。
- 全局码（code.go）：0 成功；1001 bad_request；1002 unauthorized；1003 forbidden；1004 not_found；1005 internal；2001 已存在；2002 不存在；2003 凭证错误；2004 无权限；3001 支付未配置；3002 验签失败；3003 订单不存在；3004 冲突（如已领取）；4011-4013 签名无效/过期/重放；4014-4016 OpenAPI 密钥无效/过期/未开通。
- 抽奖域 21xx（lottery_codes.go，2100-2199 整段保留）：2101 名额满；2102 已参与；2103 口令错误；2104 不可参与；2106 近期中奖者限制；2108 风控拦截；2109/2110 区域限制/缺定位；2111 未填问卷；2116 需关注公众号；2124 定位服务不可用；2125 问卷配置异常；2130-2139 组团类；2150-2159 签到抽奖；2160-2169 幸运抽奖（2160 积分不足）；2170-2179 每日666；2180-2189 助力（2180 未参加抽奖不可助力）。
- 命运盒子独立码空间（drawbox_codes.go，数值与全局重叠但仅经 DrawboxJSON 返回）：1001 无机会；1002 今日上限；1003 风控；1004 成本熔断；1005 分布式锁繁忙；1006 视频冷却；5000 系统错误。
- 实现为 sentinel error → 码表映射（errors.Is），排查时按码反查 service 内 sentinel 定义。

2.4 配置体系（两层）
- 静态配置 configs/config.yaml（viper，支持 config.local.yaml 覆盖 + 环境变量；结构定义 internal/config/config.go）。关键项：
  - server.addr(:8080)/mode；jwt.secret（空或默认拒启动）/admin_expire_hours(24)/mp_expire_hours(720)
  - db.driver：sqlite|mysql；redis.addr/password/db
  - wechat.miniprogram.appid/secret；wechat.pay.*（mchid、apiv3_key、证书、notify_url、transfer_scene_id、transfer_notify_url、refund_notify_url）；wechat.subscribe_msg.*（6 个订阅消息模板 ID）；wechat.official_account.*（粉丝同步门槛，未配置 fail-closed）；wechat.work_wechat.*（企微好友门槛，同 fail-closed）
  - redpacket.credit_mode（auto 开奖即入账 / claim 用户领取后入账，默认 claim）、min_withdraw_fen(100)、daily_withdraw_count(3)、daily_withdraw_amount_fen(50000)
  - geoip.xdb_path：ip2region 离线库（广告地区定向 + 抽奖区域限制共用；未配置时带区域限制的抽奖拒绝一切参与）
  - upload.driver local|cos（腾讯云 COS，配置不全自动降级 local）；order.pay_timeout_minutes(150，须大于微信 2 小时)；security.sign_secret/replay_window_seconds
- 运行时 KV 配置（model.Config 表，internal/service/config）：后台「配置管理/资金管理/命运盒子」等页面实时读写，改完即生效（service 每次实时读取）。重要键：wallet.withdraw_enabled、wallet.min_withdraw_fen、drawbox.daily_free_chance / drawbox.cost_*_ratio / drawbox.task_* 等、daily666.*、points.newuser_grant、alert.wecom_webhook_url、rule_1..rule_6（助力规则文案）、risk.l2_ip_limit 等风控阈值、rbac.preset_roles_seeded。
- 功能开关统一注册表（internal/service/config/switches.go）：所有跨模块功能开关集中声明为 []SwitchSpec，后台「功能开关总览」页一处管理。每个开关有 Key/Label/Group/Description/Default/Kind（plain 布尔 | json 带附属字段）。当前 4 个开关：用户动态功能（json，含附属字段）、充值入口（json，含 tiers 档位数组）、提现入口（plain）、每日666抽奖（plain）。SetFeatureSwitch 对 json 类型做 read-modify-write 保留附属字段（如切换充值入口不会丢失档位配置）。
- 充值配置（internal/service/config/config.go RechargeConfig，键 "recharge"）：JSON 存储 enabled + tiers 数组（每档 amount_fen/points）。默认 4 档（1/5/10/30 元），赠送好运币按最低档位基准汇率动态计算（BaseTier→BonusFor），超出基准的部分即为赠送。后台「充值配置」页可编辑档位与开关。

2.5 定时任务（全部在 cmd/server/main.go 启动，优雅关停统一 Stop）
- lottery Scheduler：30s——time 到点/满人/阶段开奖 + recoverAfterDraw 兜底补跑兑换码分配与红包入账（幂等）
- signin_lottery Scheduler：30s 自动开奖
- daily666 Scheduler：30s 轮询（默认每日 20:00 开奖，draw_hour/draw_minute KV 可调）
- wallet Sweeper：60s 提现转账单对账自愈（processing → success/failed）
- order Sweeper：60s 超时关单 + 超期自动确认收货
- finance Sweeper：10min 财务日汇总（FinanceLog）
- drawbox Sweeper：5min 每日限发/成本台账重置兜底
- risk L4Sweeper（24h 社交层重评）+ v8Engine（IP 滑窗 GC）
- followersync：30min 公众号粉丝全量同步到 OfficialFollower 表
- guaranteed_coupon sweep：1h 过期必中券标记
- 常驻：points EventBus（中奖/待填地址事件 → 通知）、Redis Stream 消费者 ×2（drawbox A/B 转化上报、miss_count 索引）、auditHub（后台审计日志异步落库）

2.6 横切机制
- 限流：middleware.Limiter（进程内）/RedisLimiter（多实例），挂 /mp/drawbox/draw|claim|task/complete。
- 风控：internal/service/risk —— RiskSvc.CheckAllowed 前置注入抽奖参与/提现/兑换；V8 五级引擎（L1 设备指纹、L2 IP 滑窗、L3 行为、L4 社交层），阈值经 KV 可调；RiskLog 事件（self_invite/circular_invite/bind_after_active/invite_burst/same_ip_cluster/share_token_abuse）。
- 加密：收货地址 Name/Phone/Detail 与订单 AddressSnapshot 用 AES-GCM 加密（internal/pkg/crypto，环境变量 LOTTERY_AES_KEY；未配置时明文透传）。
- 审计：admin 组全部请求经 middleware/audit.go 异步写 OperationLog。
- 可观测：Prometheus /metrics（HTTP 指标 + 业务指标）、RequestID/AccessLog、健康检查 GET /api/health。
- 上传：POST /api/admin/upload、/api/mp/upload → 本地 static/uploads 或腾讯云 COS；有大小/扩展名白名单限制。

2.7 并发与一致性总原则（各业务通用）
- 资金/库存类变更：DB 事务 + 行锁（SELECT...FOR UPDATE）或条件 UPDATE（RowsAffected 判定）+ 幂等键（唯一索引 OnConflict DoNothing）。
- 微信转账等外部网络调用绝不放进 DB 事务；结果不确定时进入 processing 状态等对账（见 10）。
- 抽奖开奖用「status<>drawn → drawn」条件更新抢占，防并发重复开奖。

====================================================================
3. 后台操作（页面级）
====================================================================

后台本身无「系统总览」专属页面；与本档相关：
- 配置管理 → 功能开关总览（/config/feature-switches）：全局开关统一注册表，按分组展示 4 个功能开关（用户动态/充值入口/提现入口/每日666），NSwitch 直切，关闭需二次确认。
- 配置管理 → 充值配置（/config/recharge）：充值入口开关 + 档位编辑（金额/好运币数），赠送按基准汇率自动计算展示。
- 系统管理 → 权限列表（/system/permissions）：只读查看全部权限码（约 90 个，分 system/business/common 组）——查某个操作需要什么权限码时用。
- 驾驶舱 → 运营驾驶舱 / 财务对账 / 盈亏平衡 / 风控中心：系统级监控（详见 17）。
后台通用操作习惯见 02。

====================================================================
4. 小程序端操作
====================================================================

小程序无系统级页面。登录为全静默（utils/auth.ts + app.ts ensureLogin：冷启动校验/静默 wx.login），业务页面统一 await app.loginReady 后加载；请求头带 Authorization: Bearer <token> 与 X-Device-Id（utils/device.ts UUID，供 L1/L2 风控）。请求封装 utils/request.ts（{code,msg,data} 约定，BusinessError 携带业务码；401 自动重登重试一次）。

====================================================================
5. API 速查（系统级）
====================================================================

GET  /api/health                          健康检查（无鉴权）
POST /api/admin/auth/login                管理端登录 {username,password} → {token,...}
GET  /api/admin/auth/me                   当前管理员信息 + 权限码列表
POST /api/mp/auth/login                   小程序登录 {code,nickname?,avatar?} → token
GET  /metrics                             Prometheus 指标（可配置关闭）
POST /api/wechat/pay/notify               微信支付回调（验签→按订单类型分发）
POST /api/wechat/transfer/notify          商家转账结果回调
POST /api/wechat/refund/notify            退款结果回调
GET  /api/admin/config/feature-switches   功能开关总览（config:read）
PUT  /api/admin/config/feature-switches/:key  切换功能开关（config:write）
GET|PUT /api/admin/config/recharge        充值配置（config:read/write）

====================================================================
6. 注意事项
====================================================================

- 金额后端/API 层一律「分」；积分/次数为整数。管理后台前端统一以「元」交互（API 层自动 fen↔yuan 转换），写新后台页面时按元传值即可。
- 业务错误 HTTP 200 + code!=0；不要用 HTTP 状态码判断业务成败。
- 后台前端菜单不做权限过滤（全部展示），无权限的操作会被后端 403 拒绝；前端按钮级权限指令未启用，判断权限以 GET /api/admin/auth/me 返回的 permissions 数组为准。
- internal/model、internal/middleware 等目录下有 test_*.db 测试残留文件，不是业务数据。
- 仓库 autocrlf=input（存 LF）；Windows 工作区 CRLF 会导致 gofmt -l 假阳性，CI 正常。
- MySQL/SQLite 双方言均有兼容测试；写 SQL 时注意方言差异（派生表别名、JSON 列型、GROUP BY 别名与 mp_users.level 撞名等既有坑）。
