# 自动投放平台统一架构

> 状态：已实现
> 日期：2026-07-25

## 1. 服务边界

生产只启动两个服务，共用 `ad-put-agent` 完整镜像。

| 服务 | 运行方式 | 职责 |
|---|---|---|
| `ad-control-service` | 常驻 | 飞书控制命令、运营暂停状态、每 10 分钟 CPM 调控、次日恢复 |
| `ad-daily-service` | 常驻调度 | 每日 10:30 广告/创意创建、每 2 小时创意审核扫描 |

旧 `server.py`、`execute_once.py` 和 `run.py` 的模型调控链路不再作为生产入口。
现有 ROI 纯计算函数保留，未来日级 ROI 服务可以复用，但本期不自动调价。

## 2. 日级流程

`ad-daily-service` 不重写业务流程，只调度已有脚本：

```text
每天 10:30
  execute_creation_once.py
    飞书配置同步
    -> 广告缺口检查与创建
    -> 创意缺口检查
    -> 历史素材召回 / AI 生成
    -> 现有飞书在线表格审批
    -> 审批通过项提交腾讯

每 2 小时
  scan_creative_reviews.py
    -> 查询腾讯正式审核结果
    -> 写入审核结果和拒审事实
```

每类任务使用独立 MySQL advisory lock，防止多 Pod 重复运行。创建流程仍保持
原有幂等、审批和副作用边界。创建、审核扫描和模板同步默认均关闭，生产必须
通过 `DAILY_*_ENABLED` 和 `DAILY_SYNC_DELIVERY_TEMPLATE` 显式启用。

## 3. 实时流程

`ad-control-service` 内有两个并发入口：

```text
飞书 WebSocket
  -> 确定性解析
  -> 权限校验
  -> 生成操作预览
  -> 二次确认
  -> 腾讯写入和回读

每 10 分钟实时循环
  -> 运营暂停状态对账
  -> 当天暂停到期处理
  -> 获取最新小时 CPM
  -> CPM 决策
  -> 合并最终广告状态和出价
  -> 腾讯写入和回读
  -> 动作审计与飞书通知
```

两个入口共用 `RTC_DB_LOCK_NAME`，同一时刻只允许一个流程修改腾讯广告。

实时 CPM 规则保持：

- `CPM > 250`：基础出价上调 5%，每天最多一次。
- `190 <= CPM <= 250`：恢复基础出价和 CPM 策略暂停。
- `CPM < 190`：恢复基础出价，将开始日期延后至次日，保持广告开启。
- 默认每天 21:00：只恢复基础出价，不主动暂停广告。
- 次日 06:00：由腾讯广告投放时段自动开始投放；实时 CPM 调控默认 12:00 开始。

## 4. 飞书命令

首期只接受确定性生产命令，不接入开放式模型问答：

```text
暂停全部
暂停账户 86197363,86748325
停止全部
停止账户 86197363 86748325
恢复全部
恢复账户 86197363、86748325
查看暂停状态
确认 cmd_xxx
取消 cmd_xxx
```

- `暂停`：暂停到下一投放日 06:00。
- `停止`：持续停止，只有明确恢复或腾讯后台人工开启才解除。
- `恢复`：解除运营暂停；如果仍有 CPM 暂停，不会误开广告。
- 所有腾讯写命令都必须在 10 分钟内二次确认。
- 群聊必须来自配置群并 @机器人；发送人必须在允许列表。
- 飞书消息 ID 是幂等键，重复事件不会重复创建命令。
- “全部”表示 `ad_creation_account_config` 历史账户与启用白名单的交集，
  不受当前是否继续新建广告影响。

## 5. 状态与优先级

`realtime_control_ad_state` 分开保存：

- `paused_by_strategy`：CPM 实时策略暂停。
- `operator_pause_mode=UNTIL_NEXT_DELIVERY`：运营当天暂停。
- `operator_pause_mode=UNTIL_MANUAL`：运营持续停止。

优先级为：

```text
未到期运营暂停 > CPM 状态
```

只认领命令执行时腾讯状态为 `NORMAL` 的广告。原本人工暂停的广告只记录跳过，
不会被后续自动恢复。腾讯后台人工重新开启运营停止广告时，系统尊重人工操作，
清除运营暂停状态并发送通知。

命令、广告明细、写前状态、目标状态、回读状态和错误分别保存到
`operator_command`、`operator_command_item`。腾讯实时动作继续写入
`realtime_control_action_log`。

## 6. 配置所有权

- 飞书/数据库：账户、人群包、出价、预算、素材来源、年龄、地域、版位。
- 日级服务：下一投放日的广告和创意供给；未来拥有 `base_bid_fen`。
- 实时服务：盘中状态和临时倍率，不改账户配置和长期投放日期。
- 新建广告统一使用 `06:00-20:00`，代码默认值和启用投放模板在日级服务启动时校准。
- 历史广告不会因本次代码发布自动批量修改投放时段。

## 7. 暂不实现

- 不实现自动日级 ROI 调价，只保留基础出价所有权边界。
- 不实现预算节奏调控。
- 不引入队列、Redis、Celery 或额外 worker。
- 不让模型解析账户 ID 或直接执行腾讯写操作。
