自营广告
受众:开发者 / 运营 摘要: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_slot、ad_creative、ad_creative_review_log、ad_creative_version、ad_event、ad_daily_report、ad_budget、ad_budget_ledger、ad_provider_revenue_report |
| 权限码前缀 | advertising:* |
应用默认开启该模块,可通过配置关闭:
spring:
open:
advertising:
enabled: true公开曝光 / 点击 / 转化事件默认启用轻量保护:
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: 20request-id-deduplication-enabled:同一广告位、素材、事件类型和requestId重放时返回既有事件,不重复写入明细,也不重复扣费。frequency-limit-enabled:按广告位、素材、事件类型、IP 和 User-Agent 做短窗口频控;缺少 IP 和 User-Agent 时不拦截,避免误伤服务端转发或测试链路。- 这些保护只作为默认生产护栏,不替代更重的广告主风控、转化归因和第三方反作弊。
event-guard配置键已由AdvertisingServiceProvider声明到 lifecycle 配置 schema,后台配置中心可以识别启用开关、requestId 去重、频控开关、频控窗口和窗口内曝光 / 点击阈值。
素材提审前默认启用内容安全预检:
spring:
open:
advertising:
content-safety:
enabled: true
fail-on-unavailable: false
fail-on-error: false
reject-on-unsafe: trueenabled:提交广告素材审核前是否调用 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_creative 以 slot_id + code 唯一,允许不同广告位复用同一个素材编码。ad_event 用于基础报表、轻量去重、频控和后续风控审计的原始明细;实时报表仍在应用侧基于事件明细轻量聚合,ad_daily_report 则用于后台手动或调度任务生成的运营日报快照。
ad_budget.code 全局唯一;当前首段一个广告素材最多绑定一个预算。ad_budget_ledger.event_id 唯一,用于保证同一公开事件最多生成一笔扣费流水。预算结算时可以写入 settlementProvider、settlementReference 和 settlementIdempotencyKey,用于把 Advertising 结算批次关联到 Cashier、Money 或外部对账系统;未传幂等键时,后端按预算和日期范围生成稳定默认值。
ad_provider_revenue_report 以 provider + report_no 幂等保存已授权第三方报表摘要。它只作为后续广告主结算、对账和人工复核的审计来源,不直接执行 Money / Cashier 入账、出账或打款。管理员可把记录标记为 reconciled 或 ignored,也可以重置为 imported 重新进入人工核对队列。
后台管理 API
后台接口需要登录并校验权限。
广告位
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
GET | /api/v1/admin/advertising/slots | advertising:slot:view | 分页查询广告位 |
GET | /api/v1/admin/advertising/slots/{id} | advertising:slot:view | 查询广告位详情 |
POST | /api/v1/admin/advertising/slots | advertising:slot:create | 创建广告位 |
PUT | /api/v1/admin/advertising/slots/{id} | advertising:slot:update | 修改广告位 |
PUT | /api/v1/admin/advertising/slots/{id}/status | advertising:slot:update | 启用或停用广告位 |
DELETE | /api/v1/admin/advertising/slots/{id} | advertising:slot:delete | 删除广告位 |
DELETE | /api/v1/admin/advertising/slots | advertising:slot:delete | 批量删除广告位 |
创建请求示例:
{
"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 建议使用 pc、app、admin 或 all,scene 由业务自定义,例如 home、article-detail、mall-product。
广告素材
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
GET | /api/v1/admin/advertising/creatives | advertising:creative:view | 分页查询广告素材 |
GET | /api/v1/admin/advertising/creatives/{id} | advertising:creative:view | 查询广告素材详情 |
POST | /api/v1/admin/advertising/creatives | advertising:creative:create | 创建广告素材 |
PUT | /api/v1/admin/advertising/creatives/{id} | advertising:creative:update | 修改广告素材,修改后回到草稿状态 |
PUT | /api/v1/admin/advertising/creatives/{id}/status | advertising:creative:update | 启用或停用广告素材;启用前必须已审核通过 |
POST | /api/v1/admin/advertising/creatives/{id}/review/submit | advertising:creative:update | 提交广告素材审核 |
POST | /api/v1/admin/advertising/creatives/{id}/review/approve | advertising:creative:review | 审核通过广告素材 |
POST | /api/v1/admin/advertising/creatives/{id}/review/reject | advertising:creative:review | 驳回广告素材并停用 |
POST | /api/v1/admin/advertising/creatives/review-timeouts/notify | advertising:creative:review | 扫描待审核超时素材并幂等写入审核超时提醒日志 |
GET | /api/v1/admin/advertising/creatives/{id}/review-logs | advertising:creative:view | 分页查询广告素材审核日志 |
GET | /api/v1/admin/advertising/creatives/{id}/versions | advertising:creative:view | 分页查询广告素材版本快照 |
DELETE | /api/v1/admin/advertising/creatives/{id} | advertising:creative:delete | 删除广告素材 |
DELETE | /api/v1/admin/advertising/creatives | advertising:creative:delete | 批量删除广告素材 |
创建请求示例:
{
"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/summary | advertising:report:view | 查询曝光、点击、转化汇总、事件质量、每日趋势、广告位排行和素材排行 |
GET | /api/v1/admin/advertising/reports/daily | advertising:report:view | 分页查询已生成的广告日报快照 |
POST | /api/v1/admin/advertising/reports/daily/generate | advertising:report:generate | 按当前筛选范围幂等生成广告日报快照 |
查询参数:
| 参数 | 说明 |
|---|---|
startDate / endDate | 日期范围,格式 YYYY-MM-DD;未传时默认近 7 天,开始日期晚于结束日期时后端会自动调换 |
slotCode | 按广告位编码过滤 |
creativeCode | 按素材编码过滤 |
client | 按终端过滤,例如 pc、app、admin、all |
scene | 按投放场景过滤 |
返回内容包含 totalEvents、impressions、clicks、conversions、clickThroughRate、conversionRate、eventQuality、attribution、sourceRisk、dailyMetrics、slotMetrics、creativeMetrics、riskSignals 和 sourceRisks。CTR / CVR 以百分比数值返回,例如 12.50 表示 12.50%。
eventQuality 是轻量运营复核摘要,基于当前筛选范围识别缺失 requestId、重复 requestId、点击数大于曝光数的素材和转化数大于点击数的素材,并给出 normal、warning 或 risk 复核等级。它用于帮助运营快速发现疑似刷量、归因异常或接入方漏传追踪 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/budgets | advertising:budget:view | 分页查询广告预算 |
GET | /api/v1/admin/advertising/budgets/{id} | advertising:budget:view | 查询广告预算详情 |
POST | /api/v1/admin/advertising/budgets | advertising:budget:create | 创建广告预算 |
PUT | /api/v1/admin/advertising/budgets/{id} | advertising:budget:update | 修改广告预算 |
PUT | /api/v1/admin/advertising/budgets/{id}/status | advertising:budget:update | 启用或停用广告预算 |
GET | /api/v1/admin/advertising/budgets/{id}/ledgers | advertising:budget:view | 分页查询预算扣费流水 |
POST | /api/v1/admin/advertising/budgets/{id}/settle | advertising:budget:settle | 结算未结算扣费流水 |
创建预算请求示例:
{
"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支持impression、click和conversion,默认click。- 公开曝光 / 点击 / 转化事件先写入
ad_event,再按素材 ID、事件类型、预算启停状态和有效期查找预算。 - 同一
eventId最多扣费一次。 - 扣费金额按
min(unitPrice, totalAmount - spentAmount, dailyAmount - 当日已扣费)计算。 - 预算余额不足或日预算不足时不写扣费流水。
- 新流水默认
settlementStatus=unsettled。
结算请求可传日期范围、资金引用和备注:
{
"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,写入 settledAt、settlementProvider、settlementReference 和 settlementIdempotencyKey,并累计预算 settledAmount。如果未显式传入 settlementIdempotencyKey,后端会生成 advertising:budget:settle:{budgetId}:{startDate|all}:{endDate|all} 格式的稳定键,方便后续资金域或外部对账系统幂等关联。预算上的 payerAccountId 和 cashierPaymentOrderId 只保存 Money / Cashier 外部引用;当前公开展示链路不同步调用资金底座,真实广告主充值、自动对账和打款继续复用 Money / Cashier。
Provider 收益报表
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
GET | /api/v1/admin/advertising/revenue-reports | advertising:revenue-report:view | 分页查询已导入 Provider 收益报表 |
GET | /api/v1/admin/advertising/revenue-reports/reconciliation-summary | advertising:revenue-report:view | 查询 Provider 收益与本地预算扣费流水对账摘要 |
POST | /api/v1/admin/advertising/revenue-reports | advertising:revenue-report:import | 受控导入 Provider 收益报表摘要 |
POST | /api/v1/admin/advertising/revenue-reports/pull | advertising:revenue-report:import | 从已注册 Provider 拉取收益报表并复用导入链路幂等更新 |
POST | /api/v1/admin/advertising/revenue-reports/{id}/settlement-status | advertising:revenue-report:import | 更新收益报表结算状态 |
POST | /api/v1/admin/advertising/revenue-reports/{id}/auto-settle | advertising:revenue-report:import | 幂等自动结算已导入收益报表 |
结算状态请求只推进运营状态,不执行资金出款:
{
"settlementStatus": "reconciled",
"remark": "已和平台后台日报核对"
}settlementStatus 支持 imported、reconciled 和 ignored。真实广告主出账、自动打款和资金对账继续复用 Money / Cashier 的独立功能簇。
自动结算请求只接受可选备注,并且只把 imported 报表推进为 reconciled;重复结算 reconciled 报表会幂等返回,ignored 报表不会被自动结算:
{
"remark": "平台日报与广告主账单已匹配"
}自动结算仍只记录运营状态和备注,不创建 Money / Cashier 资金流水,不触发真实打款。
拉取请求示例:
{
"provider": "log",
"startDate": "2026-06-01",
"endDate": "2026-06-30",
"accountCode": "ads-account-a",
"remark": "按 Provider contract 拉取六月日报"
}拉取规则:
provider为空时使用默认logProvider;默认 Provider 不触达外部网络,只生成可重复验证的 contract 快照。- 真实厂商 Provider 只需实现
AdvertisingProvider#pullRevenueReports,返回平台统一收益快照。 - 拉取结果复用导入服务,继续按
provider + reportNo幂等 upsert,避免重复拉取造成重复收益记录。 - 拉取接口不读取或保存厂商密钥;真实凭据、外部账号和网络调用由具体 Provider 自己通过受控配置处理。
对账摘要用于把 Provider 收益报表与本地 ad_budget_ledger 扣费流水放在同一个运营视图中比较,返回 Provider 收益、本地扣费、已结算 / 未结算扣费、差异金额、差异比例和风险等级。该接口只读,不创建 Money / Cashier 资金流水,也不替代真实广告厂商账单下载、广告主自动结算或三方打款。
导入请求示例:
{
"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重复导入时更新同一行,不新增重复记录。 estimatedRevenue、impressions、clicks、conversions不允许为负数。settlementStatus支持imported、reconciled、ignored。- 后端记录当前管理员为
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/providers | advertising:provider:view | 查询运行时注册 Provider、默认 Provider 和健康摘要 |
GET | /api/v1/admin/advertising/providers/{providerName} | advertising:provider:view | 查询指定 Provider 诊断详情 |
GET | /api/v1/admin/advertising/providers/smoke | advertising:provider:view | 执行 Provider 本地 contract smoke,可选按 startDate、endDate、accountCode 限定收益拉取 dry-run 范围,并返回素材同步、收益拉取、跨渠道归因、设备指纹、第三方反作弊能力矩阵、账号配置引用和真实外部验收清单 |
默认 log Provider 的 smoke 不触达外部网络,只生成可重复验证的本地 contract 快照。运营可在 Admin Provider 页填写外部账号编码和日期范围,后端会把这些条件传入 Provider smoke,用于固定收益拉取 dry-run 的报表编号、报表日期和账号快照;不传时仍使用本地默认样例。其能力矩阵会声明跨渠道归因、设备指纹和第三方反作弊的 dry-run contract,并把真实厂商的回调签名、设备标识、风险标签、误伤处理和结算拦截列为外部验收清单。后续接入巨量、腾讯广告、Google Ads 等具体厂商时,只新增独立 Provider 实现并注册为 Spring Bean;平台业务 API、数据表和公开展示 contract 保持不变。
广告主结算 / 打款联动验收使用只读 release runbook:
./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 | 上报广告转化事件 |
查询展示素材:
GET /api/v1/promotion/placements/pc-home-banner/materials?client=pc&scene=home返回字段:
{
"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的兜底素材。
上报曝光或点击:
{
"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、Referer、User-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}/materials | open:advertising:placement:read | 查询广告位当前可展示素材 |
POST | /api/v1/open/advertising/events/impression | open:advertising:event:write | 上报广告曝光事件 |
POST | /api/v1/open/advertising/events/click | open:advertising:event:write | 上报广告点击事件 |
POST | /api/v1/open/advertising/events/conversion | open:advertising:event:write | 上报广告转化事件 |
事件写入、requestId 幂等、频控保护和预算扣费继续复用公开展示事件链路;Open Platform 外层负责应用鉴权、scope 授权、调用日志、成功调用 usage event 和后续账单试算 / 月账单快照。第三方调用方必须在自己的服务端签名,不要把长期 AppSecret 放到浏览器、小程序或移动端源码。
审核状态
广告素材审核状态由后端统一流转:
| 状态 | 说明 |
|---|---|
draft | 草稿,创建或修改后默认进入该状态 |
pending | 待审核,由提交审核接口进入 |
approved | 审核通过,可进入后续展示选择 |
rejected | 审核驳回,后端会同步停用该素材 |
审核动作已接入 approval-workflow:
advertising.creative.review:控制draft/rejected -> pending、pending -> approved、pending -> rejected,驳回必须填写处理说明。advertising.creative.delivery:控制素材启用和暂停;从停用重新启用前,后端会额外要求审核状态必须为approved。
提交审核前会按 spring.open.advertising.content-safety.* 配置调用 Content Safety Manager。检测结果会写入素材的 contentSafetyAction、contentSafetyRiskLevel、contentSafetyProvider、contentSafetyProviderType、contentSafetyReason 和 contentSafetyCheckedAt 字段;后台素材列表会展示检测状态、风险等级、Provider 和原因摘要。检测建议拒绝且 reject-on-unsafe=true 时,后端会直接把素材置为 rejected 并停用。审核通过会记录 reviewedBy、reviewedAt 和 reviewRemark,提审、通过、驳回和内容安全自动驳回会同步写入 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 收益报表、更新结算状态和执行受控自动结算 |
菜单节点为 advertising、advertising:slot、advertising:creative、advertising:report、advertising:budget、advertising:provider 和 advertising: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 执行。
验证
./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