Files
shaguabijia-app-server/docs/api/admin-ad-revenue-report.md
T
zhuzihao b622f76a02 feat(ad-revenue): 接入穿山甲 GroMore 数据 API 拉取后台收益(预估+收益API) (#92)
- 新增穿山甲 GroMore「聚合数据报告 API」对接,按天 T+1 拉取后台 revenue(预估)与
  api_revenue(收益API,更接近结算),在广告收益报表大盘 + 按天趋势级展示,与客户端自报
  eCPM 折算的预估并列对照;逐条广告事件行不动(仍是客户端预估)。
- 链路:integrations/pangle_report.py(MD5 签名,与官方文档两个测试向量逐字节一致)→
  scripts/sync_pangle_revenue.py(拉昨天/--days 回补)→ 新表 ad_pangle_daily_revenue
  (repositories/ad_pangle_revenue.py:upsert + 按日聚合)→ admin/repositories/ad_revenue.py
  汇总,新增 total_pangle_revenue_yuan / total_pangle_api_revenue_yuan / daily[].pangle_*。
- 穿山甲无用户/类型/场景维度:仅全量视图(未按 user/ad_type/feed_scene 过滤)给值,否则置
  None;join key 用 ad_unit_id(=客户端配的 104xxx),非 code_id。
- 新增配置 PANGLE_REPORT_USER_ID/ROLE_ID/SECURITY_KEY(≠发奖 m-key)+ site_id→应用映射;
  含单测(签名向量+分页解析);已真连穿山甲验证。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: zzhyyyyy <2685922758@qq.com>
Reviewed-on: #92
Co-authored-by: zhuzihao <zhuzihao@wonderable.ai>
Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
2026-06-29 09:54:13 +08:00

11 KiB
Raw Blame History

Admin 广告收益报表

所属:Admin 组(前缀 /admin/api/ad-revenue-report) | 鉴权:Admin Bearer(任意已登录 admin,只读) | ← 返回 API 索引

用户 × 日期 × 广告类型 × 我们的应用 × 我们的代码位 聚合,回答「每个用户某天、每类广告(激励视频 / 信息流 / 历史 Draw)分别看了多少条收益多少、按现算法发了多少金币、广告来自哪个应用的哪个代码位」。纯只读,不发币、不改数据,也不改发奖逻辑

相关表:ad_ecpm_recordad_reward_recordad_feed_reward_record

数据来源(三流合并,聚合键 = user × ad_type × app_env × our_code_id)

指标 来源表 口径
展示条数 impressions ad_ecpm_record 每行 = 客户端一次广告展示。激励视频每次展示上报一条;信息流轮播每条展示各上报一条(每条独立 ad_session_id)
收益 revenue_yuan ad_ecpm_record Σ(eCPM元 ÷ 1000),即每条展示预估收益累加(eCPM 原值是分,÷100 转元;÷1000 是每千次→单次)。预估口径,非结算;测试应用多为 0
应发/实发金币 expected_coin/actual_coin ad_reward_record(reward_video)+ ad_feed_reward_record(feed) 复用金币审计逐条复算(ad_audit.audit_rows,与正式发奖同一公式口径,不另写公式),按同维度求和;matched = 应发==实发只读复算,不改发奖
来源应用/代码位 app_env/our_code_id 上述各表回填 prod(傻瓜比价)/test(测试);代码位是我们后台配的 104xxx,非底层 rit
底层渠道 adns ad_ecpm_record 实际填充的 ADN 子渠道集合(pangle/gdt/...),附加参考

展示与金币来自不同表,做并集:有展示无金币(用户中途关、未达发奖)、有金币无展示(未上报 eCPM)各自成行。

GET /admin/api/ad-revenue-report — 聚合报表

  • 入参(均 query,可选):

    参数 类型 默认 说明
    date_from string 今天 起始日 北京时间 YYYY-MM-DD
    date_to string =date_from 结束日 北京时间 YYYY-MM-DD,闭区间;单日时与 date_from 相同
    user_id int 全部 只看某用户;不传=所有用户
    ad_type string 全部 reward_video / feed / draw;不传=全部类型
    feed_scene string 全部 comparison(比价)/ coupon(领券)/ welfare(福利);全局筛选,同时作用于明细 / 合计 / daily·hourly 趋势;不传=全部场景
    granularity string day day=按天 / hour=按小时(聚合键再加北京时间小时 0–23);区间>1 天建议用 day
    limit int(1~1000) 500 每页条数(分页大小);total/total_*/daily/hourly 按全量统计不受分页影响
    offset int(≥0) 0 分页偏移(已跳过条数)=(页码−1)×limit
    sort string time 明细排序:time=按时间倒序(新→旧) / ecpm=按 eCPM 数值倒序

    约束:date_to 不早于 date_from、区间最长 92 天、日期须 YYYY-MM-DD,否则 422

  • 出参 200:AdRevenueReportOut

    字段 类型 说明
    date_from / date_to string 报表起止日期(闭区间)
    daily AdRevenueDaily[] 按日期汇总序列(全量,供按天趋势图;不受分页影响)
    hourly AdRevenueHourly[] 按小时汇总序列(全量,供按小时趋势图;granularity=hour 时非空;不受分页影响)
    type_stats {[ad_type]: AdRevenueTypeStat} 按广告类型(ad_type)小计(全量);前端取 draw / reward_video 做分类大盘
    dau int | null 今日活跃用户数(复用大盘口径 last_login_at,今日登录过);仅查询=今日单天时有值,历史/多天为 null
    total int 当前筛选下的分页总条数(全量,不受分页影响;= 前端分页器 total)
    truncated bool 当前页之后是否还有更多事件(len(events) > offset + limit)
    total_impressions int 全量展示条数合计
    total_revenue_yuan float 全量客户端预估收益合计(元;eCPM 折算)
    total_pangle_revenue_yuan float | null 全量穿山甲后台预估收益合计(元;GroMore revenue)。穿山甲无用户/类型/场景维度,仅全量视图(未按 user_id/ad_type/feed_scene 过滤)有值,否则 null
    total_pangle_api_revenue_yuan float | null 全量穿山甲收益Api合计(元;GroMore api_revenue,各 ADN 回传更接近结算);未配 Reporting / 查当天 / 非全量视图为 null
    pangle_revenue_available bool 本次是否带穿山甲后台收益(=全量视图且对应日期已同步到 ad_pangle_daily_revenue)
    total_expected_coin int 全量应发金币合计
    total_actual_coin int 全量实发金币合计
    mismatch_count int 应发≠实发的组数(=0 说明全部按公式发放)
    items AdRevenueRow[] 逐条广告事件(按时间倒序:新→旧);limit/offset 对全量做分页切片,返回当前页

AdRevenueDaily(daily[] — 按天趋势)

字段 类型 说明
date string 北京时间 YYYY-MM-DD
impressions int 当天展示条数合计
revenue_yuan float 当天客户端预估收益合计(元;eCPM 折算)
pangle_revenue_yuan float | null 当天穿山甲后台预估收益(元;GroMore revenue);非全量视图 / 无数据为 null
pangle_api_revenue_yuan float | null 当天穿山甲收益Api(元;GroMore api_revenue);未配 / 当天 / 无数据为 null
expected_coin int 当天应发金币合计
actual_coin int 当天实发金币合计

AdRevenueHourly(hourly[] — 按小时趋势,仅 granularity=hour 时非空)

字段 类型 说明
hour int 北京时间小时 023
impressions int 该小时展示条数合计
revenue_yuan float 该小时预估收益合计(元)
expected_coin int 该小时应发金币合计
actual_coin int 该小时实发金币合计

AdRevenueTypeStat(type_stats[ad_type] — 分广告类型小计,供大盘第二行)

字段 类型 说明
impressions int 该类型展示条数合计
revenue_yuan float 该类型预估收益合计(元);eCPM 由前端用 收益÷展示×1000 算

AdRevenueRow(items[])

字段 类型 说明
report_date string 该组所属日期 北京时间 YYYY-MM-DD
user_id int
ad_type string reward_video / feed / draw
app_env string | null 我们的应用:prod(傻瓜比价)/test(测试);旧数据为空
our_code_id string | null 我们配置的代码位 104xxx;旧数据为空
hour int | null 北京时间小时 023(granularity=hour 时有值;按天为 null)
impressions int 展示条数
revenue_yuan float 收益(元),预估口径
expected_coin int 应发金币(公式复算,与金币审计同源)
actual_coin int 实发金币(实际入账)
matched bool 该组应发==实发(组内任一条不符则 false)
adns string[] 底层填充 ADN 子渠道集合
impression_records AdRevenueImpression[] 该组逐条展示明细(前端展开下钻);只要有展示就非空
records AdRevenueRecord[] 该组逐条发奖复算明细(前端展开下钻);纯展示无发奖的组为空

AdRevenueImpression(items[].impression_records[] — 展开「展示明细」)

字段 类型 说明
id int ad_ecpm_record 主键
created_at datetime
ecpm string 本次展示 eCPM 原始值(分/千次展示)
revenue_yuan float 本次展示预估收益(元)= eCPM元 ÷ 1000
adn string | null 实际填充 ADN 子渠道
slot_id string | null 底层 mediation rit(非我们配置的广告位 ID)

AdRevenueRecord(items[].records[] — 展开「发奖明细」)

还原金币审计的逐条列,与发奖同一复算口径。

字段 类型 说明
record_id int 发奖记录主键
created_at datetime
status string granted / capped / ecpm_missing
ecpm string | null 本次采用的 eCPM 原始值
ecpm_factor float | null 因子1(eCPM 档);非 granted 为空
units int 折算份数:激励视频恒 1;信息流 = 满 10 秒份数
lt_index_start / lt_index_end int | null 占用「账号累计第几份」的起止
lt_factor_start / lt_factor_end float | null 因子2(LT)起止值
expected_coin int 应发金币
actual_coin int 实发金币
matched bool 该条复算与实发是否一致

说明与局限

  • 展示 vs 发奖分离:信息流轮播一会话可展示多条(都计入 impressions),但发奖仍按现规则(一会话发一次),coin 不因展示条数变化——这是有意设计(用户中途关只记展示不发奖)。
  • 历史 Draw 不可拆:迁移(Draw→普通信息流)前,Draw 发奖混在 ad_feed_reward_record 且无类型标记,金币侧统一记 feed;迁移后 Draw 不再产生新数据。展示侧 ad_type 由客户端上报区分,故 draw 桶基本为空。
  • 来源字段从上线起齐全:app_env/our_code_id 是本期新增列,历史记录为 NULL(报表来源列留空)。
  • 逐条/明细的收益是预估:items[].revenue_yuan 基于客户端上报的 eCPM 折算,非穿山甲后台结算值。
  • 穿山甲后台收益(汇总/趋势级):total_pangle_revenue_yuan(预估 revenue)与 total_pangle_api_revenue_yuan(收益Api api_revenue,更接近结算)来自穿山甲 GroMore 数据 API(integrations/pangle_report + scripts/sync_pangle_revenue 按天 T+1 拉取入 ad_pangle_daily_revenue)。穿山甲不提供分用户/设备/类型/场景维度(官方明确),最细到 日期×应用×代码位,故只用于汇总与按天趋势的对照,不挂到逐条事件行;且仅在全量视图(未按 user/类型/场景过滤)展示。配置见 .envPANGLE_REPORT_*
  • 对账聚合级 + 逐条下钻:行级 matched 给出该组(用户×类型×应用×代码位)应发是否==实发;展开 records 即可看该组逐条明细(eCPM/因子1/份数/LT/因子2/应发/实发/一致)定位到具体记录。独立逐条审计接口 admin-ad-coin-audit 仍保留(同一复算口径,可全局按场景/只看不符筛选)。