Files
shaguabijia-app-server/docs/guides/CPS发券分发与微信授权.md
marco 2164155a23 docs(cps): 加 CPS 发券分发 + 微信授权 交接文档
设群/建活动/生成落地页短链/美团对账/统计 + 微信网页授权拿 openid 做用户级统计的
完整说明,含数据流/数据表/平台差异/端点清单/配置项/代码地图/部署/排障/已知技术债。
挂入 docs/README 的 guides 索引。供他人接手。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 18:02:08 +08:00

14 KiB

CPS 发券分发 + 微信授权 系统说明(交接文档)

给接手人。读完应能:看懂系统、带运营走完"设群→建活动→生成链接→看统计"、接微信授权、排障、知道边界。 代码引用一律用「文件:符号」(不写行号,重构后符号比行号稳)。


一、这是什么 / 业务目标

傻瓜比价的 CPS 群发分发系统:运营在 admin 后台建「群」、建「活动」(美团/淘宝/京东的券)、生成带渠道追踪的落地页短链 /c/{code} 发到各微信群;用户点链接 → 落地页 → 跳转下单或复制淘口令领券 → 后端记点击、(美团)拉订单对账、(微信内)拿 openid 做用户级统计。

目标:把券发出去 + 把「点击 → 下单 → 佣金」漏斗、「哪个群/哪个微信用户领了券」统计出来,指导投放。


二、两套入口 / 两个域名(先建立全局)

域名 反代 代码 鉴权
运营后台 admin-web.shaguabijia.com admin 子应用 :8771 admin/routers/cps.py,前缀 /admin/api/cps admin JWT(operator/finance)
用户落地页 coupon.shaguabijia.com app-server :8770 api/v1/cps_redirect.py,无前缀 公网无鉴权(群里谁都能点)

两个域名都全反代到 app-server/admin。落地页域名 coupon.shaguabijia.comsettings.CPS_REDIRECT_BASE 配置,生成短链时拼前缀。


三、数据流

[admin] 建群(cps_group) → 建活动(cps_activity) → 生成链接(cps_link, 得 /c/{code})
                                                          │ 复制发到微信群
                                                          ▼
[用户点 /c/{code}] cps_landing:
   ├─ (微信内+开关开+无cookie) 302 跳微信授权 → 回调换 openid → 存 cps_wx_user + 种 cookie → 跳回
   ├─ 记一条点击 cps_click(visit, 带 openid)
   └─ 美团/京东:302 跳 target_url   |   淘宝:返回 H5 落地页(图+复制淘口令按钮)
                                                          │ (淘宝)点复制 → POST /c/{code}/copy 记 copy
                                                          ▼
[美团] 运营在 admin 点「刷新对账」→ query_order 拉订单 → cps_order(按 sid 归群)
                                                          ▼
[admin 统计] 对账统计页 + 群详情(折线图 / 每日明细 / 群内微信用户)

四、数据表(6 张,均在 app/models/cps_*)

模型 职责 / 关键字段
cps_group CpsGroup 群。name / platforms(多选 meituan/taobao/jd) / sid(美团渠道追踪位,仅美团群有;纯淘宝/京东为空) / member_count / status(active/archived)
cps_activity CpsActivity 可推广活动池。platform / name / act_id(美团活动物料ID) / product_view_sign(美团商品券) / payload(淘宝整段淘口令 / 京东链接) / image_url(淘宝落地页主视觉图,绝对URL)
cps_link CpsLink 群发短链。code(短码,/c/{code}) / group_id / activity_id / sid / target_url(美团短链/京东链接/淘宝淘口令) / platform
cps_click CpsClick 点击事件。link_id / group_id / sid / event_type(visit=进页/被跳转,copy=淘宝点复制口令) / ip / ua / openid(微信授权拿到,非微信/未授权为空)
cps_order CpsOrder 美团订单(query_order 拉回)。order_id(唯一,upsert) / sid(按它归群) / pay_price_cents / commission_cents(预估佣金) / refund_profit_cents(退款佣金) / mt_status(2付款3完成4取消5风控6结算) / pay_time
cps_wx_user CpsWxUser 微信用户。openid(唯一) / unionid / nickname / headimgurl / first_group_id(首次授权来源群)

金额全程存「分」,前端 ÷100 显示「元」。时间统一 tz-aware UTC,展示按北京。


五、三平台差异(最关键的一张表)

美团 淘宝 京东
链接生成 meituan.get_referral_link 转链(需群 sid) 直接用活动 payload(淘口令) 直接用活动 payload(链接)
落地页行为 302 跳美团短链 H5 落地页(主视觉图 + 复制淘口令按钮) 302 跳京东链接
对账 query_order 拉订单/佣金 ✗ 无开放 API ✗ 无开放 API
能统计到 点击 + 下单 + 佣金 点击 + 复制次数 点击

淘宝/京东订单类指标(有效单/成交额/佣金)在统计页显示「-」(无法对账)。只有美团群(有 sid)有订单数据。


