C端v3 后端设施设计(波波 2026-09-24 接管)

依据:小冈 docs/plans/2026-09-24-C端v3完整架构方案.md 第五章(客服线索承接)+ 第七章(最小埋点集)
定位:只做后端设施 + A 端台账/漏斗页。C 端前端(v3 域:小齐/小冈)不动,对接时按本文第 5 节埋点 schema 上报即可。
原则:不关心具体商户身份——所有表 merchant_id 参数化 + is_test 隔离,沿用现有惯例。

1. 范围与边界

项本设计负责不负责
线索台账 crm_leads + SLA✅ 后端表 + 接口 + A 端页—
埋点 analytics_events⚠️ 复用现有,不新建表C 端采集代码(v3 域)
转化漏斗✅ 后端聚合接口 + A 端页—
is_test 治理✅ 写入带标记、查询默认隔离既有 hotel stats 的 is_test 过滤(后续补)

不碰:具体商户是谁、MVP 商户定死(这是数据/运营决策,与系统实现无关)。


2. 复用决策(关键:避免重复造轮子)

探查发现后端已有完整埋点基础设施,C 端 v3 的埋点层直接复用,不新建:

properties JSONB 自由扩展完美承载 5 类事件的差异化字段,is_test 已支持。结论:不新建 events 表,不新建埋点写入接口。

线索台账与现有 merchant_stall_leads(B 端摊位留资:name/phone/note 三字段)场景不同(C 端转化首页 CTA 意图预选 → 客服承接,带意图/来源/SLA/结果),故新建 crm_leads,不合并。


3. 新建表(sql/082_crm_leads.sql)

3.1 crm_leads(消费者 → 客服 线索)

CREATE TABLE IF NOT EXISTS crm_leads (
    id              BIGSERIAL    PRIMARY KEY,
    merchant_id     BIGINT       NOT NULL REFERENCES merchants(id),
    scene           VARCHAR(32)  NOT NULL DEFAULT 'unknown',   -- 来源点位 front/room/restaurant/platform/qr
    channel         VARCHAR(32)  NOT NULL DEFAULT 'merchant', -- 双入口 platform(平台码)/merchant(商户码)
    intent          VARCHAR(32),                             -- 住宿/准备/行程/未定
    page_id         VARCHAR(64),                             -- 触发页面
    contact         TEXT,                                    -- 联系方式(可选)
    status          VARCHAR(16)  NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','replied','accepted','invalid')),
    first_reply_at  TIMESTAMPTZ,                             -- SLA 计时锚点
    outcome         VARCHAR(16) CHECK (outcome IS NULL OR outcome IN ('accepted','invalid','follow_up')),
    operator_id     BIGINT,                                  -- 承接客服
    is_test         BOOLEAN      NOT NULL DEFAULT FALSE,
    created_at      TIMESTAMPTZ  NOT NULL DEFAULT now(),
    updated_at      TIMESTAMPTZ  NOT NULL DEFAULT now()
);
-- 索引:merchant_id+created_at / status+created_at / channel+created_at / is_test

3.2 crm_sla_config(SLA 配置,商户参数化,运营参数后台可配)

CREATE TABLE IF NOT EXISTS crm_sla_config (
    id                  BIGSERIAL    PRIMARY KEY,
    merchant_id         BIGINT       NOT NULL REFERENCES merchants(id),
    first_reply_minutes INTEGER      NOT NULL DEFAULT 10,   -- 未响应提醒时限
    escalate_minutes    INTEGER      NOT NULL DEFAULT 120,  -- 超时升级时限
    escalate_to         VARCHAR(64),                        -- 升级提醒对象(后台配置)
    is_test             BOOLEAN      NOT NULL DEFAULT FALSE,
    created_at          TIMESTAMPTZ  NOT NULL DEFAULT now(),
    updated_at          TIMESTAMPTZ  NOT NULL DEFAULT now(),
    UNIQUE (merchant_id)
);

SLA 引擎:MVP 用台账页查询时实时计算(now()-created_at 比对配置阈值),不加 cron / 定时任务,降复杂度。后续要主动推送再上定时任务。


4. 后端接口(app/routers/crm.py,注册于 main.py)

方法路径鉴权说明
POST/api/miniapp/crm/leads匿名可写(user 可空)C 端创建线索,body 带 merchant_id/scene/channel/intent/page_id/contact/is_test
GET/api/admin/crm/leadsstaff/adminA 端台账,筛选 merchant_id/status/channel/include_test,返回含 sla_state 实时状态(normal/overdue/escalated/done)
PATCH/api/admin/crm/leads/{id}staff/admin标记 status/outcome/operator_id/first_reply_at;状态进入 replied/accepted 且原无首响则自动记 first_reply_at=now()
GET/api/admin/crm/sla-config?merchant_id=staff/admin读 SLA,未配置返回默认值(default:true)
POST/api/admin/crm/sla-configadminupsert SLA(运营参数)
GET/api/admin/crm/funnel?days=&scene=&channel=&merchant_id=&include_test=staff/admin转化漏斗,基于 analytics_events 聚合 5 类事件 + 来源分布

响应体:沿用全局 ResponseWrapperMiddleware({ok,data})。安全:全部 SQL 参数化(asyncpg $1),创建/配置前校验 merchant_id 存在。


5. 埋点约定(前端 v3 调现有 POST /api/admin/track/event)

接口已存在(匿名可写)。前端只需按约定 event_name + properties 上报,后端零改动:

event_nameproperties 字段对应指标
page_enterscene, channel, page_id双入口流量分布
intent_selectintent(stay/prepare/trip/unknown)意图选择分布
cs_clickscreen, chapter_id北极星:首屏→客服点击率
chapter_viewchapter_id, dwell章节流失点
merchant_entermerchant_id, src商户页进入率

6. A 端页面(admin-console)


7. 部署

  1. 建表:staging + prod 两库执行 sql/082_crm_leads.sql(幂等 IF NOT EXISTS)
  2. 后端:部署 kailash-app(staging + prod)——app/routers/crm.py 新模块,main.py 已注册
  3. 前端:admin-console npm run build → 同步 dist 到 a.kailashi.cn(nginx /srv/kailash/nginx/html/adminconsole)

8. 验证(部署后回填)