跳到内容

自营广告

受众:开发者 / 运营 摘要:Advertising 模块首段能力:广告位、广告素材、素材审核、审核日志、审核超时提醒、素材版本快照、内容安全预检、后台管理 contract、公开展示 contract、Open Platform 广告 API、曝光 / 点击 / 转化事件、事件幂等 / 频控保护、基础报表、归因漏斗、风险素材摘要、来源风险摘要、日报快照、预算扣费结算、结算资金引用、第三方 Provider 骨架、运维诊断、本地 contract smoke、Provider 能力矩阵、Provider 收益报表拉取 / 受控导入、收益与本地扣费对账摘要、结算状态运营、自动结算入口、广告主结算 / 打款联动验收 runbook、权限种子和数据表。

spring-open-module-advertising 承载平台自营广告投放能力。第一阶段已完成广告位、广告素材、审批工作流、审核日志、审核超时提醒、素材版本快照、内容安全预检、后台投放页、公开展示接口、Open Platform 广告接口、曝光 / 点击 / 转化事件明细、requestId 幂等去重、短窗口同源频控、基础运营报表、归因漏斗、风险素材摘要、来源风险摘要、日报快照、素材预算、事件扣费流水、后台结算、结算资金 Provider / 引用号 / 幂等键、第三方广告 Provider 接入骨架、Provider 运维诊断入口、本地 contract smoke、Provider 能力矩阵、Provider 收益报表拉取 / 受控导入、收益与本地扣费对账摘要、自动结算入口和广告主结算 / 打款联动验收 runbook;广告主账户真实资金联动、具体厂商 SDK、真实跨渠道归因、真实设备指纹和真实第三方反作弊的外部验收按部署 runbook 执行。

广告模块不放入 CMS,也不放入 Mall。CMS 可以消费广告位展示结果,但广告投放、素材审核、预算、事件上报和第三方平台适配都归 Advertising 模块。

什么时候使用

适合这些场景:

  • 平台运营配置 App / PC / 内容页广告位。
  • 自营广告素材审核和启停。
  • 素材提审前复用 Content Safety 做可选预检,并在后台素材列表展示检测摘要。
  • 给 CMS、Blog、Forum、Mall 或自定义业务提供广告位展示结果。
  • 对自营广告素材配置预算,并按曝光或点击事件生成扣费流水。
  • 从已注册广告 Provider 拉取或手工导入已授权收益报表摘要,并由管理员推进 imported / reconciled / ignored 运营状态,或对 imported 报表执行受控自动结算,作为广告主结算和对账前的审计来源。
  • 在后台执行 Provider 本地 contract smoke,确认素材同步、收益拉取、跨渠道归因、设备指纹、第三方反作弊能力矩阵、账号配置引用和真实外部验收清单。
  • 将广告展示查询和事件上报开放给外部服务端应用,并统一复用 Open Platform 的 HMAC 签名、scope、限流、调用日志、用量事件和账单治理。
  • 发版或部署前执行 ./scripts/release advertising-settlement-acceptance --provider <provider>,记录 Provider 收益报表、本地预算扣费流水、外部交易引用、结算幂等键、风险复核和回滚预案。
  • 后续扩展广告主账户、资金对账、自动打款和具体第三方广告平台 Provider SDK。

不适合把它当成 CMS 内容块、商城商品推广模型或资金结算模块。素材文件继续复用 Storage 的媒体资产,内容安全预检复用 Content Safety Provider,资金相关能力后续复用 Money / Cashier。

模块边界

