498da05995
(工作区既有改动, 非本次会话产出)
4.9 KiB
4.9 KiB
cps_group — CPS 推广群(一个微信群一条,sid 是美团渠道追踪位)
模型
app/models/cps_group.py· 仓库app/admin/repositories/cps.py(create_group/update_group/delete_group/get_group/get_group_by_sid/list_groups、统计group_stats) · 接口 adminPOST/GET/PATCH/DELETE /admin/api/cps/groups、统计GET /admin/api/cps/stats· ← 索引 · 总览
每个发券的微信群一条记录。核心字段是 sid——美团联盟二级渠道追踪位:发链接时塞进推广链接(get_referral_link),订单回来按 sid 归到这个群对账(query_order → cps_order)。在 CPS 群发漏斗里它是**"发给谁/在哪个渠道"**:群(本表)× 活动(cps_activity)组合生成 cps_link;点击(cps_click)与订单都靠 sid/group_id 归到本群,统计接口 group_stats 即以群为行做"点击→下单→佣金"漏斗。
用在哪 / 增删改查
- C(插入):
POST /admin/api/cps/groups(create_group,operator)。platforms至少选一个,非法平台 400。sid仅当platforms含meituan时才有:运营填了就用(校验全局唯一,重复 409),没填则先占位tmp<uuid>、flush 拿到 id 后回填成g<id>;纯淘宝/京东群sid恒None(那俩平台不支持 sid)。无业务幂等键(同名可重复建),唯一性只在sid上。 - U(更新):
PATCH /admin/api/cps/groups/{id}(update_group,operator)。可改name/platforms/member_count/status/remark。sid不可改(改了会断开历史订单的归群)。 - R(读):
GET /admin/api/cps/groups(list_groups,游标分页,keyword模糊匹配 name 或 sid、status过滤);生成 link 时get_group取群拿sid;统计group_stats遍历所有群、按sid关联订单、按group_id关联点击。 - D(删除):
DELETE /admin/api/cps/groups/{id}(delete_group,operator)。硬删,不级联已生成的cps_link(已发链接继续可用);该群历史cps_click/cps_order按sid/group_id仍在库,删群后这些 sid 在统计里降级为"未归群"行(group_id=None)。
字段
| 列 | 类型 | 约束 / 默认 | 说明(取值 / join) |
|---|---|---|---|
id |
Integer | PK, autoincrement | 被 cps_link.group_id、cps_click.group_id 语义引用(非 FK) |
sid |
String(64) | UNIQUE, index, nullable | 美团渠道追踪位,仅字母+数字 ≤64(美团限制,schema 正则 ^[A-Za-z0-9]+$)。仅含 meituan 的群有;留空自动 g<id>;纯淘宝/京东群为 None。订单/点击按它归群 |
name |
String(128) | NOT NULL | 群名,运营自定 |
platforms |
JSON / JSONB | NOT NULL, default [] |
该群发哪些平台(多选):["meituan","taobao","jd"]。含 meituan 才需要 sid。生成 link 时校验"活动平台必须在群范围内" |
member_count |
Integer | nullable | 群人数,运营填,作转化率分母(可空) |
status |
String(20) | NOT NULL, default active |
active / archived。统计 group_stats 只列 active 群 |
remark |
String(256) | nullable | 运营备注 |
created_at |
DateTime(tz) | server_default now(), NOT NULL | 创建时间(无 updated_at) |
关系 / Join Key
id←cps_link.group_id、cps_click.group_id(一群多 link/多点击,语义关联,无 ForeignKey)。sid←cps_order.sid(订单按 sid 归群对账,语义关联,非 FK);sid←cps_link.sid/cps_click.sid(生成 link 时把群 sid 冗余进 link/click)。- 与
cps_activity无直接列关系,经"批量生成短链"按平台组合。
索引与约束
- PK
id;UNIQUE+indexsid(uq_cps_group_sid+ix_cps_group_sid)。 - 无外键。
注意
sid从"必填"放宽到"可空"是多平台演进的关键改动:初版(277f9b1)sidNOT NULL + UNIQUE(每个美团群必有渠道位);3a40f61接淘宝/京东后,这俩平台没有 sid 概念,迁移cps_v2_platforms把sid改 nullable,并加platforms列(存量群 server_default 回填["meituan"])。理解本表必须记住:sid 只对美团有意义,对账/归群全链路只走美团群。g<id>自动 sid:运营不填 sid 时服务端生成g<群id>,既保证唯一又人类可读。先写tmp<uuid>占位是因为建群事务里 id 还没生成(flush 前拿不到),拿到 id 后二次 flush 回填。- 删群不级联是刻意的:已发到微信群里的短链不能因为后台删群就失效;历史订单/点击也要保留用于对账。代价是删群后其
sid的订单在group_stats里变成"未归群"独立行(如历史的wonderableai,见cps_order注意)。 platforms用 JSON 列:遵循全库约定JSON().with_variant(JSONB(), "postgresql")——PG 上 JSONB,SQLite 退化通用 JSON。