Files
HarborForge/CALENDAR_DESIGN.md

8.3 KiB
Raw Blame History

HarborForge Calendar System — Design Document

Date: 2026-03-22


Overview

为 HarborForge 新增日程表Calendar系统支持 Agent/人类用户的任务调度、周期性计划、以及通过 OpenClaw 插件心跳自动唤醒 Agent 执行日程。

同时包含一个 bug fixacc-mgr 用户密码不可修改,前端隐藏修改密码入口。


一、数据模型

1.1 TimeSlot日程槽

字段 类型 说明
slot_id int (PK) 已物化 slot 的数据库 ID
user_id FK -> users.id 所属用户
date date 日期
slot_type Enum(Work, OnCall, Entertainment, System) 槽类型
estimated_duration int (1-50) 预估时长(分钟),设计上限 50 分钟,超过需拆分
scheduled_at time (00:00-23:00) 计划开始时间
started_at time, nullable 实际开始时间
attended bool, default false 是否已出席
actual_duration int (0-65535), nullable 实际时长(分钟),无上限
event_type Enum(Job, Entertainment, SystemEvent), nullable 事件类型
event_data JSON, nullable 事件详情(见下方 Event 子类型)
priority int (0-99) 优先级
status Enum(NotStarted, Ongoing, Deferred, Skipped, Paused, Finished, Aborted) 状态
plan_id FK -> schedule_plans.id, nullable 来源计划(物化自 plan 时填入,被 edit/cancel 后置 NULL
created_at datetime 创建时间
updated_at datetime 更新时间

1.2 Event 子类型(存储在 event_data JSON 中)

Job:

{
  "type": "Task|Support|Meeting",
  "code": "TASK-42",
  "working_sessions": ["session-id-1", "session-id-2"]
}

SystemEvent:

{
  "event": "ScheduleToday|SummaryToday"
}

Entertainment:

待设计

1.3 SchedulePlan周期性计划

字段 类型 说明
id int (PK) plan-id
user_id FK -> users.id 所属用户
slot_type Enum(Work, OnCall, Entertainment, System) 槽类型
estimated_duration int (1-50) 预估时长
event_type Enum(Job, Entertainment, SystemEvent), nullable 事件类型
event_data JSON, nullable 事件详情
at_time time 每天的计划时间 (--at HH:mm)
on_day Enum(Sun, Mon, Tue, Wed, Thu, Fri, Sat), nullable 星期几 (--on-day)
on_week int (1-4), nullable 第几周 (--on-week)
on_month Enum(Jan-Dec), nullable 月份 (--on-month)
created_at datetime 创建时间
updated_at datetime 更新时间

周期参数层级约束:

  • 使用 --on-month--on-week 必须也用
  • 使用 --on-week--on-day 必须也用
  • --at 始终必填

示例:

  • --at 09:00 --on-day Sun --on-week 1 --on-month Jan → 每年一月第一周周日 09:00
  • --at 09:00 --on-day Sun --on-week 1 → 每月第一周周日 09:00
  • --at 09:00 --on-day Sun → 每周日 09:00
  • --at 09:00 → 每天 09:00

1.4 Agent 表

字段 类型 说明
id int (PK)
user_id FK -> users.id, UNIQUE 关联用户
agent_id VARCHAR, UNIQUE OpenClaw agent name ($AGENT_ID)
claw_identifier VARCHAR OpenClaw 实例 identifier与 Monitor 碰巧一致,无 FK
status Enum(Idle, OnCall, Busy, Exhausted, Offline), default Idle Agent 当前状态
last_heartbeat datetime, nullable 最后心跳时间
created_at datetime 创建时间

1.5 MinimumWorkload最小工作量配置

{
  "daily":   { "work": 0, "on_call": 0, "entertainment": 0 },
  "weekly":  { "work": 0, "on_call": 0, "entertainment": 0 },
  "monthly": { "work": 0, "on_call": 0, "entertainment": 0 },
  "yearly":  { "work": 0, "on_call": 0, "entertainment": 0 }
}

值为分钟数 (0-65535)。存储方式待定(可作为用户级配置存 JSON 字段或独立表)。


二、Slot ID 策略

  • 已物化的 slot:使用数据库自增 ID
  • Plan 虚拟 slot(未物化):使用 plan-{plan_id}-{date} 格式
  • 当虚拟 slot 被 editcancel 时,物化到数据库,获得真实 ID同时该日期该 plan 不再生成虚拟 slot

三、存储与缓存策略

3.1 Plan 不预展开

Plan 只存规则,不为每一天生成数据行。

3.2 物化时机

以下情况写入 time_slots 表:

  1. hf calendar schedule 手动创建
  2. Plan 的虚拟 slot 被 editcancel(物化后断开 plan 关联)
  3. 每天预计算:服务器每日将当天所有 plan 匹配的 slot 物化到缓存/数据库

3.3 当日缓存

  • 每天(凌晨或首次心跳时)预计算当天所有 plan → 物化为当日 slot 缓存
  • 当天新增 schedule / plan-schedule 影响当天时,同步更新缓存

3.4 不可变性

  • cancel / edit 不能操作过去的 slot
  • plan-cancel / plan-edit 不追溯过去已物化的 slot

四、时区

统一使用 HarborForge 服务器时区,不做用户级时区。


五、验证规则

schedule / plan-schedule 提交时验证:

  1. Overlap 检测:与同日已有 slot 时间重叠 → 拒绝,报错
  2. 最小工作量检查:不满足 MinimumWorkload 配置 → 警告,但允许提交

六、Agent 唤醒机制

6.1 心跳流程

  1. 插件每分钟向 HarborForge 服务器发送心跳
  2. 服务器返回该插件claw_identifier对应所有 Agent 当前需要执行的日程
    • 筛选条件:当天 slotstatus 为 NotStarted 或 Deferredscheduled_at 已过
  3. 插件检查 Agent 状态

6.2 唤醒逻辑

Agent 状态为 Idle

  • 唤醒 Agent提供提示词开始工作
  • 向服务器设置 Agent status = Busy 或 OnCall取决于 slot_type
  • 设置 slot: attended = true, started_at = now, status = Ongoing

Agent 状态非 Idle

  • 设置 slot status = Deferred

6.3 多 Slot 竞争

  • 选 priority 最高的执行,其余 Deferred 且 priority += 1
  • 通知 Agent 当前任务完成后重新规划所有 Deferred + NotStarted 的 slot

6.4 状态转移

触发条件 Agent Status 变化
超过 2 分钟无心跳 → Offline
无待执行日程 → Idle
被 TimeSlot 唤醒 → Busy / OnCall
完成 TimeSlot → Idle

七、CLI 命令

7.1 日程操作

# 创建单次日程
hf calendar schedule <slot-type> <scheduled-at> <estimated-duration> \
  [--job <code>] [--date <yyyy-mm-dd>]

# 查看某天日程
hf calendar show [--date <yyyy-mm-dd>]

# 取消日程plan 来源的 slot 物化后断开 plan
hf calendar cancel [--date <yyyy-mm-dd>] <slot-id>

# 编辑日程plan 来源的 slot 物化后断开 plan
hf calendar edit [--date <yyyy-mm-dd>] <slot-id> \
  [--slot-type <type>] [--estimated-duration <mins>] \
  [--job <code>] [--scheduled-at <HH:mm>]

# 列出所有有已物化日程的未来日期(纯 plan 的不算)
hf calendar date-list

7.2 计划操作

# 创建周期性计划
hf calendar plan-schedule <slot-type> <estimated-duration> \
  --at <HH:mm> [--on-day <day>] [--on-week <1-4>] [--on-month <month>]

# 列出所有计划
hf calendar plan-list

# 取消计划(不追溯过去)
hf calendar plan-cancel <plan-id>

# 编辑计划(不追溯过去)
hf calendar plan-edit <plan-id> \
  [--at <HH:mm>] [--on-day <day>] [--on-week <1-4>] [--on-month <month>] \
  [--slot-type <type>] [--estimated-duration <mins>]

7.3 用户创建Agent 支持)

hf user create <username> [--agent-id <id>] [--claw-identifier <id>] ...
  • --agent-id + --claw-identifier 必须同时出现或同时不出现
  • pcexec 模式下:
    • --agent-id$AGENT_ID
    • --claw-identifieropenclaw config get plugins.harbor-forge.identifier
  • 后端 POST /users 扩展:接受 agent_id + claw_identifier,创建 User 同时写入 agents 表

八、前端

  • 每个用户可查看/调整自己的日程表
  • Admin 可查看/调整所有用户的日程表
  • 日程表页面展示(具体 UI 待设计)

九、Bug Fix

  • acc-mgr 用户后端禁止修改密码admin 也不行)
  • 前端acc-mgr 用户不显示修改密码入口

十、待定项

  • Entertainment 事件子类型设计
  • MinimumWorkload 存储方式JSON 字段 vs 独立表)
  • 前端日程表 UI 详细设计
  • Agent 唤醒的提示词模板