Files
task_pilot/PLAN.md
T
CNWei 37479f48c7 docs: 更新 uv 与虚拟环境文档
- README:三栏工作台与弹窗说明、uv 路径默认值(python / uv-cache)、镜像只在装包时生效、API 与数据布局、测试现状注记

- RELEASE:补 uv-cache 与 uv 目录、配置入口改为弹窗、运行时注入说明

- 新增 ADR-0009:uv 与托管 Python 环境的决策与边界

- PLAN:补记已完成的后继迭代
2026-11-07 17:05:02 +08:00

18 KiB
Raw Blame History

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       单次执行超时
├── concurrency_policy 首版固定为 skip
├── retry_policy       首版允许 0 次重试,结构上预留
├── 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. 开发顺序与检查点

每个阶段按以下顺序推进:

  1. 先确定数据模型和 API 契约。
  2. 实现后端能力并补充自动化测试。
  3. 通过 API 或命令行验证真实行为。
  4. 接入 React 页面,不先做没有后端支持的假交互。
  5. 运行完整检查并更新本计划的勾选状态。

阶段之间保留可运行状态,不进行长期无法启动的大规模重构。旧 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. 后续维护

六个计划阶段已经完成。后续版本优先评估:

  1. 自动重试与退避策略。
  2. Windows 服务安装和开机自启。
  3. 系统凭据存储与更严格的秘密管理。
  4. 任务模板、导入导出和批量操作。
  5. 运行指标、告警和长期监控。
  6. 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 与镜像源不再同页)。