六、运营操作流程(带新人就照这个)

  1. 建群:CPS 分发 → 群管理 → 新建群。选这个群发哪些平台的券(可多选);含美团时可填 sid(留空自动 g<id>)。
  2. 建活动:活动管理 → 新建活动。按平台填:美团填 actId(联盟「我要推广-活动推广」第一列) 或 商品券 productViewSign;淘宝填整段淘口令 + 必须上传落地页图;京东填推广链接。
  3. 生成链接:群管理 → 某群 → 「生成链接」→ 勾选要发的活动(只列该群平台范围内的)→ 每个活动出一条 https://coupon.shaguabijia.com/c/{code} → 复制发到群里。
  4. 对账(仅美团,finance 角色):对账统计 → 「刷新对账(拉美团订单)」→ 拉近 N 天订单入库。非实时,要手动点
  5. 看统计:对账统计页看各群点击/独立/复制/有效单/取消风控/成交额/预估佣金/结算佣金;点群名进群详情 → 折线图(点击趋势,天/小时)+ 每日明细大表格(点击+订单按天,含退款/净佣金)+ 群内微信用户(头像/昵称/领券次数)。

七、微信授权(用户级统计)

目的

用户在微信内打开落地页时,拿到 openid(识别这个人) + 昵称头像,做「每个微信用户在每个群领没领券」的用户级统计。

链路

/c/{code} (微信内 + 开关开 + 无 wx_openid cookie)
  → 302 跳微信 base 授权(snsapi_base,静默不打断)
  → 微信回调 /wx/oauth/cb?code=..&state=base:{code}
  → wx_oauth.exchange_code 换 openid → cps_wx_user_repo.upsert 存用户 + 关联群 → 种 wx_openid cookie(30天)
  → 302 跳回 /c/{code}(这次有 cookie,正常展示,记 visit 带 openid)
[淘宝群] 用户点「复制口令」→ 若还没昵称头像 → 跳 snsapi_userinfo 授权(用户点击=交互触发,避免微信"快照页")
  → 回调拉 userinfo 补 nickname/headimgurl → 跳回落地页自动复制

代码:cps_redirect.py:cps_landing / cps_redirect.py:wx_oauth_cb / cps_redirect.py:_taobao_landing_html(注入 userinfo 授权链接);微信调用封装 integrations/wx_oauth.py

三个硬前提

  1. 必须是已认证服务号(订阅号、未认证都不支持网页授权 → 报 10005)。
  2. 网页授权域名 = coupon.shaguabijia.com,在服务号后台「设置与开发→公众号设置→功能设置→网页授权域名」配置 + 放校验文件。校验文件由本服务端点 serve(见 cps_redirect.pyMP_verify_*.txt 路由,换号/换文件时改这里返回的串)。
  3. 凭证 + 开关:.envWX_MP_APPID / WX_MP_SECRET(服务号的, 微信支付那个 WECHAT_APP_ID);总开关 WX_MP_OAUTH_ENABLED=true。开关默认关 → 落地页走原逻辑、不拿 openid(认证未就绪时用)。判定见 config.py:Settings.wx_oauth_active

群内微信用户怎么算(重要,踩过坑)

admin/repositories/cps.py:group_wx_users 按「该群有带 openid 的点击」(cps_click.group_id + openid)算群内用户,再关联 cps_wx_user 拿画像。不是cps_wx_user.first_group_id——因为一个用户(cookie 已存)会去多个群,first_group_id 只记首次授权群,会漏算。

  • 美团/京东群只有 openid、没有昵称头像:它们是 302 跳转、没有"点复制领券"那一步,触发不了 userinfo。只有淘宝群点复制口令时才补昵称头像。

八、端点清单

admin(/admin/api/cps,operator/finance 鉴权)— admin/routers/cps.py

  • 群:GET /groups POST /groups PATCH /groups/{id} DELETE /groups/{id}
  • 活动:GET /activities POST /activities PATCH /activities/{id} DELETE /activities/{id} POST /upload-image GET /activity-images
  • 生成链接:POST /referral-links(批量,按 activity_ids,美团转链)
  • 对账:POST /orders/reconcile(拉美团订单) GET /orders(明细)
  • 统计:GET /stats(按群对账统计) GET /groups/{id}/timeseries(折线) GET /groups/{id}/daily(每日明细) GET /groups/{id}/wx-users(群内微信用户)

落地页(coupon 域,公网无鉴权)— api/v1/cps_redirect.py

  • GET /c/{code}(落地页:授权+记点击+跳转/H5)
  • POST /c/{code}/copy(淘宝点复制,记 copy)
  • GET /wx/oauth/cb(微信授权回调)
  • GET /MP_verify_*.txt(微信域名归属校验文件)

删除/编辑都不级联删已生成的 cps_link——已发出去的短链永远要能用,落地页只查 link 本身,不依赖 group/activity 是否还在(删了淘宝活动,其落地页图回退默认图)。


