docs/notifications.md
本文档记录通知能力 P0-P3 基线:渠道、配置 key、GitHub Actions 映射、Web 设置元数据、CLI 诊断口径、Web 一键测试、自定义 Webhook Body 模板语义和通知路由策略。P0 只做基线与只读诊断;P1 增加 Web 单渠道真实测试;P2 产品化现有 Body 模板;P3 增加 report / alert / system_error 路由,不包含降噪、per-URL 模板或新增一等渠道。
| 渠道 | 类型 | Minimal key | Advanced key | 说明 |
|---|---|---|---|---|
| 企业微信 | 静态配置 | WECHAT_WEBHOOK_URL | WECHAT_MSG_TYPE | 配置后参与批量通知发送 |
| 飞书 Webhook | 静态配置 | FEISHU_WEBHOOK_URL | FEISHU_WEBHOOK_SECRET, FEISHU_WEBHOOK_KEYWORD | FEISHU_APP_ID / FEISHU_APP_SECRET 不会单独开启群 Webhook 推送 |
| Telegram | 静态配置 | TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID | TELEGRAM_MESSAGE_THREAD_ID | token 与 chat id 必须同时存在 |
| 邮件 | 静态配置 | EMAIL_SENDER, EMAIL_PASSWORD | EMAIL_RECEIVERS, EMAIL_SENDER_NAME | EMAIL_RECEIVERS 留空时发给自己 |
| Pushover | 静态配置 | PUSHOVER_USER_KEY, PUSHOVER_API_TOKEN | - | 两个 key 必须同时存在 |
| PushPlus | 静态配置 | PUSHPLUS_TOKEN | PUSHPLUS_TOPIC | PUSHPLUS_TOPIC 仅在 token 存在时生效 |
| Server酱3 | 静态配置 | SERVERCHAN3_SENDKEY | - | 手机 App 推送 |
| 自定义 Webhook | 静态配置 | CUSTOM_WEBHOOK_URLS | CUSTOM_WEBHOOK_BEARER_TOKEN, CUSTOM_WEBHOOK_BODY_TEMPLATE, WEBHOOK_VERIFY_SSL | 支持多个 URL,逗号分隔 |
| Discord | 静态配置 | DISCORD_WEBHOOK_URL 或 DISCORD_BOT_TOKEN + DISCORD_MAIN_CHANNEL_ID | DISCORD_INTERACTIONS_PUBLIC_KEY | Webhook 与 Bot 均可启用发送 |
| Slack | 静态配置 | SLACK_WEBHOOK_URL 或 SLACK_BOT_TOKEN + SLACK_CHANNEL_ID | - | Bot 优先用于文本与图片同频道发送 |
| AstrBot | 静态配置 | ASTRBOT_URL | ASTRBOT_TOKEN, WEBHOOK_VERIFY_SSL | ASTRBOT_TOKEN 可选 |
UNKNOWN | 兜底枚举 | - | - | 仅为未知渠道兜底,不由静态环境变量启用 |
| 钉钉会话 | 运行时上下文 | - | - | 从来源消息上下文提取,无法仅由 .env 静态判断 |
| 飞书会话 | 运行时上下文 | - | - | 从来源消息上下文提取,无法仅由 .env 静态判断 |
NOTIFICATION_*_CHANNELS 属于 Advanced key:只收窄已启用渠道,不会单独启用渠道。.env.example、Web 元数据与回归测试。仓库自带 .github/workflows/daily_analysis.yml 只显式导入固定变量名。P0 补齐以下已存在发送链路所需的映射:
CUSTOM_WEBHOOK_BODY_TEMPLATEWEBHOOK_VERIFY_SSLFEISHU_WEBHOOK_SECRETFEISHU_WEBHOOK_KEYWORDPUSHPLUS_TOPICP3 补齐以下通知路由映射:
NOTIFICATION_REPORT_CHANNELSNOTIFICATION_ALERT_CHANNELSNOTIFICATION_SYSTEM_ERROR_CHANNELS默认 workflow 仍不映射 MARKDOWN_TO_IMAGE_CHANNELS 与 MERGE_EMAIL_NOTIFICATION。它们是发送形态或聚合行为开关,不是渠道凭证;在 Actions 中自动开始读取同名 Secret/Variable 会引入额外行为变化。
python main.py --check-notify
该命令只读配置,不发送通知,不写入 .env。它会在配置加载和日志初始化后立即执行,完成后直接退出,不再进入 Web、调度、大盘复盘或默认分析流程。
0:没有 error 级诊断。1:存在 error,例如 0 个静态通知渠道已配置,或成对 key 只配置了一半。Web 设置页的“通知渠道”分类提供单渠道测试入口。测试会使用当前页面草稿值合成临时配置,发送一条真实测试通知,但不会保存 .env,也不会修改运行时全局配置。
UNKNOWN 和运行时上下文渠道。success=false,不会影响已保存配置和默认分析流程。CUSTOM_WEBHOOK_BODY_TEMPLATE 是自定义 Webhook 的全局 JSON body 模板。配置后,它会先于 URL 自动识别生效,因此会覆盖 Bark、Slack、Discord、钉钉等自动 payload。未配置时仍使用原有 URL 自动识别;渲染后不是合法 JSON object 时会记录错误并回退默认 payload,不中断主通知流程。
可用占位符:
$content_json:JSON 转义后的通知正文,推荐默认使用。$title_json:JSON 转义后的通知标题,推荐默认使用。$content / $title:原始字符串,不做 JSON 转义。正文含双引号、反斜杠或换行时可能导致 JSON 无效并触发 fallback。通用 webhook 示例:
CUSTOM_WEBHOOK_BODY_TEMPLATE={"title":$title_json,"content":$content_json}
Bark 通过 custom webhook 使用时,默认会按 api.day.app 自动生成 title / body / group。如果配置全局模板,需要自己写出 Bark body:
CUSTOM_WEBHOOK_BODY_TEMPLATE={"title":$title_json,"body":$content_json,"group":"stock"}
AstrBot 已是一等通知渠道,优先使用 ASTRBOT_URL 和可选的 ASTRBOT_TOKEN。只有需要把 AstrBot 兼容端点放入 CUSTOM_WEBHOOK_URLS 时,才使用 custom webhook 模板,例如:
CUSTOM_WEBHOOK_BODY_TEMPLATE={"content":$content_json}
NapCat / OneBot HTTP API 需要按实际 endpoint 和目标类型调整。下面只是常见 body 形态示例,user_id、group_id、URL 路径和鉴权方式都应以你的 NapCat 配置为准:
# 私聊:CUSTOM_WEBHOOK_URLS=http://127.0.0.1:3000/send_private_msg
CUSTOM_WEBHOOK_BODY_TEMPLATE={"user_id":123456,"message":$content_json}
# 群聊:CUSTOM_WEBHOOK_URLS=http://127.0.0.1:3000/send_group_msg
CUSTOM_WEBHOOK_BODY_TEMPLATE={"group_id":123456789,"message":$content_json}
P3 新增三类通知路由配置:
| 路由类型 | 配置 key | 当前生产者 |
|---|---|---|
report | NOTIFICATION_REPORT_CHANNELS | 单股推送、聚合日报、大盘复盘、合并推送、飞书文档成功链接 |
alert | NOTIFICATION_ALERT_CHANNELS | EventMonitor 触发通知 |
system_error | NOTIFICATION_SYSTEM_ERROR_CHANNELS | 预留能力;当前不新增自动系统错误生产者 |
配置值为逗号分隔渠道枚举:wechat,feishu,telegram,email,pushover,pushplus,serverchan3,custom,discord,slack,astrbot。
send_to_context() 不受路由限制,机器人会话上下文仍会收到触发任务的回复。MARKDOWN_TO_IMAGE_CHANNELS 只对路由后的渠道子集生效。MERGE_EMAIL_NOTIFICATION 不需要额外配置;只要 email 仍在 report 路由后的渠道中,现有合并邮件行为保持不变。--check-notify 会把未知渠道值报为 error,把合法但未启用的路由目标报为 warning。.env,可用 python main.py --check-notify 做本地诊断。env: 中显式映射的 Secret/Variable。.env。