# Elio 主动唤醒 API

目标环境：`pro` 预发布环境。

基础地址：

```text
https://proapi.banlv-ai.com
```

所有接口都需要：

```http
X-Admin-Token: <admin token>
Content-Type: application/json
```

`ADMIN_VIEW_TOKEN` 只能读取规则。更新规则或运行扫描需要使用 `ADMIN_TOKEN`。

## 状态

主动唤醒调度器已经部署在 `pro` 环境，但真实发送受环境变量控制：

```text
ENABLE_PROACTIVE_WAKEUP=false
PROACTIVE_WAKEUP_DRY_RUN=true
```

在当前默认配置下，每小时调度器会跳过真实发送。管理后台仍然可以手动调用 dry-run，用于监控和预览。

## 规则模型

```ts
type ProactiveRule = {
  id: string;
  rule_key:
    | "global_anti_harassment"
    | "festival"
    | "social_post_share"
    | "dormant_wakeup";
  category: "guardrail" | "festival" | "social_post" | "dormant";
  enabled: boolean;
  priority: number;
  trigger_conditions: Record<string, unknown>;
  behavior_strategy: Record<string, unknown>;
  frequency_limit: Record<string, unknown>;
  created_at: string;
  updated_at: string;
};
```

默认规则：

| 规则 | 用途 | 主要限制 |
| --- | --- | --- |
| `festival` | 情人节、圣诞节、生日等个性化唤醒 | 每个节日周期最多 1 次 |
| `social_post_share` | 分享 Elio 最新 Facebook 帖子 | 每个 Facebook 帖子事件最多 1 次 |
| `dormant_wakeup` | 48 小时未活跃用户唤醒 | 每个沉睡周期最多 1 次 |
| `global_anti_harassment` | 用户闲置 7 天后停止唤醒 | 全局抑制规则 |

## 获取规则列表

```http
GET /api/admin/proactive/rules
```

示例：

```bash
curl -H "X-Admin-Token: $ADMIN_TOKEN" \
  https://proapi.banlv-ai.com/api/admin/proactive/rules
```

响应：

```json
{
  "success": true,
  "data": [
    {
      "id": "8b14a3bf-6c01-4d0c-85b5-613399cb8f14",
      "rule_key": "dormant_wakeup",
      "category": "dormant",
      "enabled": true,
      "priority": 30,
      "trigger_conditions": {
        "min_idle_hours": 48,
        "min_user_messages": 5
      },
      "behavior_strategy": {
        "mode": "ai_dormant_wakeup",
        "tone": "soft_missing",
        "send_channel": "cozsweet"
      },
      "frequency_limit": {
        "cycle_scope": "dormant_period",
        "max_per_cycle": 1
      },
      "created_at": "2026-06-29T07:38:46.155433+00:00",
      "updated_at": "2026-06-29T10:52:11.041169+00:00"
    }
  ]
}
```

## 更新规则

```http
PATCH /api/admin/proactive/rules/{rule_key}
```

允许的请求字段：

```ts
type UpdateProactiveRuleRequest = {
  enabled?: boolean;
  priority?: number;
  trigger_conditions?: Record<string, unknown>;
  behavior_strategy?: Record<string, unknown>;
  frequency_limit?: Record<string, unknown>;
};
```

示例：

```bash
curl -X PATCH \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  https://proapi.banlv-ai.com/api/admin/proactive/rules/dormant_wakeup
```

响应：

```json
{
  "success": true,
  "data": {
    "rule_key": "dormant_wakeup",
    "enabled": true,
    "priority": 30,
    "trigger_conditions": {
      "min_idle_hours": 48,
      "min_user_messages": 5
    }
  }
}
```

## 运行扫描

```http
POST /api/admin/proactive/run?dry_run=true
```

查询参数：

| 名称 | 类型 | 默认值 | 含义 |
| --- | --- | --- | --- |
| `dry_run` | boolean | `true` | `true` 表示预览符合条件的候选用户；`false` 仅在 `ENABLE_PROACTIVE_WAKEUP=true` 时执行真实发送并写入投递记录。 |

示例：

```bash
curl -X POST \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  "https://proapi.banlv-ai.com/api/admin/proactive/run?dry_run=true"
```

当前 `pro` 环境在没有符合条件用户时的响应：

```json
{
  "success": true,
  "data": {
    "enabled": false,
    "dryRun": true,
    "candidates": 0,
    "sent": 0,
    "items": []
  }
}
```

当存在候选用户时，`items` 会包含规则、周期上下文；在 dry-run 模式下，还会包含生成的预览消息。

## 前端状态

管理后台需要处理以下状态：

| 状态 | 检测方式 | UI 建议 |
| --- | --- | --- |
| 未授权 | HTTP `403`，`message=admin token required` | 提示操作人员输入 admin token。 |
| 无候选用户 | `success=true`，`data.candidates=0` | 展示空状态。 |
| Dry-run 预览 | `data.dryRun=true`，`items.length>0` | 展示候选用户列表和预览文本。 |
| 真实发送已禁用 | `data.enabled=false` | 提示当前环境配置已关闭真实发送。 |
| 已执行发送 | `data.dryRun=false`，`data.sent>0` | 展示发送数量和投递记录行。 |
| 部分失败 | 任意 item 的 `status="failed"` | 展示每个用户的失败原因，同时保留成功记录。 |

## 备注

- 用户符合条件的前提是 cozsweet/web 用户消息数 `>= 5`，并且最后一次互动时间早于规则阈值。
- 全局反骚扰规则会在用户闲置 7 天后抑制唤醒。
- 生日唤醒需要生日数据。迁移中包含 `users.birthday`；如果该列尚不存在，生日匹配会被跳过，但不会影响其他规则。
- Facebook 帖子分享需要向 `proactive_message_events` 插入一条 `elio_fb_post` 记录。
