Version: 0.9.59.dev.260430

后端:
1. 主动调度预览确认主链路落地——新增主动调度数据模型、DAO 与事件契约;接入 dry-run pipeline 与任务触发的 job upsert/cancel;新增 preview 查询与 confirm API,支持 apply_id 幂等确认并同步写入 task_pool 日程
2. 同步更新主动调度实施文档的阶段状态与验收记录

前端:
3. AssistantPanel 脚本层继续解耦——私有类型迁移到独立类型文件,并抽离会话、工具轨迹、思考摘要、任务表单等纯函数辅助逻辑;保持助手面板模板与样式不变,降低表现层回归风险
This commit is contained in:
LoveLosita
2026-04-30 12:05:15 +08:00
parent 1555042e80
commit e945578fbf
38 changed files with 10267 additions and 580 deletions

View File

@@ -0,0 +1,82 @@
package events
import (
"errors"
"strconv"
"strings"
"time"
)
const (
NotificationFeishuRequestedEventType = "notification.feishu.requested"
NotificationFeishuRequestedEventVersion = "1"
)
// FeishuNotificationRequestedPayload 是飞书通知请求事件载荷。
//
// 职责边界:
// 1. 只描述“需要尝试发送一条飞书提醒”的跨模块协议;
// 2. 不包含 provider SDK 参数,也不复用 notification_records 的 GORM model
// 3. 不决定是否真正投递,去重、配置关闭和重试由 notification 模块处理。
type FeishuNotificationRequestedPayload struct {
NotificationID int64 `json:"notification_id,omitempty"`
UserID int `json:"user_id"`
TriggerID string `json:"trigger_id"`
PreviewID string `json:"preview_id"`
TriggerType string `json:"trigger_type"`
TargetType string `json:"target_type"`
TargetID int `json:"target_id"`
DedupeKey string `json:"dedupe_key"`
TargetURL string `json:"target_url"`
SummaryText string `json:"summary_text,omitempty"`
FallbackText string `json:"fallback_text,omitempty"`
TraceID string `json:"trace_id,omitempty"`
RequestedAt time.Time `json:"requested_at"`
}
// Validate 校验飞书通知事件的协议级必填字段。
//
// 职责边界:
// 1. 只保证通知 handler 能定位用户、预览和去重键;
// 2. 不校验用户是否绑定飞书,也不调用 provider
// 3. target_url 必须是站内相对路径,避免事件载荷携带任意外部跳转。
func (p FeishuNotificationRequestedPayload) Validate() error {
if p.UserID <= 0 {
return errors.New("user_id 必须大于 0")
}
if strings.TrimSpace(p.PreviewID) == "" {
return errors.New("preview_id 不能为空")
}
if strings.TrimSpace(p.DedupeKey) == "" {
return errors.New("dedupe_key 不能为空")
}
targetURL := strings.TrimSpace(p.TargetURL)
if targetURL == "" {
return errors.New("target_url 不能为空")
}
if !strings.HasPrefix(targetURL, "/schedule-adjust/") {
return errors.New("target_url 必须是 /schedule-adjust/{preview_id} 站内相对路径")
}
if strings.Contains(targetURL, "://") || strings.HasPrefix(targetURL, "//") {
return errors.New("target_url 不允许携带外部链接")
}
if p.RequestedAt.IsZero() {
return errors.New("requested_at 不能为空")
}
return nil
}
// MessageKey 返回 outbox/Kafka 消息键。
func (p FeishuNotificationRequestedPayload) MessageKey() string {
if p.UserID <= 0 {
return ""
}
return strconv.Itoa(p.UserID)
}
// AggregateID 返回事件聚合 ID。
//
// 说明notification.feishu.requested 使用 preview_id 串联通知与预览。
func (p FeishuNotificationRequestedPayload) AggregateID() string {
return strings.TrimSpace(p.PreviewID)
}