Skip to content

运营数据指标与归因体系 · 技术实现方案

版本:v2.1(去归因,聚焦自动化 EDM) | 更新:2026-07-09 配套:运营数据指标与归因体系.md v2.1(口径)、eladmin-运营看板原型.html(产品形态,一期/二期已分组) v2.1 变化:砍掉归因(t_ops_action_result 表、对照组/A-B 分组、归因任务)。依据:生命周期触发邮件是金融行业基本功,不是实验对象;当前体量下 uplift 统计上测不出(检测 2pp 差异需每组数千样本)。保留 action_log(频控依据+不可回算)、实时响应率(运营故障报警,非因果证明)、EDM 事件(渠道健康+合规硬要求)。恢复条件:接入真金白银激励需算 ROI 时。 v2.0 变化:新表 11 → 6 张(v2.1 后为 5 张),定时任务 6 → 3 个(v2.1 后为 2 个),实时查询为主。


0. 关键前提(已核对代码)

0.1 大小写已定论

生产 CardStatisticsMapper.xml 实际使用小写 intent='charge' / status='posted'。本方案所有交易 SQL 统一小写。上线前跑 SELECT DISTINCT status,intent FROM t_user_card_transaction_utgl LIMIT 20 终确认。ATM 识别:authorization_obj LIKE '%"type":"ATM"%'

0.2 工程约定(新代码必须遵循)

位置命名 / 注解
定时任务wallet-front-api/.../svc/schedule/ops/XxxTask.kt@Component + @Scheduled(cron)(@EnableScheduling 只在 FrontApiApplication)
实体/Mapper/DALwallet-front-dal/.../modular/ops/@TableName+@TableId(AUTO)extends BaseMapper;复杂聚合走 XML <select>IXxxDalService/Impl
eladmin 接口eladmin-wallet/.../modules/ops/rest//api/eladmin/ops/*@PreAuthorize("@el.check('ops:x')") + @Log(经 wallet-rpc→wallet-front-dal 传递依赖复用 DAL)
公网追踪接口wallet-front-api收件人点击来自公网,不能放 eladmin;复用 GlobalRateLimitFilter
DDL手动执行(无 Flyway)建表脚本纳入 docs/sql/(stat_*.sql / ops_*.sql,按表前缀命名) 版本管理

