# 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 总体结构 ```text 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 ``` 计划目录结构: ```text 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 ```text 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 ```text 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 ```text 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 状态与日志事件 | 统一错误结构至少包含: ```json { "code": "TASK_CRON_INVALID", "message": "Cron expression is invalid", "field": "cron", "details": {} } ``` ## 6. 里程碑 ### Phase 0:工程基线 状态:已完成 状态:进行中 - [x] 盘点现有 HTML 原型和功能。 - [x] 生成项目 README。 - [x] 确认 Volta、Node.js、pnpm 和 Rust 工具链。 - [x] 制定本开发计划。 - [x] 为 Cron 引擎和静态资源托管方式编写 ADR。 验收:计划中的技术边界明确,后续任务有清晰顺序。 ### Phase 1:工程脚手架与契约 状态:已完成(2026-10-18) - [x] 创建 `frontend/` React + TypeScript + Vite 工程。 - [x] 通过 Volta 固定 Node.js 24.12.0 和 pnpm 11.20.0。 - [x] 创建 `backend/` Axum 工程并固定 Rust 1.95.0。 - [x] 配置 Vite 开发代理到 Rust API。 - [x] 提供 `/api/v1/health`。 - [x] 配置 Cargo fmt、clippy、test,以及前端 lint、typecheck、test、build。 - [x] 添加 OpenAPI 生成与前端类型生成脚本。 - [x] 确定 Cron 引擎依赖并完成 POC。 - [x] 保留旧 HTML,作为迁移期间的视觉参考。 验收: - `pnpm install`、`pnpm build`、`cargo test` 和 `cargo clippy` 可执行。 - 前端开发服务器能够通过代理访问 Rust 健康检查。 - OpenAPI 快照可以重复生成,前后端对接口类型没有手工漂移。 ### Phase 2:任务 CRUD 与持久化 状态:已完成(2026-10-18) - [x] 创建 SQLite 迁移和任务表。 - [x] 实现领域模型、仓储层和服务层。 - [x] 实现任务列表、详情、创建、更新、删除接口。 - [x] 实现 Cron、时区、超时、路径和 Action 类型校验。 - [x] 实现统一 API 错误格式。 - [x] 增加任务列表搜索、筛选和分页参数。 - [x] 为 CRUD、校验和持久化编写后端测试。 说明:独立启停接口调整到 Phase 3,与调度器注册和取消同时实现,避免产生只改数据库但不更新调度的中间状态。 验收: - 创建三类任务后重启进程,数据仍然存在。 - 非法 Cron、空路径、无效 URL 和错误 Action 字段被后端拒绝。 - 删除不存在的任务返回明确错误,而不是成功提示。 ### Phase 3:调度器与脚本任务闭环 状态:已完成(2026-10-18) - [x] 启动时从 SQLite 加载启用任务并注册调度。 - [x] 支持创建、更新、启停和删除任务时动态刷新调度。 - [x] 实现手动立即执行。 - [x] 实现脚本任务执行,使用结构化参数,不经过 Shell。 - [x] 捕获 stdout、stderr、退出码和耗时。 - [x] 实现同一任务并发触发时跳过。 - [x] 通过 Windows Job Object 实现超时和取消时的进程树终止。 - [x] 记录每次运行状态并处理进程异常退出。 - [x] 引入确定性时间计算测试和实时秒级调度测试,验证调度逻辑。 验收: - 创建一个每秒执行的临时脚本任务后,自动运行并生成可查看日志。 - 超时脚本及其子进程被终止,运行状态为 `timed_out`。 - 后端重启后调度恢复,错过的历史运行不会批量重复执行。 - 前端尚未接入前,可通过 API 完整验证脚本任务链路。 ### Phase 4:React 前端迁移与垂直切片 状态:已完成(2026-10-18) - [x] 将现有页面拆分为布局、指标卡、任务表格、任务编辑器和日志查看器。 - [x] 接入真实任务列表、详情、创建、更新、删除和启停 API。 - [x] 接入手动运行 API,并展示 `queued/running/succeeded/failed` 状态。 - [x] 使用表单校验替代浏览器无效的 `required` 假象。 - [x] 根据 Action 类型提交完整、不同的载荷。 - [x] 实现加载、空数据、失败、重试和保存中状态。 - [x] 日志页面先使用轮询读取真实运行日志。 - [x] 移除伪造的成功提示和静态任务数据。 验收: - 页面中的每个 CRUD、启停和手动运行操作都对应真实 API。 - 刷新页面后任务状态与 SQLite 一致。 - HTTP 和进程任务不会在尚未实现执行器时被错误提交为脚本任务。 - 表单错误能定位到具体字段,Cron 校验错误来自前后端一致结果。 ### Phase 5:HTTP、进程任务与实时日志 状态:已完成(2026-10-18) - [x] 实现 HTTP Executor,支持 GET/POST、Header、Body 和期望状态码。 - [x] 实现二进制进程 Executor。 - [x] 将 SSE 接入任务状态和日志增量更新,轮询作为降级方案。 - [x] 支持取消正在运行的任务。 - [x] 增加运行历史列表、状态/触发筛选、退出码、错误摘要和日志下载。 - [x] 实现日志大小上限、保留期限和清理策略。 - [x] 对敏感环境变量和 Header 值进行输入遮罩,并在日志中脱敏。 验收: - 三类任务均可从 React 页面创建、执行和查看结果。 - 运行中日志可以持续更新,完成后状态正确收敛。 - HTTP 非预期状态码和进程非零退出码能明确标记失败。 - 取消或超时不会遗留目标进程树。 ### Phase 6:质量、安全与交付 状态:已完成(2026-10-18) - [x] 补齐后端单元、集成和 Windows 平台测试。 - [x] 补齐前端组件测试和 Playwright 主流程测试。 - [x] 完成键盘导航、焦点管理、ARIA 和窄屏布局。 - [x] 移除所有用户输入的 `innerHTML` 拼接,统一安全文本渲染。 - [x] 后端默认绑定 `127.0.0.1`,配置严格 CORS 和 Origin 校验。 - [x] 增加本地管理令牌或等价的本机接口保护方案。 - [x] 检查路径逃逸、命令注入、日志注入和敏感信息泄露。 - [x] 由 Axum 托管生产构建后的 React 静态资源。 - [x] 提供一键启动脚本、生产构建说明和故障排查文档。 - [x] 更新 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 落地: ```powershell # 前端 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](docs/decisions/0009-uv-and-managed-environments.md)):uv 只用程序目录副本或指定路径, 不读系统 PATH;可从科大镜像下载并校验 sha256;`UV_*` 环境变量可配置,两个路径变量默认相对程序目录(`python` / `uv-cache`)。 - **托管虚拟环境**:`data/envs/<名称>`、uv 下载的 Python 版本管理、预装包与已装包查看。 - **环境时机调整**:新建任务保存时用 uv 创建 `.venv`,运行期只校验;运行任务会注入平台 uv、`UV_*` 与默认 `UV_DEFAULT_INDEX`。 - **界面**:顶部品牌栏 + 三栏工作台,uv / 镜像源 / 虚拟环境各自独立弹窗(uv 与镜像源不再同页)。