Files
HarborForge/CALENDAR_DESIGN.md

275 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:**
```json
{
"type": "Task|Support|Meeting",
"code": "TASK-42",
"working_sessions": ["session-id-1", "session-id-2"]
}
```
**SystemEvent:**
```json
{
"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最小工作量配置
```json
{
"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 被 `edit``cancel` 时,物化到数据库,获得真实 ID同时该日期该 plan 不再生成虚拟 slot
---
## 三、存储与缓存策略
### 3.1 Plan 不预展开
Plan 只存规则,不为每一天生成数据行。
### 3.2 物化时机
以下情况写入 time_slots 表:
1. `hf calendar schedule` 手动创建
2. Plan 的虚拟 slot 被 `edit``cancel`(物化后断开 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 日程操作
```bash
# 创建单次日程
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 计划操作
```bash
# 创建周期性计划
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 支持)
```bash
hf user create <username> [--agent-id <id>] [--claw-identifier <id>] ...
```
- `--agent-id` + `--claw-identifier` 必须同时出现或同时不出现
- pcexec 模式下:
- `--agent-id``$AGENT_ID`
- `--claw-identifier``openclaw 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 唤醒的提示词模板