1. 数据流 v2.0(实时为主,三条路径)

     源业务表(已存在):t_user_info / t_user_identity_audit_master /
     t_user_card / t_user_card_transaction_utgl / t_agency / t_user_asset

  ┌─────────┼──────────────────────┬───────────────────────┐
  │(A) 实时查询【主路径】            │(B) 日更计数表【仅1张】    │(C) 动作与EDM【准实时】
  │漏斗(cohort口径)/六张行动名单/    │t_stat_agent_daily        │t_ops_action_log
  │留存cohort/沉睡分层/高余额低频    │(只存分子分母计数)         │t_ops_email_template/event/suppression
  │——全部可回算,直查源表            │排行/趋势/沉睡代理检测      │响应率/邮件事件均实时查
  └─────────┴──────────────────────┴───────────────────────┘

          eladmin 查询接口(/api/eladmin/ops/*)+ wallet-front-api 公网追踪端点
  • (A) 是主路径:留存/沉睡/漏斗全部由时间戳回算(0.4 见指标文档),当前体量直查源表足够快,不建表。查询变慢再物化(附录恢复条件)。
  • (B) 只建一张代理日计数表:排行/趋势要按天对比,且"当日归属代理"是快照性质(用户可能换代理)。
  • (C) 动作日志不可回算(不记就永远没有),第一天就建;响应率 = action_log ⋈ 源表实时算,不建结果表、不跑归因任务

2. 表设计(5 张 DDL)

前缀按性质区分:数据统计类用 t_stat_(与既有 t_stat_card 同族,如 t_stat_agent_daily);运营动作/EDM 类用 t_ops_(action_log / email 三表)。同库,日期字段 INT YYYYMMDD

2.1 t_stat_agent_daily — 代理每日计数(唯一的聚合表)

只存分子分母计数,不存比率——比率在查询时按所选窗口 SUM(分子)/SUM(分母) 现算(日比率不能平均;小代理单日比率无意义)。

sql
CREATE TABLE t_stat_agent_daily (
  id                BIGINT PRIMARY KEY AUTO_INCREMENT,
  stat_date         INT NOT NULL COMMENT '统计日 YYYYMMDD',
  agency_id         BIGINT NOT NULL COMMENT '0=全平台汇总',
  -- 规模计数(当日新增)
  reg_cnt           INT DEFAULT 0 COMMENT '新增注册(人)',
  kyc_submit_cnt    INT DEFAULT 0 COMMENT '新增KYC提交(人)',
  kyc_approve_cnt   INT DEFAULT 0 COMMENT '新增KYC通过(人)',
  card_apply_cnt    INT DEFAULT 0 COMMENT '新增申请卡',
  card_produce_cnt  INT DEFAULT 0 COMMENT '新增制卡',
  card_active_cnt   INT DEFAULT 0 COMMENT '新增激活',
  card_firstuse_cnt INT DEFAULT 0 COMMENT '新增首刷',
  -- 价值(当日)
  charge_amt        DECIMAL(20,4) DEFAULT 0 COMMENT '消费GMV(posted charge,北极星)',
  charge_cnt        INT DEFAULT 0,
  topup_amt         DECIMAL(20,4) DEFAULT 0 COMMENT '充值(先行指标,不并入GMV)',
  withdraw_amt      DECIMAL(20,4) DEFAULT 0,
  active_card_cnt   INT DEFAULT 0 COMMENT '当日有消费的卡数',
  -- 风控计数(比率查询时算,分母<30不评估)
  declined_cnt      INT DEFAULT 0,
  txn_cnt           INT DEFAULT 0 COMMENT '总笔数(拒付率分母)',
  create_time       DATETIME DEFAULT CURRENT_TIMESTAMP,
  update_time       DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_date_agency (stat_date, agency_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='代理每日计数(只存分子分母)';

2.2 t_ops_action_log — 运营动作日志(频控依据 + 不可回算,第一天就建)

sql
CREATE TABLE t_ops_action_log (
  id                 BIGINT PRIMARY KEY AUTO_INCREMENT,
  card_id            BIGINT COMMENT '作用的卡',
  user_id            BIGINT,
  agency_id          BIGINT COMMENT '归属代理(快照,防换代理)',
  action_type        VARCHAR(32) NOT NULL COMMENT 'ACTIVATE_NUDGE/FIRST_USE_NUDGE/REACTIVATE/KYC_ASSIST/RESUBMIT_PUSH/OPEN_CARD_NUDGE',
  channel            VARCHAR(20) COMMENT 'EMAIL/SMS/TELEGRAM/MANUAL',
  operator           VARCHAR(64) COMMENT '执行人/系统/代理账号',
  batch_id           VARCHAR(64) COMMENT '活动批次',
  template_id        BIGINT COMMENT '使用的模板版本',
  send_status        VARCHAR(16) DEFAULT 'SENT' COMMENT 'SENT/SKIPPED(频控拦截)/FAILED',
  incentive_type     VARCHAR(32) COMMENT '预留:激励类型(券/费率减免)',
  incentive_cost     DECIMAL(20,4) COMMENT '预留:激励成本(日后接激励算ROI用)',
  target_metric      VARCHAR(32) COMMENT 'ACTIVATION/FIRST_USE/RETENTION(决定响应率判定口径)',
  card_status_before VARCHAR(32) COMMENT '动作时卡状态快照',
  create_time        DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '响应率窗口起点',
  KEY idx_card (card_id),
  KEY idx_batch (batch_id),
  KEY idx_type_time (action_type, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运营动作事件日志';

v2.1 已移除 group_type(对照组分组)列——不做 A/B,全部 100% 发送。日后接入付费激励需要 uplift 时 ALTER TABLE 加回即可。

2.3 EDM 三表(模板 / 事件 / 压制)

sql
CREATE TABLE t_ops_email_template (
  id            BIGINT PRIMARY KEY AUTO_INCREMENT,
  template_code VARCHAR(64) NOT NULL,
  action_type   VARCHAR(32) NOT NULL,
  lang          VARCHAR(8) DEFAULT 'zh' COMMENT 'zh/en',
  version       INT DEFAULT 1,
  subject       VARCHAR(255) NOT NULL,
  body_html     MEDIUMTEXT COMMENT '占位符 ${cardTailNo}/${balance}/${activateUrl}',
  enabled       TINYINT DEFAULT 1,
  create_time   DATETIME DEFAULT CURRENT_TIMESTAMP,
  update_time   DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_code_lang_ver (template_code, lang, version)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='EDM邮件模板';

CREATE TABLE t_ops_email_event (
  id          BIGINT PRIMARY KEY AUTO_INCREMENT,
  action_id   BIGINT NOT NULL COMMENT '关联 t_ops_action_log.id',
  event_type  VARCHAR(16) NOT NULL COMMENT 'OPENED/CLICKED/BOUNCED/UNSUBSCRIBED',
  event_time  DATETIME DEFAULT CURRENT_TIMESTAMP,
  ua          VARCHAR(255) COMMENT '过滤预取虚增',
  KEY idx_action (action_id),
  KEY idx_type_time (event_type, event_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='EDM邮件事件';

CREATE TABLE t_ops_email_suppression (
  id          BIGINT PRIMARY KEY AUTO_INCREMENT,
  email       VARCHAR(128) NOT NULL,
  reason      VARCHAR(32) COMMENT 'UNSUBSCRIBE/COMPLAINT/HARD_BOUNCE',
  create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
  UNIQUE KEY uk_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='EDM压制名单';

2.4 后置表(本期不建,日后启用时的变更要点)

后置原因启用时必须的改动
t_ops_action_result + 对照组机制生命周期邮件是基本功不做实验;当前体量 uplift 统计上测不出恢复条件=接入付费激励(券/费率减免)需算 ROI;届时 action_log 加回 group_type 列、恢复 hash 分组与归因任务
t_stat_card_daily沉睡/留存可回算,实时查够用瘦身为只存不可回算字段:balance / card_status / agency_id 快照
t_stat_funnel_daily漏斗实时查;KYC 积压趋势暂用当前快照改存当日新增数而非累计(累计可加总得出,反之不行);补 KYC 各状态积压快照列
t_stat_retention_cohort完全可回算仅当查询慢时作为物化缓存
t_ops_anomaly_rule/hit代理少,人工看记分卡即可规则表加 min_denominator 分母保护列;auto_action 禁止 FREEZE_COMMISSION,仅允许 NUDGE 类

3. 计算逻辑

3.1 实时接口 SQL 要点(路径 A,不建表)

  • cohort 漏斗(考核口径):按申请周分组,激活率 = COUNT(active_time <= create_time + 14d) / COUNT(*),只统计申请时间早于今天−14 天的"已成熟"cohort;快照累计口径(状态≥阶段)仅存量盘点接口用
  • 六张行动名单:直查 t_user_card + 反连接交易表;沉睡分层用 MAX(posted charge create_time) 距今天数;剔除 LOCKED/SUSPENDED 单列;分页在 SQL 内完成(修掉老接口先分页后过滤的缺陷)
  • 留存 cohort / 活跃趋势:按 active_time 分月 cohort × 窗口内 distinct 有消费卡——全历史可回算,上线即有完整热力图
  • 高余额×低频t_user_card ⋈ t_user_asset,balance > 阈值 AND 近 30 天 charge < 2 笔,按 balance 降序

3.2 t_stat_agent_daily(每日 upsert)

  • agency_id 聚合当日新增各计数 + 当日交易金额(posted charge / topup / withdraw 分列)
  • INSERT ... ON DUPLICATE KEY UPDATE(沿用 CardStatistics 惯例),另落一行 agency_id=0 全平台汇总
  • 排行接口读此表按窗口 SUM;沉睡代理检测 = 连续 4 周 SUM(reg_cnt)=0 的代理;新代理激活期 = t_agency.create_time 起算首个 reg/首个 active 的间隔(实时查)

3.3 响应率(实时查,无表无任务)

  • 定位:运营故障报警,不是因果证明——发了 500 封催激活窗口内 0 人激活 = 链接挂了/进垃圾箱/落地页撞登录墙,这才是它要抓的问题
  • 按 batch_id / action_type / template_id 分组:响应率 = 窗口内达成数 / SENT 数(ACTIVATION=active_time 落窗口;FIRST_USE/RETENTION=窗口内 posted charge),action_log ⋈ 源表实时算
  • 分母只取 send_status='SENT'(SKIPPED/FAILED 不进分母)
  • ⚠️ 展示处固定标注"响应率含自然转化,不代表动作净效果",防止被当成 ROI 汇报

3.4 EDM 指标

  • 打开率/点击率/退订率分母 = channel='EMAIL' AND send_status='SENT'
  • 事件采集见 §6.3;与响应率并排展示:点击高但响应低 → 落地承接有问题;点击低 → 文案/送达有问题
  • 退订率/硬退信率是合规监控红线:单批退订 >1% 或硬退信 >2% 立即停发排查(发件域名声誉殃及验证码邮件)

3.5 对账与水位线(OpsReconcileTask)

  • 日对账:agent_daily 各计数总和 vs 源表按日现算,偏差 >1% 告警——指标被抓到一次不准,信任就崩
  • 内审积压水位线COUNT(card_account_status='PENDING_REVIEW') > X 或较昨日 +50% → 消息中心告警内部审核负责人(防雪崩,非考核)

4. 定时任务(2 个,wallet-front-api/svc/schedule/ops/)

任务Cron职责
OpsAgentDailyTask0 20 1 * * ?(1:20,避开 CardStatisticsTask 1:00)upsert t_stat_agent_daily
OpsReconcileTask0 40 2 * * ?日对账 + 内审积压水位线告警

骨架沿用 CardStatisticsTask:@Component + @Scheduled(cron),复杂聚合放 Mapper XML。


5. 接口清单

5.1 eladmin 查询接口(modules/ops/rest/,权限点 ops:*)

接口数据源类型
/api/eladmin/ops/funnel实时 cohort 漏斗 + KYC 两段快照A 实时
/api/eladmin/ops/list/{type}六张行动名单(分页 SQL 内完成)A 实时
/api/eladmin/ops/retention留存 cohort + 活跃趋势(回算)A 实时
/api/eladmin/ops/agent/rank分层排行(甲/乙联赛,窗口 SUM 现算比率)B
/api/eladmin/ops/agent/lifecycle新代理激活期名单 + 沉睡代理名单 + 集中度A+B
/api/eladmin/ops/action/log (POST)人工动作/一键触达写日志C
/api/eladmin/ops/action/stats响应率(batch/action_type/模板维度,实时算)A 实时
/api/eladmin/ops/email/template (CRUD)模板管理(版本化+启停)CRUD
/api/eladmin/ops/email/stats批次打开/点击/退订率B

5.2 公网追踪端点(wallet-front-api,HMAC 验签防遍历刷数据)

端点行为
GET /t?aid=&sig=验签 → 写 CLICKED → 302 到落地页(激活页/用卡指引,深链+短时效免密会话,别让登录墙杀掉转化)
GET /e/o/{aid}.png写 OPENED → 返回 1×1 透明 PNG
GET /e/unsub?aid=&sig=写 suppression + UNSUBSCRIBED → 退订成功页

6. 触达接入点

6.1 发送前置校验 canSend(cardId, actionType)(全部查已有表,零额外成本)

  1. 收件地址在 suppression → 拒发
  2. 该用户 7 天内已有 SENT 运营邮件 → 拒发(全局频次)
  3. 同卡同 action_type 30 天内已发 → 拒发(冷却)
  4. 该卡 7 天内已被代理触达 → 平台不发(权属去重,代理动作也须写 action_log)
  5. 同卡命中多名单 → 只发最高优先级(补件>激活>首刷>唤醒)
  6. 卡 LOCKED/SUSPENDED/风控审查中 → 拒发 拦截的记 send_status='SKIPPED' 入 action_log(留痕,不进响应率分母)。

6.2 不做 A/B 分组(v2.1 决策)

  • 所有动作 100% 发送,不留对照组、代码不做 hash 分组——生命周期触发邮件是基本功,不是实验对象;当前体量 uplift 也测不出统计显著
  • 文案好坏用同 action_type 不同模板版本的响应率/点击率对比粗判(非严格实验,够用)
  • 恢复条件见 2.4:接入付费激励需算 ROI 时再加回

6.3 写入位置

  • 系统触达:调 IMessageSendCenterService 处同步 INSERT action_log(渲染模板记 template_id)
  • 人工/代理动作:eladmin 与 wallet-pc 的"触达/标记回访"按钮 → POST /ops/action/log
  • 触达权属:t_agency 维度配置触达策略(平台代发/代理自发/双发仲裁),上线前与头部代理通气

7. 分阶段路线(与指标文档 v2.0 第 5 章一致)

阶段交付任务接口
P0大小写终确认
P1实时漏斗 + 六张行动名单funnel, list/{type}, retention
P2EDM 触达闭环 + 响应率监控action_log, email×3action/log, action/stats, email/*, 公网×3
P3代理记分卡 + 排行 + 生命周期agent_dailyOpsAgentDailyTaskagent/rank, agent/lifecycle
P4对账 + 水位线OpsReconcileTask—(告警走消息中心)
后期归因(接激励时)/异常引擎/趋势表/卡快照/RFM/wallet-pc见 2.4视体量复用+agencyId 过滤

8. 风险与注意事项

  1. 大小写:上线前实测一次,错则所有交易指标归零。
  2. 成熟期偏差:cohort 接口必须只返回"已成熟"的 cohort(申请日 ≤ 今天−窗口),否则最近一周永远"看起来在恶化"。
  3. 小样本:比率类展示时分母 <30 标灰不参与排名/告警。
  4. 响应率误读:响应率含自然转化,只作运营健康监控,不得当"动作净贡献/ROI"汇报——展示处固定标注。
  5. GMV 双计:charge 与 topup 分列,任何"总额"展示不得相加;北极星只认 charge。
  6. 触达权属:平台直触前必须过代理策略配置——这是渠道政治问题,技术挡不住投诉。
  7. EDM 合规:退订链接硬底线;运营邮件被举报会殃及同域名的验证码/通知邮件;像素打开率只看趋势;送达痛点直接换 ESP 不自建。
  8. 银盛:上线前交易 SQL 扩为 UTGL UNION 银盛表,预留 channel 维度。
  9. agency 快照:action_log 与 agent_daily 都存当时的 agency_id,防换代理导致历史错乱。
  10. 时区:stat_date 与交易 create_time 口径统一(现有任务用服务器本地日期)。
  11. DDL:无 Flyway,脚本入 docs/sql/(stat_*.sql / ops_*.sql,按表前缀命名),发布手动执行并记录。

9. 交付物汇总 v2.1

  • 新增表 5 张:t_stat_agent_daily(只存计数)、t_ops_action_log(含 template/send_status/incentive 列,无对照组列)、t_ops_email_template、t_ops_email_event、t_ops_email_suppression
  • 定时任务 2 个:OpsAgentDailyTask / OpsReconcileTask(对账+水位线)
  • 实时接口为主:漏斗/名单/留存/响应率全部直查源表(可回算),不建预聚合表、不建归因结果表
  • 公网追踪 3 端点:/t 点击 302、/e/o 像素、/e/unsub 退订(wallet-front-api,HMAC 验签)
  • 接入:canSend 六条前置校验(含代理触达去重)+ 模板渲染,所有动作 100% 发送
  • 已砍/后置:action_result+对照组/归因(恢复条件=接付费激励)、card_daily、funnel_daily、retention_cohort、anomaly 两表、RFM、时延 P90(详见 2.4 与指标文档 6.1)

本方案贴合现有代码约定,可直接拆分为 P1-P4 工程任务排期。