九、配置项(.env,见 app/core/config.py)

配置 说明
CPS_REDIRECT_BASE 落地页域名,如 https://coupon.shaguabijia.com。生成 /c/{code} 拼前缀;也是图/回调的绝对 URL 基址
MT_CPS_APP_KEY / MT_CPS_APP_SECRET 美团联盟凭证(转链 + 对账)。缺则美团相关优雅降级
MT_CPS_DEFAULT_SID 美团默认渠道位(群没 sid 时兜底)
WX_MP_APPID / WX_MP_SECRET 微信服务号网页授权凭证(≠ WECHAT_APP_ID 那个 App 支付用的)
WX_MP_OAUTH_ENABLED 微信授权总开关。默认 false;认证就绪后置 true 重启启用

十、代码地图

关注点 位置
admin 端点 admin/routers/cps.py
admin 业务逻辑(群/活动/订单/统计/群内用户) admin/repositories/cps.py(group_stats / group_click_timeseries / group_order_daily / group_wx_users / reconcile_orders)
admin 出入参 admin/schemas/cps.py
落地页 + 微信授权 api/v1/cps_redirect.py
短码生成 / 记点击 / 点击聚合 repositories/cps_link.py(create_link / record_click / click_stats_by_group)
微信用户 upsert repositories/cps_wx_user.py
美团集成(转链/拉单) integrations/meituan.py(get_referral_link / query_order)
微信网页授权集成 integrations/wx_oauth.py(build_authorize_url / exchange_code / get_userinfo)
数据模型 app/models/cps_*.py
admin 前端 shaguabijia-admin-web src/app/(main)/cps/(列表页 page.tsx + 群详情 groups/[id]/page.tsx)

十一、部署 / 运维

  • 部署:ssh ecs1deploy server(app-server + admin 后端)/ deploy web(admin-web 前端)。机制 = git reset 到 origin/main + 装依赖 + alembic 迁移 + 重启 + health 自检。
  • .env(如开微信开关、换服务号凭证)后:systemctl restart shaguabijia-app-server shaguabijia-admin 或重跑 deploy server
  • 数据库迁移:CPS 相关迁移在 alembic/versions/cps_*(建表 cps_tables/cps_link_tables、多平台 cps_v2_platforms、活动图 cps_activity_image、微信用户 cps_wx_user)。

十二、排障速查

现象 原因 / 处理
微信授权报 10005(没有这些 scope 权限) 账号不是已认证服务号,或「网页授权获取用户基本信息」接口未获得。确认账号类型 + 接口权限
微信授权报 10003(redirect_uri 域名不一致) 服务号后台「网页授权域名」没填 coupon.shaguabijia.com 或没保存成功
换了服务号后授权失败 .envWX_MP_APPID/SECRET + 在新服务号后台重配网页授权域名(校验文件可能是新的,要换 MP_verify_* 端点返回值)
落地页在微信里不跳授权 开关 WX_MP_OAUTH_ENABLED 没开,或不是微信 UA(外部浏览器不跳,正常)
群详情「群内微信用户」看不到人 已按"本群点击"算(group_wx_users)。确认该群 cps_click 有带 openid 的记录;美团/京东群昵称头像本就为空
统计页订单/佣金是「-」 淘宝/京东群无对账(正常);美团群需先点「刷新对账」拉单
成交额/佣金不更新 对账非实时,要 finance 手动「刷新对账」
账号验证 appid/账号类型 可用基础 token 调 cgi-bin/account/getaccountbasicinfo 查(account_type / 认证 / 主体)

十三、已知边界 / 技术债(接手前必读)

  1. 下单归因只到「群」级,做不到「人」级:美团 query_order 返回的订单只带 sid(群级渠道位),不带 openid。要统计"某个微信用户下没下单/下单额",需把 sid 体系改成用户级(每个用户进落地页时用其 openid 实时转链),是较大改动,未做。当前微信侧只能统计到"用户级领券/点击",下单仍是群级。
  2. 美团/京东群拿不到昵称头像:无 userinfo 触发点(直接 302 跳转)。只有淘宝群(H5 落地页点复制)能补昵称头像。
  3. 淘宝/京东无对账 API:只能统计点击/复制,拿不到下单/佣金。
  4. 落地页公网无鉴权:群发场景,链接谁拿到都能点(刻意如此)。点击 UV 按 (ip, ua) 近似去重,非精确。
  5. 对账非实时:cps_order 是上次「刷新对账」的快照,不点不更新。
  6. 激励奖励金额未统计:美团订单里 incentiveOrder 标记了是否参与激励活动,但 query_order 不给激励奖励金额,需另接「奖励活动报表」API(未做)。

本系统由本轮从零搭建:CPS 分发(群/活动/链接/对账/统计)+ 群详情可视化 + 微信网页授权用户级统计。后端在 shaguabijia-app-server,前端在 shaguabijia-admin-web。