Files
shaguabijia-app-server/docs/database/cps_click.md
T
2026-06-17 23:32:36 +08:00

4.3 KiB

cps_click — CPS 短链点击事件(/c/{code} 每次访问/复制记一条)

模型 app/models/cps_link.py(CpsClick,与 CpsLink 同文件) · 仓库 app/repositories/cps_link.py(record_click / click_stats_by_group) · 接口 用户 GET /c/{code}(记 visit)、POST /c/{code}/copy(记 copy,app/api/v1/cps_redirect.py);统计 admin GET /admin/api/cps/stats · ← 索引 · 总览

群发短链 cps_link 每被点一次就在此记一条。在 CPS 群发漏斗里它是**"用户点了"这一步**:用户点 /c/{code} 进落地/被跳转记 visit,淘宝落地页点"复制口令"记 copy。据此统计点击 PV/UV(按群/活动/时段),配合 cps_order 的下单/佣金构成"点击→下单→佣金"漏斗。group_id/sid 在本表冗余一份(来自 link),统计直接按群聚合、不必 join cps_link

用在哪 / 增删改查

  • C(插入):record_click(app/repositories/cps_link.py),由 cps_redirect 两处触发——GET /c/{code}(cps_landing)记 event_type=visit;POST /c/{code}/copy(cps_copy,淘宝落地页点复制按钮 fetch 回调)记 event_type=copy。写入时把 link 的 group_id/sid 冗余进来,ua 截断到 500。记点击失败被 _record 吞掉绝不阻断用户跳转/落地(公网无鉴权,任何人点都要能跳)。无幂等——每次点都写新行(PV 即行数)。
  • U / D:。点击是只追加的事件流。
  • R(读):click_stats_by_group(GET /admin/api/cps/statsgroup_stats 调用)按 group_id 聚合 → {pv, uv, copy_pv, copy_uv};UV 按 (ip, ua) 近似去重,visit 计 pv/uv、copy 计 copy_pv/copy_uv。聚合在 Python 侧做(量级小、跨 PG/SQLite 无方言坑)。

字段

类型 约束 / 默认 说明(取值 / join)
id Integer PK, autoincrement
link_id Integer index, NOT NULL 来源短链 = cps_link.id(语义关联,非 FK)
group_id Integer index, NOT NULL 冗余自 link.group_id;按群聚合点击快,免 join cps_link
sid String(64) index, nullable 冗余自 link.sid;美团有、淘宝/京东无
event_type String(16) NOT NULL, default/server_default visit visit(进落地页/被 302 跳) / copy(淘宝落地页点了"复制口令")
ip String(64) nullable 客户端 IP(取 X-Forwarded-For 首段,否则 request.client.host),UV 去重键之一
ua String(512) nullable User-Agent,入库截断到 500;UV 去重键之一
clicked_at DateTime(tz) server_default now(), index, NOT NULL 点击时间,统计按时间窗过滤

关系 / Join Key

  • link_idcps_link.id(多对一,语义关联,无 ForeignKey)。
  • group_idcps_group.idsidcps_group.sid——均冗余字段,直接按群聚合用,非 FK。
  • cps_order 无直接关联:点击与订单在 group_stats各按 group_id/sid 聚合后并到同一群行,共同组成漏斗,但两表之间无 join key(无法把某次点击对到某笔订单——CPS 联盟不回传点击 id)。

索引与约束

  • PK id;index link_idgroup_idsidclicked_at
  • 无唯一约束、无外键(纯事件流,PV 即行数,允许重复)。

注意

  • event_type 是接淘宝时新增的:初版(277f9b1)只有 visit(点了就 302 跳美团,记一条即可);3a40f61 接淘宝后,淘宝落地页是 H5、用户要点按钮"复制口令"才算转化,故迁移 cps_v2_platformsevent_type(server_default visit 回填存量),copy 单独统计成 copy_pv/copy_uv。同迁移把 sid 改 nullable(淘宝/京东点击无 sid)。
  • group_id/sid 冗余的理由:统计是高频读路径,直接 WHERE group_id=? 聚合,省掉 cps_click → cps_link 的 join;代价是写入时多带两列(record_click 从 link 拷)。这与 model docstring 明说的"统计直接按群聚合、不必 join cps_link"一致。
  • UV 是近似值:按 (ip, ua) 去重,无 Cookie/设备指纹;同一人换网络/浏览器会重复计 UV。够运营看趋势,不作精确口径。
  • 记点击绝不阻断:_recordtry/except: pass 包住,落地/跳转优先级高于统计——丢几条点击可接受,挡住用户领券不可接受。