设群/建活动/生成落地页短链/美团对账/统计 + 微信网页授权拿 openid 做用户级统计的 完整说明,含数据流/数据表/平台差异/端点清单/配置项/代码地图/部署/排障/已知技术债。 挂入 docs/README 的 guides 索引。供他人接手。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.com由settings.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)有订单数据。
六、运营操作流程(带新人就照这个)
- 建群:CPS 分发 → 群管理 → 新建群。选这个群发哪些平台的券(可多选);含美团时可填 sid(留空自动
g<id>)。 - 建活动:活动管理 → 新建活动。按平台填:美团填
actId(联盟「我要推广-活动推广」第一列) 或 商品券productViewSign;淘宝填整段淘口令 + 必须上传落地页图;京东填推广链接。 - 生成链接:群管理 → 某群 → 「生成链接」→ 勾选要发的活动(只列该群平台范围内的)→ 每个活动出一条
https://coupon.shaguabijia.com/c/{code}→ 复制发到群里。 - 对账(仅美团,finance 角色):对账统计 → 「刷新对账(拉美团订单)」→ 拉近 N 天订单入库。非实时,要手动点。
- 看统计:对账统计页看各群点击/独立/复制/有效单/取消风控/成交额/预估佣金/结算佣金;点群名进群详情 → 折线图(点击趋势,天/小时)+ 每日明细大表格(点击+订单按天,含退款/净佣金)+ 群内微信用户(头像/昵称/领券次数)。
七、微信授权(用户级统计)
目的
用户在微信内打开落地页时,拿到 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。
三个硬前提
- 必须是已认证服务号(订阅号、未认证都不支持网页授权 → 报 10005)。
- 网页授权域名 =
coupon.shaguabijia.com,在服务号后台「设置与开发→公众号设置→功能设置→网页授权域名」配置 + 放校验文件。校验文件由本服务端点 serve(见cps_redirect.py里MP_verify_*.txt路由,换号/换文件时改这里返回的串)。 - 凭证 + 开关:
.env配WX_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 /groupsPOST /groupsPATCH /groups/{id}DELETE /groups/{id} - 活动:
GET /activitiesPOST /activitiesPATCH /activities/{id}DELETE /activities/{id}POST /upload-imageGET /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 ecs1→deploy 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 或没保存成功 |
| 换了服务号后授权失败 | 换 .env 的 WX_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 / 认证 / 主体) |
十三、已知边界 / 技术债(接手前必读)
- 下单归因只到「群」级,做不到「人」级:美团
query_order返回的订单只带sid(群级渠道位),不带 openid。要统计"某个微信用户下没下单/下单额",需把 sid 体系改成用户级(每个用户进落地页时用其 openid 实时转链),是较大改动,未做。当前微信侧只能统计到"用户级领券/点击",下单仍是群级。 - 美团/京东群拿不到昵称头像:无 userinfo 触发点(直接 302 跳转)。只有淘宝群(H5 落地页点复制)能补昵称头像。
- 淘宝/京东无对账 API:只能统计点击/复制,拿不到下单/佣金。
- 落地页公网无鉴权:群发场景,链接谁拿到都能点(刻意如此)。点击 UV 按 (ip, ua) 近似去重,非精确。
- 对账非实时:
cps_order是上次「刷新对账」的快照,不点不更新。 - 激励奖励金额未统计:美团订单里
incentiveOrder标记了是否参与激励活动,但query_order不给激励奖励金额,需另接「奖励活动报表」API(未做)。
本系统由本轮从零搭建:CPS 分发(群/活动/链接/对账/统计)+ 群详情可视化 + 微信网页授权用户级统计。后端在 shaguabijia-app-server,前端在 shaguabijia-admin-web。