- 页头只保留品牌与操作图标,三栏改为 1:2:1、容器最宽 1320 - 任务卡片:状态标签移入标题行并缩小,隐藏任务标识,操作行贴内容底边 - uv 配置弹窗:删掉与首页重复的状态条,三段配置改成标签页 - 镜像源:弹窗去掉默认镜像汇总,首页卡片改为展示默认镜像与运行时注入的变量 - 后端:迁移合并为单一基线 0001_init,删掉未生效的 concurrency_policy / retry_*, 运行触发只剩 schedule / manual;contracts、前端生成类型、README / PLAN 同步
18 KiB
TaskPilot 开发计划
更新时间:2026-10-18 目标后端:Rust 目标前端:React 首要平台:Windows 当前阶段:Phase 6 已完成,项目进入维护与迭代
1. 项目目标
将现有的单文件 HTML 原型升级为一个真实可用的本地定时任务管理平台,满足以下核心场景:
- 创建、编辑、启用、停用和删除定时任务。
- 使用 Cron 表达式按计划自动执行任务,也可以手动立即执行。
- 支持脚本、HTTP 请求和 Windows 二进制进程三类任务。
- 实时展示任务状态、下次执行时间和每次运行结果。
- 查看真实 stdout、stderr、退出码和耗时。
- 任务配置和运行历史在重启后仍然保留。
- 超时或取消时可靠终止目标进程及其子进程。
- React 前端成为真实 API 的使用者,不再用静态数据或
alert模拟成功。
首版范围
- Windows 单机部署。
- 单用户、本地运行,默认只监听
127.0.0.1。 - 单后端实例。
- SQLite 持久化。
- 同一任务默认不并发执行,重叠触发时跳过并记录原因。
- 日志按运行实例保存,并配置容量和保留期限。
暂不纳入首版
- 多租户、登录和远程用户管理。
- 多机分布式调度。
- DAG、任务依赖和分布式队列。
- 集群高可用。
- 跨平台进程树管理。
- 移动端专用应用。
这些能力在单机版本稳定后再评估,避免首版范围过大。
2. 当前基线
仓库目前只有 task_pilot.html 和文档,没有前后端工程。现有页面具备完整视觉原型,但运行、删除、保存和日志均为演示行为。
已确认的本地工具链:
| 工具 | 版本 | 来源 |
|---|---|---|
| Volta | 2.0.2 | 本地安装 |
| Node.js | 24.12.0 | Volta |
| npm | 11.6.2 | Volta |
| pnpm | 11.20.0 | Volta |
| Rust | 1.95.0 | stable-x86_64-pc-windows-msvc |
| Cargo | 1.95.0 | 本地 Rust 工具链 |
开发时使用 pnpm,并通过 package.json 的 volta 字段固定 Node.js 和 pnpm 版本。Rust 使用 rust-toolchain.toml 固定 MSVC 工具链。
3. 技术方案
3.1 前端
- React + TypeScript + Vite。
- pnpm 作为包管理器,Volta 固定工具版本。
- React Router 管理任务列表和任务详情路由。
- TanStack Query 管理服务端状态、缓存、刷新和错误状态。
- React Hook Form + Zod 管理表单和前端校验。
- 原生
fetch封装类型化 API 客户端。 - 沿用现有 CSS 变量和视觉语言,组件样式使用 CSS Modules,不先引入大型 UI 框架。
- Vitest + React Testing Library 进行单元和组件测试。
- Playwright 进行关键业务流程端到端测试。
3.2 后端
- Rust + Axum + Tokio。
- Serde 定义 API 和持久化 DTO。
- SQLx + SQLite 负责迁移、查询和事务。
tracing+tracing-subscriber输出结构化运行日志。reqwest执行 HTTP 任务。- Windows Job Object 管理子进程树,实现超时和取消时的可靠终止。
- SSE 或轮询先用于运行状态与日志更新,后续再评估 WebSocket。
- Cron 引擎在 Phase 1 通过小型 POC 选定,必须支持动态增删任务、秒级 Cron、时区和下次执行时间计算。
初步候选为 tokio-cron-scheduler。进入正式实现前需要验证其维护状态、Cron 语义和动态任务能力;如果不能满足要求,则改用 Cron 解析 crate 与自建 Tokio 调度循环。
3.3 接口契约
- 后端 DTO 是 API 数据的唯一来源。
- 使用 OpenAPI 生成接口描述,并提交稳定快照供前端生成 TypeScript 类型。
- 前端不得手写与后端重复的 DTO 类型。
- 接口变更时,必须同时更新 OpenAPI 快照、生成类型和契约测试。
3.4 总体结构
React SPA
|
| REST /api/v1 + SSE
v
Axum HTTP API
|
+--> Task Service --> SQLite
|
+--> Scheduler
|
+--> Script Executor
+--> HTTP Executor
+--> Process Executor
|
+--> Windows Job Object
+--> Log Capture
计划目录结构:
task_pilot/
├── backend/
│ ├── Cargo.toml
│ ├── migrations/
│ ├── src/
│ └── tests/
├── frontend/
│ ├── package.json
│ ├── src/
│ └── tests/
├── contracts/
│ └── openapi.json
├── docs/
│ └── decisions/
├── task_pilot.html # 迁移完成前保留作视觉参考
├── PLAN.md
├── README.md
└── rust-toolchain.toml
4. 核心数据模型
4.1 Task
Task
├── id 用户可读的唯一任务标识
├── name 显示名称
├── cron 5 位或 6 位 Cron 表达式
├── timezone 默认使用系统时区,可选择 IANA 时区
├── enabled 是否参与自动调度
├── timeout_secs 单次执行超时
├── action 带 type 标签的任务动作
├── created_at
└── updated_at
4.2 Action
Action
├── script
│ ├── working_dir
│ ├── interpreter
│ ├── script
│ ├── args[]
│ └── env{}
├── http
│ ├── url
│ ├── method
│ ├── headers{}
│ ├── body
│ └── expected_status[]
└── process
├── executable
├── working_dir
├── args[]
└── env{}
- 参数必须使用结构化数组,禁止默认经过 Shell 拼接。
- 环境变量需要区分普通值和敏感值;敏感值返回前端时使用遮罩。
- 路径、URL、超时、Cron 和任务类型必须执行后端校验。
4.3 TaskRun
TaskRun
├── id
├── task_id
├── trigger schedule / manual / retry
├── status queued / running / succeeded / failed / timed_out / cancelled / skipped
├── started_at
├── finished_at
├── duration_ms
├── exit_code
├── error_message
└── logs
5. API 草案
所有业务接口使用 /api/v1 前缀。
| 方法 | 路径 | 用途 |
|---|---|---|
GET |
/api/v1/health |
健康检查 |
GET |
/api/v1/tasks |
查询任务,支持搜索、筛选和分页 |
POST |
/api/v1/tasks |
创建任务 |
GET |
/api/v1/tasks/{id} |
查询任务详情 |
PUT |
/api/v1/tasks/{id} |
更新任务 |
DELETE |
/api/v1/tasks/{id} |
删除任务 |
POST |
/api/v1/tasks/{id}/enable |
启用任务 |
POST |
/api/v1/tasks/{id}/disable |
停用任务 |
POST |
/api/v1/tasks/{id}/run |
手动执行 |
GET |
/api/v1/tasks/{id}/runs |
查询运行历史 |
GET |
/api/v1/runs/{run_id} |
查询单次运行结果 |
GET |
/api/v1/runs/{run_id}/logs |
分页或增量读取日志 |
GET |
/api/v1/events |
SSE 状态与日志事件 |
统一错误结构至少包含:
{
"code": "TASK_CRON_INVALID",
"message": "Cron expression is invalid",
"field": "cron",
"details": {}
}
6. 里程碑
Phase 0:工程基线
状态:已完成
状态:进行中
- 盘点现有 HTML 原型和功能。
- 生成项目 README。
- 确认 Volta、Node.js、pnpm 和 Rust 工具链。
- 制定本开发计划。
- 为 Cron 引擎和静态资源托管方式编写 ADR。
验收:计划中的技术边界明确,后续任务有清晰顺序。
Phase 1:工程脚手架与契约
状态:已完成(2026-10-18)
- 创建
frontend/React + TypeScript + Vite 工程。 - 通过 Volta 固定 Node.js 24.12.0 和 pnpm 11.20.0。
- 创建
backend/Axum 工程并固定 Rust 1.95.0。 - 配置 Vite 开发代理到 Rust API。
- 提供
/api/v1/health。 - 配置 Cargo fmt、clippy、test,以及前端 lint、typecheck、test、build。
- 添加 OpenAPI 生成与前端类型生成脚本。
- 确定 Cron 引擎依赖并完成 POC。
- 保留旧 HTML,作为迁移期间的视觉参考。
验收:
pnpm install、pnpm build、cargo test和cargo clippy可执行。- 前端开发服务器能够通过代理访问 Rust 健康检查。
- OpenAPI 快照可以重复生成,前后端对接口类型没有手工漂移。
Phase 2:任务 CRUD 与持久化
状态:已完成(2026-10-18)
- 创建 SQLite 迁移和任务表。
- 实现领域模型、仓储层和服务层。
- 实现任务列表、详情、创建、更新、删除接口。
- 实现 Cron、时区、超时、路径和 Action 类型校验。
- 实现统一 API 错误格式。
- 增加任务列表搜索、筛选和分页参数。
- 为 CRUD、校验和持久化编写后端测试。
说明:独立启停接口调整到 Phase 3,与调度器注册和取消同时实现,避免产生只改数据库但不更新调度的中间状态。
验收:
- 创建三类任务后重启进程,数据仍然存在。
- 非法 Cron、空路径、无效 URL 和错误 Action 字段被后端拒绝。
- 删除不存在的任务返回明确错误,而不是成功提示。
Phase 3:调度器与脚本任务闭环
状态:已完成(2026-10-18)
- 启动时从 SQLite 加载启用任务并注册调度。
- 支持创建、更新、启停和删除任务时动态刷新调度。
- 实现手动立即执行。
- 实现脚本任务执行,使用结构化参数,不经过 Shell。
- 捕获 stdout、stderr、退出码和耗时。
- 实现同一任务并发触发时跳过。
- 通过 Windows Job Object 实现超时和取消时的进程树终止。
- 记录每次运行状态并处理进程异常退出。
- 引入确定性时间计算测试和实时秒级调度测试,验证调度逻辑。
验收:
- 创建一个每秒执行的临时脚本任务后,自动运行并生成可查看日志。
- 超时脚本及其子进程被终止,运行状态为
timed_out。 - 后端重启后调度恢复,错过的历史运行不会批量重复执行。
- 前端尚未接入前,可通过 API 完整验证脚本任务链路。
Phase 4:React 前端迁移与垂直切片
状态:已完成(2026-10-18)
- 将现有页面拆分为布局、指标卡、任务表格、任务编辑器和日志查看器。
- 接入真实任务列表、详情、创建、更新、删除和启停 API。
- 接入手动运行 API,并展示
queued/running/succeeded/failed状态。 - 使用表单校验替代浏览器无效的
required假象。 - 根据 Action 类型提交完整、不同的载荷。
- 实现加载、空数据、失败、重试和保存中状态。
- 日志页面先使用轮询读取真实运行日志。
- 移除伪造的成功提示和静态任务数据。
验收:
- 页面中的每个 CRUD、启停和手动运行操作都对应真实 API。
- 刷新页面后任务状态与 SQLite 一致。
- HTTP 和进程任务不会在尚未实现执行器时被错误提交为脚本任务。
- 表单错误能定位到具体字段,Cron 校验错误来自前后端一致结果。
Phase 5:HTTP、进程任务与实时日志
状态:已完成(2026-10-18)
- 实现 HTTP Executor,支持 GET/POST、Header、Body 和期望状态码。
- 实现二进制进程 Executor。
- 将 SSE 接入任务状态和日志增量更新,轮询作为降级方案。
- 支持取消正在运行的任务。
- 增加运行历史列表、状态/触发筛选、退出码、错误摘要和日志下载。
- 实现日志大小上限、保留期限和清理策略。
- 对敏感环境变量和 Header 值进行输入遮罩,并在日志中脱敏。
验收:
- 三类任务均可从 React 页面创建、执行和查看结果。
- 运行中日志可以持续更新,完成后状态正确收敛。
- HTTP 非预期状态码和进程非零退出码能明确标记失败。
- 取消或超时不会遗留目标进程树。
Phase 6:质量、安全与交付
状态:已完成(2026-10-18)
- 补齐后端单元、集成和 Windows 平台测试。
- 补齐前端组件测试和 Playwright 主流程测试。
- 完成键盘导航、焦点管理、ARIA 和窄屏布局。
- 移除所有用户输入的
innerHTML拼接,统一安全文本渲染。 - 后端默认绑定
127.0.0.1,配置严格 CORS 和 Origin 校验。 - 增加本地管理令牌或等价的本机接口保护方案。
- 检查路径逃逸、命令注入、日志注入和敏感信息泄露。
- 由 Axum 托管生产构建后的 React 静态资源。
- 提供一键启动脚本、生产构建说明和故障排查文档。
- 更新 README,并评审是否将旧 HTML 移入
legacy/。
说明:旧 task_pilot.html 暂时保留在根目录作为视觉参考;正式运行入口为 React 构建产物。
验收:
- 完整测试、格式检查、静态检查和前端生产构建通过。
- 单机 Release 构建能够启动、自动打开或明确提示访问地址。
- 关闭程序后,任务数据仍保留;重新启动后启用任务恢复调度。
- README 中的命令全部经过实际验证。
7. 开发顺序与检查点
每个阶段按以下顺序推进:
- 先确定数据模型和 API 契约。
- 实现后端能力并补充自动化测试。
- 通过 API 或命令行验证真实行为。
- 接入 React 页面,不先做没有后端支持的假交互。
- 运行完整检查并更新本计划的勾选状态。
阶段之间保留可运行状态,不进行长期无法启动的大规模重构。旧 HTML 一直保留到 React 版本完成等价迁移。
8. 测试策略
后端
- 单元测试:Cron 校验、任务校验、状态转换、重试和并发策略。
- 集成测试:使用临时 SQLite 验证 CRUD、迁移和重启恢复。
- 调度测试:使用可控时钟验证下次执行时间和动态调度。
- 平台测试:在 Windows 上验证脚本参数、退出码、超时和进程树终止。
- 契约测试:检查 OpenAPI 与实现一致。
前端
- 组件测试:表单类型切换、错误展示、状态徽章和权限式操作可用性。
- API Mock 测试:加载、失败、空数据和重试。
- E2E:创建脚本任务、手动执行、查看日志、编辑、停用和删除。
提交前检查
计划提供以下统一命令,具体脚本在 Phase 1 落地:
# 前端
pnpm --dir frontend lint
pnpm --dir frontend typecheck
pnpm --dir frontend test
pnpm --dir frontend build
# 后端
cargo fmt --manifest-path backend/Cargo.toml --check
cargo clippy --manifest-path backend/Cargo.toml --all-targets -- -D warnings
cargo test --manifest-path backend/Cargo.toml
9. 安全与可靠性约束
- 后端默认只监听本机地址,不默认暴露到局域网。
- 脚本和进程任务使用结构化参数调用,不通过字符串拼接进入 Shell。
- 所有路径在执行前规范化并校验允许范围。
- 用户提交的文本只通过 React 文本节点渲染,禁止直接拼接 HTML。
- 环境变量中的敏感值在列表、详情、日志和错误信息中脱敏。
- stdout/stderr 必须并发读取,避免管道写满导致子进程卡死。
- 所有运行都有超时和取消路径,终止时覆盖子进程树。
- 日志设置单次大小和总容量上限,避免磁盘被无限占用。
- 数据库迁移必须可重复执行,并在失败时给出明确错误。
- 前端不得把请求失败或未接入能力显示为成功。
10. 主要风险
| 风险 | 影响 | 应对 |
|---|---|---|
| Cron crate 语义或动态调度能力不满足要求 | 自动执行时间错误 | Phase 1 POC,覆盖 5/6 位、时区、日和星期语义 |
| Windows 子进程树难以可靠终止 | 超时后遗留进程 | 使用 Job Object,并增加真实 Windows 集成测试 |
| stdout/stderr 处理不当 | 子进程阻塞或日志丢失 | 异步并发读取,设置背压和日志上限 |
| SQLite 与调度器状态不一致 | 重启后漏跑或重复跑 | 事务更新、启动时重建调度、记录运行状态 |
| 前端迁移范围过大 | 长期无法交付 | 先完成脚本任务垂直切片,再扩展三类 Action |
| 敏感环境变量泄露 | 凭据暴露 | 遮罩、日志脱敏,后续接入系统凭据存储 |
| 动态依赖下载受网络影响 | 工程搭建受阻 | 锁定版本和 lockfile,必要时分阶段安装并记录依赖 |
| 本地接口被其他网页调用 | 未授权操作 | localhost 绑定、Origin 校验和本机管理令牌 |
11. MVP 完成标准
满足以下条件后,第一版可以视为完成:
- React 页面完全使用真实 API 数据。
- 任务 CRUD、启停和手动运行形成闭环。
- 脚本、HTTP 和二进制进程任务至少各有一条成功路径和一条失败路径验证。
- Cron 自动调度、时区和下次运行时间可验证。
- 任务配置、运行历史和日志重启后保留。
- 超时和取消可以终止 Windows 进程树。
- 页面能够展示运行中、成功、失败、超时和跳过状态。
- 后端默认仅本机可访问,敏感值不会出现在日志中。
- 自动化测试、格式检查和 Release 构建通过。
12. 后续维护
六个计划阶段已经完成。后续版本优先评估:
- 自动重试与退避策略。
- Windows 服务安装和开机自启。
- 系统凭据存储与更严格的秘密管理。
- 任务模板、导入导出和批量操作。
- 运行指标、告警和长期监控。
- HTTP 响应断言、认证方案和请求重放。
13. 已完成的后继迭代
计划阶段之外已经交付、并已写入 ADR 的改动:
- 本地 uv 管理(ADR-0009):uv 只用程序目录副本或指定路径,
不读系统 PATH;可从科大镜像下载并校验 sha256;
UV_*环境变量可配置,两个路径变量默认相对程序目录(python/uv-cache)。 - 托管虚拟环境:
data/envs/<名称>、uv 下载的 Python 版本管理、预装包与已装包查看。 - 环境时机调整:新建任务保存时用 uv 创建
.venv,运行期只校验;运行任务会注入平台 uv、UV_*与默认UV_DEFAULT_INDEX。 - 界面:顶部品牌栏 + 三栏工作台,uv / 镜像源 / 虚拟环境各自独立弹窗(uv 与镜像源不再同页)。