feat: 初始化Webhook中继系统项目

- 添加FastAPI应用基础结构,包括主入口、路由和模型定义
- 实现Webhook接收端点(/webhook/{namespace})和健康检查(/health)
- 添加管理后台路由和模板,支持端点、目标、渠道和模板管理
- 包含SQLite数据库模型定义和初始化逻辑
- 添加日志记录和统计服务
- 包含Dockerfile和配置示例文件
- 添加项目文档,包括设计、流程图和验收标准
This commit is contained in:
2025-12-21 18:43:12 +08:00
commit 2bc7460f1f
42 changed files with 3177 additions and 0 deletions
@@ -0,0 +1,21 @@
# 验收记录
## 用例1:示例JSON
- 步骤:POST /webhook/opps-webhook,负载为示例
- 期望:
- 路由至 target_3
- 生成文本包含商户名、支付方式、金额、状态与日期,例如:`【某商户】支付宝 收款 5.50 元,状态:成功,日期:20251220`
- 飞书与企业微信推送成功
## 用例2remark未匹配
- 步骤:remark为未知值
- 期望:使用 default_targets 或仅通知
## 用例3:退款事件
- 步骤:事件为 `refund.standard`
- 期望:从 `actual_ref_amt``ref_amt/settlement_amt` 渲染文本
## 用例4:目标不可达
- 步骤:模拟目标URL不可达
- 期望:记录失败并按策略重试
@@ -0,0 +1,48 @@
# 任务名称
Webhook中继与通知系统(Docker化)
## 背景与目标
- 统一接收外部Webhook,按规则路由到目标端点,并生成通知消息推送至飞书/企业微信。
- 基于配置可扩展,支持新增目标、remark映射与事件模板。
## 业务范围
- 接收JSON负载,至少包含 `remark``event_define_no``trans_amt``trans_order_info.cash_resp_desc`、可选 `actual_ref_amt`
- 路由策略:按 `remark` 映射至一个或多个目标Webhook;若无匹配使用 `default_targets`
- 通知策略:按 `event_define_no` 模板生成文本,支持多渠道并发推送。
## 技术范围
- Python 3.12、FastAPI、httpx
- Docker 容器化;SQLite 持久化,模型定义见 `app/db.py`
- 管理后台 `/admin` 维护端点、规则、动作、模板与通知渠道
- 结构化日志;失败重试(在转发逻辑中可扩展);请求与分发记录持久化
## 输入与输出
- 输入:`POST /webhook/{namespace}` JSON
- 输出:200 返回路由与通知结果结构
## 验收标准
- 能正确解析示例 JSON 并生成消息,包含商户名、支付方式、金额、状态与日期,例如:`【某商户】支付宝 收款 5.50 元,状态:成功,日期:20251220`
- `remark=imcgcd03` 时转发至配置第3个目标;`remark=imcgcd02` 时至第2个目标
- 同时推送至飞书与企业微信(若配置存在多个机器人则全部发送)
- 失败记录与重试可配置(次数与退避)
## 部署与运行方式(概要)
- 运行模式:
- 作为独立 FastAPI 服务运行,暴露 `POST /webhook/{namespace}``/admin` 管理界面
- 通过 Docker 镜像部署到服务器
- 最低运行环境:
- Python 3.12 或兼容的 Docker 运行时
- 对外开放的 HTTP 端口(默认 8080)
- 配置与数据:
- 数据库:默认 `sqlite:///./config/data.db`,可通过环境变量 `DB_PATH` 调整
- 规则、模板、渠道均通过 Web 管理后台写入数据库,无需修改代码或 YAML
## 边界与不做事项
- 不实现目标端点的认证协议,默认匿名POST;可通过配置扩展签名
- 不提供长期持久幂等存储,默认进程内短期去重
## 风险与约束
- 目标Webhook不可达导致延迟;通过重试与超时保护
- 通知渠道限流;并发可控与错误日志
@@ -0,0 +1,25 @@
# 共识与决策
## 技术选型
- 语言与框架:Python + FastAPI
- 网络库:httpx
- 配置:YAML(PyYAML),环境变量 `WEBHOOK_CONFIG_PATH`
- 重试:简单指数退避
- 容器:python:3.12-slim,入口 `uvicorn app.main:app --host 0.0.0.0 --port 8080`
## 接口规范
- `POST /webhook/{namespace}` 接收上游负载;`GET /health` 健康检查
## 配置规范
- `targets`:目标Webhook注册表
- `routing.remark_map`remark到target名称列表映射
- `notifications.event_map`:事件模板与渠道列表
- `channels`:各渠道机器人Webhook列表
## 路由与通知规则
- 路由按 `remark` 精确匹配,多目标并发转发
- 通知按 `event_define_no` 模板渲染,支持多渠道并发推送
## 验收口径
- 示例JSON生成消息与路由正确;返回结构包含每个目标与渠道的状态
@@ -0,0 +1,51 @@
# 架构设计
## 总体架构
```mermaid
flowchart LR
A[Incoming Webhook] --> B[FastAPI /webhook/{namespace}]
B --> C[Router]
C --> D[Targets Forwarder]
B --> E[Event Template]
E --> F[Channels Sender]
D --> G[External Webhook Targets]
F --> H[Feishu]
F --> I[WeCom]
```
## 模块分层
- 接入层:`app/main.py`FastAPI 入口与 Webhook 接收)
- 管理后台:`app/admin.py`(端点、规则、模板与渠道的增删改查)
- 领域模型与持久化:`app/db.py`, `app/models.py`
- 规则引擎:`app/services/engine.py`(树形规则 + 动作编排)
- 通知发送:`app/services/notify.py`
- 统计与日志:`app/services/stats.py`, `app/logging.py`
## 关键接口
- `engine.process(endpoint_id, payload) -> (routed: List, notified: List)`
- `_exec_forward(target, payload) -> Result`(内部使用)
- `_exec_notify(channel, msg) -> Result`(内部使用)
- 管理接口:`/admin/*` 用于维护端点、规则树、动作、模板与渠道
## 数据契约
- 输入:示例 JSON 结构,关键字段存在于顶层与 `trans_order_info`
- 输出:`{"namespace": str, "routed": [...], "notified": [...]}`,其中:
- `routed`:每个转发目标的执行摘要(目标名、是否成功、失败原因)
- `notified`:每个通知渠道的执行摘要(渠道名、是否成功、失败原因)
## 异常策略
- 超时与网络错误重试;失败记录结构化日志
- 非致命错误不影响其他目标或渠道发送
## 部署与运行(概要)
- 本地直接运行:
- 创建并激活虚拟环境(可选)
- 执行 `pip install -r requirements.txt`
- 启动服务:`uvicorn app.main:app --host 0.0.0.0 --port 8080`
- Docker 部署:
- 构建镜像:`docker build -t webhook-relay .`
- 运行容器示例:
- `docker run -d --name webhook-relay -p 8080:8080 webhook-relay`
- 默认使用 SQLite 数据库,路径由环境变量 `DB_PATH` 控制,默认值为 `sqlite:///./config/data.db`
- 如需持久化,可将宿主机目录挂载到容器内 `/app/config` 目录
+191
View File
@@ -0,0 +1,191 @@
# Webhook 中继系统流程图
## 1. 系统宏观架构图
```mermaid
graph TB
subgraph External["外部世界"]
Sender["发送方 (支付宝/微信/业务系统)"]
User["管理员"]
TargetSys["目标系统 (ERP/BI)"]
NotifyApp["IM工具 (飞书/企微)"]
end
subgraph WebhookRelay["Webhook中继服务 (Docker)"]
direction TB
subgraph Interface["接入层"]
API["FastAPI (端口:8080)"]
AdminUI["Web管理后台"]
end
subgraph Core["核心逻辑层"]
Parser["数据解析 (Pydantic)"]
Router["路由引擎 (Routing)"]
Notifier["通知引擎 (Notification)"]
Logger["日志审计 (Logging)"]
end
subgraph Data["数据存储层"]
DB[(SQLite 数据库)]
Config["Config Loader (DB优先 + YAML回退)"]
end
end
Sender -->|POST JSON| API
User -->|浏览器访问| AdminUI
AdminUI -->|CRUD配置| DB
API --> Parser
Parser --> Router
Parser --> Notifier
Router <-->|查询规则| Config
Notifier <-->|查询模板| Config
Config <-->|读取| DB
Router -->|转发请求| TargetSys
Notifier -->|推送消息| NotifyApp
API -->|异步写入| Logger
Logger -->|持久化| DB
```
## 2. 详细数据处理流程
此图展示了一个 Webhook 请求从进入系统到完成分发与记录的完整生命周期。
```mermaid
sequenceDiagram
participant Ext as 外部系统
participant API as FastAPI入口
participant DB as SQLite数据库
participant Router as 路由服务
participant Target as 目标系统
participant Notifier as 通知服务
participant Channel as IM渠道(飞书/企微)
participant Log as 日志服务
Note over Ext, API: 1. 请求接入
Ext->>API: POST /webhook/{namespace} (Payload)
activate API
API->>DB: 校验 Namespace 是否有效/启用
alt Namespace 无效/禁用
API-->>Ext: 403 Forbidden
else Namespace 有效
API->>API: 解析 Payload (remark, event_no, trans_amt...)
par 2. 并行处理 - 转发 (Relay)
API->>Router: 使用规则引擎匹配路由规则
Router->>DB: 查询 ProcessingRule/RuleAction/Target
Router-->>API: 返回目标列表 [Target A, Target B]
loop 对每个目标
API->>Target: POST /target_url (异步 + 重试机制)
Target-->>API: 响应 (200 OK / 500 Error)
end
and 3. 并行处理 - 通知 (Notify)
API->>Notifier: notify(event_no, payload)
Notifier->>DB: 查询 ProcessingRule/RuleAction/MessageTemplate/NotificationChannel
Notifier->>Notifier: 渲染模板 ("【{biz_name}】{pay_method_name} 收款 {trans_amt} 元,状态:{cash_resp_desc},日期:{trans_date}")
Notifier-->>API: 返回消息文本 & 渠道列表
loop 对每个渠道
API->>Channel: POST Webhook (发送消息)
Channel-->>API: 响应结果
end
end
Note over API, Log: 4. 收尾工作
API->>Log: BackgroundTask: 保存 RequestLog & DeliveryLog
Log->>DB: INSERT request_logs, delivery_logs
API-->>Ext: 200 OK (包含 routed/notified 摘要)
end
deactivate API
```
## 3. 数据库实体关系图 (ERD)
展示了用于支撑上述流程的数据库模型结构。
```mermaid
erDiagram
WebhookEndpoint {
int id PK
string namespace "URL路径标识"
string description
bool is_active
datetime created_at
}
ProcessingRule {
int id PK
int endpoint_id FK
int parent_rule_id FK "父规则ID,可为空"
int priority "优先级,高优先级先匹配"
string match_field "如 remark / event_define_no"
string operator "eq/neq/contains/regex"
string match_value "匹配值"
}
RuleAction {
int id PK
int rule_id FK
string action_type "forward/notify"
int target_id FK "转发目标,可空"
int channel_id FK "通知渠道,可空"
int template_id FK "消息模板,可空"
json template_vars "模板变量,键值对"
}
Target {
int id PK
string name
string url
int timeout_ms
}
NotificationChannel {
int id PK
string name
string channel_type "feishu/wecom"
string webhook_url
}
MessageTemplate {
int id PK
string name "模板名称"
text template_content "模板内容"
}
RequestLog {
int id PK
string namespace
string remark "来源标识"
string event_no "事件类型"
json raw_body "原始数据"
datetime received_at
string status "success/error"
}
DeliveryLog {
int id PK
int request_id FK
string target_name
string type "relay/notify"
string status "success/failed"
text response_summary
datetime created_at
}
WebhookEndpoint ||--|{ ProcessingRule : "拥有多条规则"
ProcessingRule ||--|{ ProcessingRule : "树形子规则"
ProcessingRule ||--|{ RuleAction : "每条规则包含多个动作"
RuleAction }o--|| Target : "转发到目标"
RuleAction }o--|| NotificationChannel : "推送到渠道"
RuleAction }o--|| MessageTemplate : "使用消息模板"
RequestLog ||--|{ DeliveryLog : "包含多条分发记录"
```
@@ -0,0 +1,27 @@
# 原子任务清单
## T1 配置加载
- 输入:`config/config.yml`
- 输出:内存配置对象与查询API
- 验收:能返回目标、remark与事件模板
## T2 模型解析
- 输入:请求JSON
- 输出:`IncomingPayload` 对象
- 验收:示例JSON解析字段正确
## T3 路由与转发
- 输入:`remark` 与目标列表
- 输出:并发POST结果数组
- 验收:`imcgcd03` 路由到 `target_3`
## T4 通知消息
- 输入:`event_define_no` 与负载
- 输出:消息文本与渠道推送结果
- 验收:`pay.ali_scaned` 生成正确文本并推送
## T5 接口与容器
- 输入:应用代码
- 输出:FastAPI端点与Dockerfile
- 验收:健康检查与示例数据POST通过