Maven 模块spring-open-module-advertising
公开 API 前缀/api/v1/promotion/**
Open Platform API 前缀/api/v1/open/advertising/**
后台 API 前缀/api/v1/admin/advertising/**
配置前缀spring.open.advertising.*
Java 包名com.springopen.module.advertising
数据表ad_slotad_creativead_creative_review_logad_creative_versionad_eventad_daily_reportad_budgetad_budget_ledgerad_provider_revenue_report
权限码前缀advertising:*

应用默认开启该模块,可通过配置关闭:

yaml
spring:
  open:
    advertising:
      enabled: true

公开曝光 / 点击 / 转化事件默认启用轻量保护:

yaml
spring:
  open:
    advertising:
      event-guard:
        enabled: true
        request-id-deduplication-enabled: true
        frequency-limit-enabled: true
        frequency-window: 1m
        max-impressions-per-window: 60
        max-clicks-per-window: 20
  • request-id-deduplication-enabled:同一广告位、素材、事件类型和 requestId 重放时返回既有事件,不重复写入明细,也不重复扣费。
  • frequency-limit-enabled:按广告位、素材、事件类型、IP 和 User-Agent 做短窗口频控;缺少 IP 和 User-Agent 时不拦截,避免误伤服务端转发或测试链路。
  • 这些保护只作为默认生产护栏,不替代更重的广告主风控、转化归因和第三方反作弊。
  • event-guard 配置键已由 AdvertisingServiceProvider 声明到 lifecycle 配置 schema,后台配置中心可以识别启用开关、requestId 去重、频控开关、频控窗口和窗口内曝光 / 点击阈值。

素材提审前默认启用内容安全预检:

yaml
spring:
  open:
    advertising:
      content-safety:
        enabled: true
        fail-on-unavailable: false
        fail-on-error: false
        reject-on-unsafe: true
  • enabled:提交广告素材审核前是否调用 Content Safety Manager。
  • fail-on-unavailable:Content Safety Manager 未装配或未返回检测结果时是否阻断提审;默认不阻断,避免未引入内容安全 Provider 的部署无法运营广告素材。
  • fail-on-error:内容安全检测异常时是否阻断提审;默认不阻断,异常摘要会记录到素材检测字段。
  • reject-on-unsafe:检测结果建议拒绝时是否自动驳回并停用素材;默认开启。
  • Advertising 只调用 Content Safety 统一 contract,不内置具体厂商 SDK。真实厂商、模型或规则由 Content Safety 模块的 Provider 配置负责。

数据表

当前主要数据表均带中文备注,方便数据库排查:

说明
ad_slot自营广告位,保存广告位编码、终端、场景、尺寸、最大展示数量、兜底素材和状态
ad_creative自营广告素材,保存所属广告位、素材编码、标题、图片 / 媒体资产、跳转目标、展示窗口、审核状态和内容安全预检摘要
ad_creative_review_log广告素材审核日志,保存提审、人工通过、人工驳回和内容安全自动驳回的前后状态、操作人、备注和内容安全摘要
ad_creative_version广告素材版本快照,保存创建和修改时的素材内容、跳转目标、展示窗口、状态、操作人和发生时间
ad_event广告曝光 / 点击 / 转化事件明细,保存广告位 / 素材快照、事件类型、请求追踪、客户端上下文和发生时间
ad_daily_report广告日报快照,按日期、广告位、素材、终端和场景幂等保存曝光、点击、转化、追踪缺失、重放和来源缺失指标
ad_budget广告预算,保存素材预算编码、总预算、日预算、已扣费、已结算、单次扣费、扣费事件类型和 Money / Cashier 外部引用
ad_budget_ledger广告预算扣费流水,保存预算、素材、事件、扣费金额、余额、结算状态、请求追踪、结算资金 Provider、引用号和幂等键
ad_provider_revenue_report第三方 Provider 收益报表导入记录,保存 Provider、报表编号、日期、账号、币种、收益、曝光、点击、转化、结算状态、来源文件、原始摘要、导入时间和导入人

ad_slot.code 全局唯一。ad_creativeslot_id + code 唯一,允许不同广告位复用同一个素材编码。ad_event 用于基础报表、轻量去重、频控和后续风控审计的原始明细;实时报表仍在应用侧基于事件明细轻量聚合,ad_daily_report 则用于后台手动或调度任务生成的运营日报快照。

ad_budget.code 全局唯一;当前首段一个广告素材最多绑定一个预算。ad_budget_ledger.event_id 唯一,用于保证同一公开事件最多生成一笔扣费流水。预算结算时可以写入 settlementProvidersettlementReferencesettlementIdempotencyKey,用于把 Advertising 结算批次关联到 Cashier、Money 或外部对账系统;未传幂等键时,后端按预算和日期范围生成稳定默认值。

ad_provider_revenue_reportprovider + report_no 幂等保存已授权第三方报表摘要。它只作为后续广告主结算、对账和人工复核的审计来源,不直接执行 Money / Cashier 入账、出账或打款。管理员可把记录标记为 reconciledignored,也可以重置为 imported 重新进入人工核对队列。

后台管理 API

后台接口需要登录并校验权限。

广告位

方法路径权限说明
GET/api/v1/admin/advertising/slotsadvertising:slot:view分页查询广告位
GET/api/v1/admin/advertising/slots/{id}advertising:slot:view查询广告位详情
POST/api/v1/admin/advertising/slotsadvertising:slot:create创建广告位
PUT/api/v1/admin/advertising/slots/{id}advertising:slot:update修改广告位
PUT/api/v1/admin/advertising/slots/{id}/statusadvertising:slot:update启用或停用广告位
DELETE/api/v1/admin/advertising/slots/{id}advertising:slot:delete删除广告位
DELETE/api/v1/admin/advertising/slotsadvertising:slot:delete批量删除广告位

创建请求示例:

json
{
  "code": "pc-home-banner",
  "name": "PC 首页横幅",
  "client": "pc",
  "scene": "home",
  "width": 1200,
  "height": 320,
  "maxItems": 3,
  "sortOrder": 100,
  "status": 1,
  "fallbackImageUrl": "https://example.com/fallback.png",
  "fallbackTargetUrl": "https://example.com",
  "remark": "首页首屏轮播"
}

status 使用统一启停语义:1 为启用,0 为停用。client 建议使用 pcappadminallscene 由业务自定义,例如 homearticle-detailmall-product

广告素材

方法路径权限说明
GET/api/v1/admin/advertising/creativesadvertising:creative:view分页查询广告素材
GET/api/v1/admin/advertising/creatives/{id}advertising:creative:view查询广告素材详情
POST/api/v1/admin/advertising/creativesadvertising:creative:create创建广告素材
PUT/api/v1/admin/advertising/creatives/{id}advertising:creative:update修改广告素材,修改后回到草稿状态
PUT/api/v1/admin/advertising/creatives/{id}/statusadvertising:creative:update启用或停用广告素材;启用前必须已审核通过
POST/api/v1/admin/advertising/creatives/{id}/review/submitadvertising:creative:update提交广告素材审核
POST/api/v1/admin/advertising/creatives/{id}/review/approveadvertising:creative:review审核通过广告素材
POST/api/v1/admin/advertising/creatives/{id}/review/rejectadvertising:creative:review驳回广告素材并停用
POST/api/v1/admin/advertising/creatives/review-timeouts/notifyadvertising:creative:review扫描待审核超时素材并幂等写入审核超时提醒日志
GET/api/v1/admin/advertising/creatives/{id}/review-logsadvertising:creative:view分页查询广告素材审核日志
GET/api/v1/admin/advertising/creatives/{id}/versionsadvertising:creative:view分页查询广告素材版本快照
DELETE/api/v1/admin/advertising/creatives/{id}advertising:creative:delete删除广告素材
DELETE/api/v1/admin/advertising/creativesadvertising:creative:delete批量删除广告素材

创建请求示例:

json
{
  "slotId": 1,
  "code": "spring-campaign-a",
  "title": "春季活动 A",
  "summary": "首页自营广告素材",
  "imageUrl": "https://example.com/material.png",
  "mediaAssetKey": 10001,
  "targetType": "url",
  "targetUrl": "https://example.com/campaign",
  "sortOrder": 100,
  "status": 1,
  "visibleAt": "2026-06-01T00:00:00",
  "expiredAt": "2026-06-30T23:59:59",
  "extraJson": "{\"utm\":\"spring\"}"
}

mediaAssetKey 用于绑定 Storage 媒体资产;imageUrl 可作为外部图片或过渡字段。公开展示接口只返回审核通过、启用且处于展示窗口内的素材。

审核日志由审核状态机自动写入:提交审核、人工通过、人工驳回、内容安全自动驳回和后台审核超时提醒都会记录到 ad_creative_review_log。后台素材页的“记录”按钮会展示动作、前后审核状态、操作人、备注、内容安全建议动作、风险等级、Provider 和检测原因。日志只做运营追溯和排障,不触发外部通知、资金动作或第三方广告平台同步。

版本快照由素材创建和修改自动写入:每次创建或修改都会在 ad_creative_version 记录当时的素材内容、跳转目标、展示窗口、状态、操作人和发生时间。后台素材页的“版本”按钮会展示历史版本,并支持选择两个版本对比素材字段差异,便于运营复盘素材内容变化;该记录不回滚素材、不同步第三方平台,也不触发资金动作。

报表看板

方法路径权限说明
GET/api/v1/admin/advertising/reports/summaryadvertising:report:view查询曝光、点击、转化汇总、事件质量、每日趋势、广告位排行和素材排行
GET/api/v1/admin/advertising/reports/dailyadvertising:report:view分页查询已生成的广告日报快照
POST/api/v1/admin/advertising/reports/daily/generateadvertising:report:generate按当前筛选范围幂等生成广告日报快照

查询参数:

参数说明
startDate / endDate日期范围,格式 YYYY-MM-DD;未传时默认近 7 天,开始日期晚于结束日期时后端会自动调换
slotCode按广告位编码过滤
creativeCode按素材编码过滤
client按终端过滤,例如 pcappadminall
scene按投放场景过滤

返回内容包含 totalEventsimpressionsclicksconversionsclickThroughRateconversionRateeventQualityattributionsourceRiskdailyMetricsslotMetricscreativeMetricsriskSignalssourceRisks。CTR / CVR 以百分比数值返回,例如 12.50 表示 12.50%

eventQuality 是轻量运营复核摘要,基于当前筛选范围识别缺失 requestId、重复 requestId、点击数大于曝光数的素材和转化数大于点击数的素材,并给出 normalwarningrisk 复核等级。它用于帮助运营快速发现疑似刷量、归因异常或接入方漏传追踪 ID,不替代更重的跨渠道归因和第三方反作弊系统。

attribution 是基于 requestId 的归因漏斗摘要,返回已归因 / 未归因事件、已归因 / 未归因转化、事件归因率和转化归因率。riskSignals 按广告位 + 素材聚合缺失追踪、重放事件、点击倒挂、转化倒挂、可疑占比和风险等级,方便运营直接定位需要复核的素材。该能力只基于平台自有事件明细,不伪装跨渠道归因或第三方反作弊结果。

sourceRisk 是基于事件明细中已记录的 IP 和 User-Agent 的来源风险摘要,返回独立 IP 数、独立 User-Agent 数、来源缺失事件数、高频 IP 数、高频 User-Agent 数、来源缺失率和整体风险等级。sourceRisks 按来源类型和来源值聚合事件、曝光、点击、转化、CTR、CVR 和风险等级,用于快速定位疑似同源刷量或接入方漏传来源字段。该能力不是设备指纹系统,也不替代第三方反作弊;真实设备指纹、跨渠道归因和厂商风控仍需要具体 Provider 或部署验收接入。

日报快照由 ad_event 幂等生成,幂等键为 reportDate + slotCode + creativeCode + client + scene。管理员可以在报表页按当前筛选条件手动生成并刷新列表;调度任务名称默认为 advertising.daily-report.generate,配置前缀为 spring.open.advertising.daily-report.*,默认启用能力但不自动注册周期任务,只有显式开启 auto-startup 后才交给 Scheduler 周期生成。该快照用于运营复盘、异步统计和后续结算对账,不替代实时事件明细、跨渠道归因或第三方反作弊。

预算扣费与结算

方法路径权限说明
GET/api/v1/admin/advertising/budgetsadvertising:budget:view分页查询广告预算
GET/api/v1/admin/advertising/budgets/{id}advertising:budget:view查询广告预算详情
POST/api/v1/admin/advertising/budgetsadvertising:budget:create创建广告预算
PUT/api/v1/admin/advertising/budgets/{id}advertising:budget:update修改广告预算
PUT/api/v1/admin/advertising/budgets/{id}/statusadvertising:budget:update启用或停用广告预算
GET/api/v1/admin/advertising/budgets/{id}/ledgersadvertising:budget:view分页查询预算扣费流水
POST/api/v1/admin/advertising/budgets/{id}/settleadvertising:budget:settle结算未结算扣费流水

创建预算请求示例:

json
{
  "creativeId": 10,
  "code": "budget-spring-campaign-a",
  "name": "春季活动 A 预算",
  "currency": "CNY",
  "totalAmount": 10000,
  "dailyAmount": 800,
  "unitPrice": 2,
  "chargeEventType": "conversion",
  "status": 1,
  "effectiveAt": "2026-06-01T00:00:00",
  "expiredAt": "2026-06-30T23:59:59",
  "payerAccountId": 30001,
  "cashierPaymentOrderId": 40001,
  "remark": "转化扣费"
}

扣费规则:

  • chargeEventType 支持 impressionclickconversion,默认 click
  • 公开曝光 / 点击 / 转化事件先写入 ad_event,再按素材 ID、事件类型、预算启停状态和有效期查找预算。
  • 同一 eventId 最多扣费一次。
  • 扣费金额按 min(unitPrice, totalAmount - spentAmount, dailyAmount - 当日已扣费) 计算。
  • 预算余额不足或日预算不足时不写扣费流水。
  • 新流水默认 settlementStatus=unsettled

结算请求可传日期范围、资金引用和备注:

json
{
  "startDate": "2026-06-01",
  "endDate": "2026-06-30",
  "settlementProvider": "cashier",
  "settlementReference": "cashier-settlement-1001",
  "settlementIdempotencyKey": "advertising:budget:settle:1001:2026-06-01:2026-06-30",
  "remark": "六月广告结算"
}

结算会把范围内未结算流水标记为 settled,写入 settledAtsettlementProvidersettlementReferencesettlementIdempotencyKey,并累计预算 settledAmount。如果未显式传入 settlementIdempotencyKey,后端会生成 advertising:budget:settle:{budgetId}:{startDate|all}:{endDate|all} 格式的稳定键,方便后续资金域或外部对账系统幂等关联。预算上的 payerAccountIdcashierPaymentOrderId 只保存 Money / Cashier 外部引用;当前公开展示链路不同步调用资金底座,真实广告主充值、自动对账和打款继续复用 Money / Cashier。

Provider 收益报表

方法路径权限说明
GET/api/v1/admin/advertising/revenue-reportsadvertising:revenue-report:view分页查询已导入 Provider 收益报表
GET/api/v1/admin/advertising/revenue-reports/reconciliation-summaryadvertising:revenue-report:view查询 Provider 收益与本地预算扣费流水对账摘要
POST/api/v1/admin/advertising/revenue-reportsadvertising:revenue-report:import受控导入 Provider 收益报表摘要
POST/api/v1/admin/advertising/revenue-reports/pulladvertising:revenue-report:import从已注册 Provider 拉取收益报表并复用导入链路幂等更新
POST/api/v1/admin/advertising/revenue-reports/{id}/settlement-statusadvertising:revenue-report:import更新收益报表结算状态
POST/api/v1/admin/advertising/revenue-reports/{id}/auto-settleadvertising:revenue-report:import幂等自动结算已导入收益报表

结算状态请求只推进运营状态,不执行资金出款:

json
{
  "settlementStatus": "reconciled",
  "remark": "已和平台后台日报核对"
}

settlementStatus 支持 importedreconciledignored。真实广告主出账、自动打款和资金对账继续复用 Money / Cashier 的独立功能簇。

自动结算请求只接受可选备注,并且只把 imported 报表推进为 reconciled;重复结算 reconciled 报表会幂等返回,ignored 报表不会被自动结算:

json
{
  "remark": "平台日报与广告主账单已匹配"
}

自动结算仍只记录运营状态和备注,不创建 Money / Cashier 资金流水,不触发真实打款。

拉取请求示例:

json
{
  "provider": "log",
  "startDate": "2026-06-01",
  "endDate": "2026-06-30",
  "accountCode": "ads-account-a",
  "remark": "按 Provider contract 拉取六月日报"
}

拉取规则:

  • provider 为空时使用默认 log Provider;默认 Provider 不触达外部网络,只生成可重复验证的 contract 快照。
  • 真实厂商 Provider 只需实现 AdvertisingProvider#pullRevenueReports,返回平台统一收益快照。
  • 拉取结果复用导入服务,继续按 provider + reportNo 幂等 upsert,避免重复拉取造成重复收益记录。
  • 拉取接口不读取或保存厂商密钥;真实凭据、外部账号和网络调用由具体 Provider 自己通过受控配置处理。

对账摘要用于把 Provider 收益报表与本地 ad_budget_ledger 扣费流水放在同一个运营视图中比较,返回 Provider 收益、本地扣费、已结算 / 未结算扣费、差异金额、差异比例和风险等级。该接口只读,不创建 Money / Cashier 资金流水,也不替代真实广告厂商账单下载、广告主自动结算或三方打款。

导入请求示例:

json
{
  "provider": "google",
  "reportNo": "RPT-20260624",
  "reportDate": "2026-06-24",
  "accountCode": "ads-account-a",
  "currency": "USD",
  "estimatedRevenue": 128.66,
  "impressions": 12000,
  "clicks": 860,
  "conversions": 42,
  "settlementStatus": "imported",
  "sourceFileName": "google-ads-20260624.csv",
  "remark": "已由运营人工确认来源",
  "rawSummary": "{\"source\":\"ops-import\"}"
}

导入规则:

  • provider 会规范为小写,reportNo 保留原始大小写。
  • 同一 provider + reportNo 重复导入时更新同一行,不新增重复记录。
  • estimatedRevenueimpressionsclicksconversions 不允许为负数。
  • settlementStatus 支持 importedreconciledignored
  • 后端记录当前管理员为 importedBy,便于审计来源。
  • 手工导入接口不调用外部厂商网络,也不直接写入 Money / Cashier 账本。

第三方广告 Provider 骨架

Advertising 模块提供第三方广告平台 Provider SPI,业务侧仍使用平台统一的广告位、素材、展示、事件和预算模型。Provider 只负责把平台素材同步到外部广告平台,不改变现有后台和公开展示 API。Admin 提供 Provider 运维入口,用于查看当前运行时注册的 Provider、默认 Provider、轻量健康摘要,并可执行本地 contract smoke,校验素材同步 dry-run、收益拉取 dry-run、账号配置引用和真实外部验收清单;该入口不编辑厂商密钥或外部广告账号。

当前内置默认 Provider:

Provider说明
log本地日志型 Provider,不调用外部平台,用于稳定 SPI、模块装配和后续厂商接入测试

核心入口:

  • AdvertisingProvider:第三方广告平台适配接口。
  • AdvertisingProviderManager:Provider 注册表和素材同步入口,默认使用 log
  • AdvertisingCreativeSyncCommand:从 AdvertisingCreative 映射出的素材同步命令。
  • AdvertisingCreativeSyncResult:Provider 同步结果,当前默认返回 accepted 状态。
  • AdvertisingProviderDiagnostic:Provider 轻量诊断快照,默认不触达外部网络,具体厂商 Provider 可覆写为受控健康检查。
  • AdvertisingProviderSmokeResult:Provider 本地 contract smoke 结果,返回本地 contract、账号配置、素材同步、收益拉取、跨渠道归因、设备指纹、第三方反作弊能力矩阵和外部验收清单状态。

后台运维接口:

方法路径权限说明
GET/api/v1/admin/advertising/providersadvertising:provider:view查询运行时注册 Provider、默认 Provider 和健康摘要
GET/api/v1/admin/advertising/providers/{providerName}advertising:provider:view查询指定 Provider 诊断详情
GET/api/v1/admin/advertising/providers/smokeadvertising:provider:view执行 Provider 本地 contract smoke,可选按 startDateendDateaccountCode 限定收益拉取 dry-run 范围,并返回素材同步、收益拉取、跨渠道归因、设备指纹、第三方反作弊能力矩阵、账号配置引用和真实外部验收清单

默认 log Provider 的 smoke 不触达外部网络,只生成可重复验证的本地 contract 快照。运营可在 Admin Provider 页填写外部账号编码和日期范围,后端会把这些条件传入 Provider smoke,用于固定收益拉取 dry-run 的报表编号、报表日期和账号快照;不传时仍使用本地默认样例。其能力矩阵会声明跨渠道归因、设备指纹和第三方反作弊的 dry-run contract,并把真实厂商的回调签名、设备标识、风险标签、误伤处理和结算拦截列为外部验收清单。后续接入巨量、腾讯广告、Google Ads 等具体厂商时,只新增独立 Provider 实现并注册为 Spring Bean;平台业务 API、数据表和公开展示 contract 保持不变。

广告主结算 / 打款联动验收使用只读 release runbook:

bash
./scripts/release advertising-settlement-acceptance --provider <provider> --account-code <account-code>

该 runbook 会输出本地门禁、Provider smoke、收益报表拉取 / 导入、收益与预算扣费流水对账、预算结算引用和真实外部打款联动记录模板。它不调用广告厂商、不移动资金、不写数据库,也不替代 Money / Cashier / 外部财务系统的真实打款验收。

公开展示 API

公开接口不要求后台权限,供 PC / App / CMS / Blog / Forum / Mall 等消费方按广告位编码取当前可展示广告。

当前用户侧首页已经内置两个消费方:

  • PC 首页读取 pc-home-banner
  • App 首页读取 app-home-banner

运营在 Admin 广告位 / 素材页配置对应编码后,用户侧会读取展示素材、首次展示上报曝光,点击时先上报点击再跳转目标地址。

方法路径说明
GET/api/v1/promotion/placements/{code}/materials查询广告位当前可展示素材
POST/api/v1/promotion/events/impression上报广告曝光事件
POST/api/v1/promotion/events/click上报广告点击事件
POST/api/v1/promotion/events/conversion上报广告转化事件

查询展示素材:

http
GET /api/v1/promotion/placements/pc-home-banner/materials?client=pc&scene=home

返回字段:

json
{
  "slotId": 1,
  "slotCode": "pc-home-banner",
  "slotName": "PC 首页横幅",
  "client": "pc",
  "scene": "home",
  "width": 1200,
  "height": 320,
  "maxItems": 3,
  "creatives": [
    {
      "id": 10,
      "code": "spring-campaign-a",
      "title": "春季活动 A",
      "summary": "首页自营广告素材",
      "imageUrl": "https://example.com/material.png",
      "mediaAssetKey": 10001,
      "targetType": "url",
      "targetUrl": "https://example.com/campaign",
      "sortOrder": 100,
      "visibleAt": "2026-06-01T00:00:00",
      "expiredAt": "2026-06-30T23:59:59",
      "extraJson": "{\"utm\":\"spring\"}",
      "fallback": false
    }
  ]
}

展示选择规则:

  • 广告位必须存在、未删除且启用。
  • 素材必须未删除、启用、审核通过,并处于 visibleAt <= now < expiredAt 的展示窗口内。
  • 返回数量不超过广告位 maxItems,按 sortOrder 升序、id 降序排序。
  • 没有可展示素材且广告位配置了 fallbackImageUrl 时,返回一条 fallback=true 的兜底素材。

上报曝光或点击:

json
{
  "slotCode": "pc-home-banner",
  "creativeId": 10,
  "creativeCode": "spring-campaign-a",
  "client": "pc",
  "scene": "home",
  "requestId": "trace-20260605-001",
  "targetUrl": "https://example.com/campaign",
  "extraJson": "{\"position\":\"hero\"}"
}

后端会校验广告位和素材仍处于可展示状态,并记录 requestId、IP、RefererUser-Agent 和跳转目标快照。事件写入前会按配置执行 requestId 幂等去重和短窗口同源频控;命中重复 requestId 时返回既有事件,不重复扣费。事件写入后会按素材预算尝试扣费,命中预算时生成未结算扣费流水。复杂反作弊、跨渠道转化归因和异步日报汇总后续继续基于 ad_event 明细推进。

Open Platform 广告 API

Open Platform 广告 API 供第三方服务端应用调用,路由前缀为 /api/v1/open/advertising/**,统一走 Open Platform 的 AppKey + AppSecret + HMAC 签名、防重放、scope、限流、调用日志、用量事件和账单治理。Advertising 模块只消费 core-runtime 中立 OpenApiAccessGrant,不反向依赖 Open Platform 内部实体。

方法路径Scope说明
GET/api/v1/open/advertising/placements/{code}/materialsopen:advertising:placement:read查询广告位当前可展示素材
POST/api/v1/open/advertising/events/impressionopen:advertising:event:write上报广告曝光事件
POST/api/v1/open/advertising/events/clickopen:advertising:event:write上报广告点击事件
POST/api/v1/open/advertising/events/conversionopen:advertising:event:write上报广告转化事件

事件写入、requestId 幂等、频控保护和预算扣费继续复用公开展示事件链路;Open Platform 外层负责应用鉴权、scope 授权、调用日志、成功调用 usage event 和后续账单试算 / 月账单快照。第三方调用方必须在自己的服务端签名,不要把长期 AppSecret 放到浏览器、小程序或移动端源码。

审核状态

广告素材审核状态由后端统一流转:

状态说明
draft草稿,创建或修改后默认进入该状态
pending待审核,由提交审核接口进入
approved审核通过,可进入后续展示选择
rejected审核驳回,后端会同步停用该素材

审核动作已接入 approval-workflow:

  • advertising.creative.review:控制 draft/rejected -> pendingpending -> approvedpending -> rejected,驳回必须填写处理说明。
  • advertising.creative.delivery:控制素材启用和暂停;从停用重新启用前,后端会额外要求审核状态必须为 approved

提交审核前会按 spring.open.advertising.content-safety.* 配置调用 Content Safety Manager。检测结果会写入素材的 contentSafetyActioncontentSafetyRiskLevelcontentSafetyProvidercontentSafetyProviderTypecontentSafetyReasoncontentSafetyCheckedAt 字段;后台素材列表会展示检测状态、风险等级、Provider 和原因摘要。检测建议拒绝且 reject-on-unsafe=true 时,后端会直接把素材置为 rejected 并停用。审核通过会记录 reviewedByreviewedAtreviewRemark,提审、通过、驳回和内容安全自动驳回会同步写入 ad_creative_review_log。后台“超时提醒”会扫描待审核超过阈值的素材并幂等写入 review-timeout 日志,不自动通过或驳回素材;真实外部通知和超时自动处理后续按独立功能簇接入。

权限与菜单

迁移会初始化以下权限,并默认授予 super-admin

权限说明
advertising:slot:view查看广告位
advertising:slot:create创建广告位
advertising:slot:update修改 / 启停广告位
advertising:slot:delete删除广告位
advertising:creative:view查看广告素材
advertising:creative:create创建广告素材
advertising:creative:update修改 / 启停 / 提交审核广告素材
advertising:creative:delete删除广告素材
advertising:creative:review审核广告素材
advertising:report:view查看广告报表
advertising:report:generate生成广告日报快照
advertising:budget:view查看广告预算和扣费流水
advertising:budget:create创建广告预算
advertising:budget:update修改 / 启停广告预算
advertising:budget:settle结算广告预算扣费流水
advertising:provider:view查看广告 Provider 运维诊断
advertising:revenue-report:view查看广告 Provider 收益报表
advertising:revenue-report:import拉取 / 导入广告 Provider 收益报表、更新结算状态和执行受控自动结算

菜单节点为 advertisingadvertising:slotadvertising:creativeadvertising:reportadvertising:budgetadvertising:provideradvertising:revenue-report。Admin 已接入真实投放页、报表页、预算结算页、Provider 运维页和收益报表导入页:

  • /#/advertising/slots:广告位列表、筛选、创建、修改、启停、删除和批量删除。
  • /#/advertising/creatives:广告素材列表、广告位筛选、创建、修改、启停、提交审核、审核通过、驳回、删除和批量删除。
  • /#/advertising/reports:曝光 / 点击 / 转化汇总、每日趋势、广告位排行和素材排行。
  • /#/advertising/budgets:广告预算列表、筛选、创建、修改、启停、扣费流水查看和未结算流水结算。
  • /#/advertising/providers:Provider 注册状态、默认 Provider、轻量诊断摘要和可按外部账号 / 日期范围执行的本地 contract smoke。
  • /#/advertising/revenue-reports:Provider 收益报表筛选、列表、Provider 拉取、受控导入、结算状态推进和自动结算。

后续收口

当前已完成模块骨架、广告位、素材、审核状态机、审核超时提醒、内容安全预检、基础权限菜单、Admin 投放页 / 报表页 / 日报快照 / 预算结算页 / Provider 运维页 / 收益报表页、公开展示 / 事件上报 contract、requestId 幂等去重、短窗口同源频控、基础事件报表、预算扣费结算、Provider 本地 contract smoke、Provider 条件化 smoke、Provider 能力矩阵、Provider 收益报表拉取 / 受控导入、收益与本地扣费对账摘要、结算状态运营与自动结算入口、广告主结算 / 打款联动验收 runbook、迁移、i18n、后端 contract 和服务测试。

后续按独立功能簇继续推进:

  • 真实广告厂商侧设备指纹 / 第三方反作弊和跨渠道转化归因验收;本地 Provider 能力矩阵、基于 IP / User-Agent 的来源风险摘要和日报快照已完成。
  • 真实外部通知和超时自动处理;人工复核日志、内容安全自动驳回和审核超时提醒已接入后台“记录”抽屉。
  • 真实广告厂商账号、预算充值、实际资金入账 / 出账和厂商 SDK 生产凭据验收;广告主结算 / 打款联动验收 runbook 已提供记录入口,真实资金动作仍由 Money / Cashier / 外部财务系统或具体 Provider 执行。

验证

bash
./mvnw -pl spring-open-modules/spring-open-module-advertising -am test -DskipFrontend
pnpm -C views/admin typecheck
./.ai/scripts/check modules
./.ai/scripts/check i18n
./.ai/scripts/check migrations
git diff --check

Released under the Apache License 2.0.