Files
UHD_Media_Tool/docs/plan/00-first-version-plan.md
T

22 KiB

首个可用版本(v0.1)工程规划

编制:2026-09-27。需求基线:../../media_automation_requirements_architecture_v0.7.md(下称 REQ)。本文件是所有开发子任务的统一任务书;与 REQ 冲突时以 REQ 的产品要求为准,技术选型以本文件为准。

1. 技术决策(ADR 摘要,详见 docs/adr/)

项 决定 说明
运行时 Deno 2.9.7(锁定)+ TypeScript 7.0.2,deno.json workspace(nodeModulesDir: auto,npm 依赖走 npm: 说明符,deno.lock 锁定) 用户 2026-09-27 确认:按 REQ §9 采用最新稳定版 Deno;之前 W0 用 Node 24 + pnpm 搭的底座在 W1 结束后统一迁移(ADR-004 取代 ADR-001)。前端仍用 Vite 7 + React Router 7 构建,由 Deno 执行。
前端 React 19 + React Router 7(SPA, ssr:false)+ Vite 7 + Tailwind v4 + shadcn(new-york, radix-ui 统一包)+ TanStack Query 5 + zod 4 + sonner + lucide 直接拷贝 uhd_web 的 app/app.css 设计 token、app/components/ui/*、app/lib/api.ts、app/lib/utils.ts、scripts/gen-design-tokens.mjs、scripts/check-design-tokens.sh、docs/features/{design-tokens,interface-materials,ui-controls}.md。不引入 uhd_web 的播放器/WASM 相关内容。
后端 HTTP Hono 4(Deno.serve),REST + SSE OpenAPI 由 zod schema 生成(@hono/zod-openapi)。
数据库 PostgreSQL 16;Kysely + pg;SQL 迁移文件 + Kysely Migrator;kysely-codegen 或手写 DB 类型 开发用 docker-compose 起 postgres:16-alpine,端口 55433。
持久任务引擎 优先 [email protected](peer: postgres.js);须先通过 spike 验证(重启恢复/等待信号/取消/重试)。未通过则用 packages/tasks 内的 PG 租约式任务表(lease + attempts + dead-letter)。 结论写 ADR-002。
Agent 内核 @earendil-works/[email protected] + @earendil-works/[email protected],锁版本;通过自有 AgentRuntimePort 封装,显式工具白名单,不开放 bash/文件系统/任意网络 测试用脚本化 fake 模型 provider;真实上游由设置页配置。
校验/测试 vitest 5(deno run -A npm:vitest run,deno task test 逐成员执行);类型门禁两道:tsc 7.0.2(npm:[email protected],Go 原生实现,入口 tsc)+ deno check(Deno 内置 TS 6.0.3);lint/format 用 biome 2.5.14(开启 useImportExtensions,相对 import 必须带扩展名);web 沿用 token 守卫脚本 deno task ci = typecheck(tsc 7.0.2 + deno check)+ lint + test + check:tokens + build(web 构建 + deno compile 单文件 server)。W1.5 实测(2026-09-27)连跑 3 次全绿,约 75 秒/次(v0.1 验收时已涨到约 135 秒/次,server 与 tasks 测试是主要耗时,见 04);测试数 server 24、adapters 214(+2 skip)、agent 27、contracts 361、db 11、domain 230、tasks 15、testkit 1、web 2
端口 web dev 5180,API 4380,PG 55433 本机 3000/5175/5176/55432 已被占用,不要用
参考源码 MoviePilot v3: /opt/moviepilot-plus/upstream/MoviePilot(提交 e6820a8,GPLv3,只做行为对照与 TS 重写,不复制文件)。数据来源适配(站点 spider、馒头、RSS、TMDB、qB)照抄 MP v3 实现迁移(用户 2026-09-27 明确):app/modules/indexer/spider/__init__.py、spider/mtorrent.py、app/application/rss.py、app/modules/themoviedb/tmdbapi.py、app/modules/qbittorrent/qbittorrent.py;站点定义按 app/application/site/sites.pyi 的 schema 手写(MP 的定义文件 user.sites.v3.bin 是加密的,无法取用)。用户 2026-09-27 追加:MP 开源的站点框架全部移植——所有专用 spider(haidan/hddolby/rousi/sunnypt/tnode/torrentleech/yema/mtorrent)与所有站点类型用户信息解析器(nexus_php/nexus_audiences/nexus_hhanclub/nexus_project/nexus_rabbit/gazelle/unit3d/discuz/ipt/file_list/small_horse/zhixing/bitpt/…),文件与函数一一对应,并维护 docs/porting/mp-sync-ledger.md + scripts/mp-sync 差异脚本,以后跟随 MP 提交增量移植;MovieClaw 若本机不存在则按 REQ 附录链接对照 迁移对照记录写 docs/porting/

2. 仓库结构(Deno workspace)

apps/web            React Router 7 SPA 控制台(复用 uhd_web 设计系统)
apps/server         Node 服务:HTTP API + SSE + worker 入口(单进程可跑,也可 `--role api|worker` 分开)
packages/contracts  zod schema + 类型:所有 API/事件/能力(capability)输入输出的唯一定义,web 与 server 共用
packages/db         Kysely 类型、迁移、仓储辅助
packages/domain     纯业务逻辑(无 IO):标题解析/身份匹配/Slot 满足度/路径绑定/整理计划/策略评估
packages/adapters   外部系统适配:qBittorrent、RSS、站点(观众 NexusPHP / 馒头 API)、TMDB、Emby 兼容、文件系统
packages/tasks      持久任务定义与执行器(OpenWorkflow 或自研租约表),outbox
packages/agent      Pi 接入:AgentRuntimePort、能力注册中心桥接、agent_run 持久化、fake provider
packages/testkit    mock 服务:mock qB WebUI、mock NexusPHP 站点、mock M-Team API、mock RSS、mock TMDB、临时目录夹具
docs/adr            架构决策记录
docs/plan           本规划与里程碑验收清单
docs/porting        MoviePilot/MovieClaw 迁移对照账本(REQ §14.1.2 格式)
docs/spikes         兼容性验证记录
docs/runbook        启动/备份/恢复/配置说明
scripts             dev/ci 辅助脚本

约定:

  • 所有共享类型只在 packages/contracts 定义;web 不得手写与 server 重复的 DTO。
  • packages/domain 不 import 任何 IO 库,100% 可单元测试。
  • 每个包有 src/index.ts 作为唯一公开入口;跨包只通过入口引用。
  • 命名:表名 snake_case 与 REQ §12 实体名一致;TS 类型 PascalCase;能力 ID 用 域.动作(如 download.submit)。
  • 提交:conventional commits(feat(server): ...),每个子任务结束前 deno task ci 必须绿再提交。
  • 凭证一律 secret reference(secret_ref 列 + 加密存储),日志/错误/模型上下文脱敏;含 passkey 的 URL 不得进入日志。

3. v0.1 范围(= REQ M0 + M1 纵切,可在无真实 PT 账号下用 mock 全链路验证)

3.1 必做

  1. 底座:monorepo、配置(env + settings 表)、迁移、API Key 鉴权(scope:read/organize.read/organize.execute/admin)、审计日志 audit_event、SSE 事件流(带序号可补读)、全局"自动化总开关"。
  2. 数据模型(REQ §12 子集,表名照抄):media_entity、content_unit、external_identity、identity_revision、title_alias、media_asset、asset_location、path_binding、library_root、site_account、feed_source、observation、source_release、subscription、policy_revision、acquisition_slot、preference_tag、preference_suppression、acquisition_plan、download_task、asset_operation、decision、approval、automation_grant、agent_run、artifact、audit_event、outbox_event、reconcile_run、server_mapping、api_key、organization_record、organization_file_result、downloader_instance、media_server_instance、settings。
  3. 来源:多 RSS 抓取(ETag/Last-Modified、重叠窗口、GUID+摘要去重、退避/熔断、passkey 脱敏)、观众(NexusPHP 列表/详情/下载,参考 MovieClaw audiences.yaml 结构)与馒头(API Key)两类站点适配器、站点快照缓存 + 实时补查 + 站点启停 + 站点级限流。
  4. 身份与元数据:发布标题解析(对照 MP MetaInfo 行为:标题/年份/季集/分辨率/来源/编码/发布组/版本)、TMDB 查询与缓存、本地实体优先 + external_identity 映射(provider+type+id 唯一)、title_alias 模糊召回(pg_trgm)、临时 content_unit、待识别池。
  5. 规则与选片:subscription(单次/持续追踪)、acquisition_slot(硬条件/软偏好/升级阈值/完成条件,状态机 empty→reserved→downloading→verifying→satisfied/upgrade_pending/attention)、确定性 evaluateAcquisition(不含 Agent 主观选片,只留接口)、每日预算与并发限制、优先级(即时>追更>新作品>升级)。
  6. 下载:qB WebUI 适配(多实例、管理标签、提交/接管/查询/暂停恢复)、缓存卷硬阈值与恢复水位(暂停范围仅限纳管任务)、download_task 状态机、无进展只记录不换源。
  7. 入库:verifyAndImport → Copy/Move(临时文件+校验+提交;跨卷 Copy→核验→删源;EXDEV 不静默降级)、路径绑定固定(已绑定目录不因译名变化改变)、organization_record + 文件级结果、公开整理记录 API(API Key、游标增量)。
  8. 持久任务:ingestFeed、resolveObservation、evaluateAcquisition、submitDownload、verifyAndImport、refreshMetadata、reconcileLibrary(资产存在性)、cleanupDownloadCache、resolveDecision;outbox;重启恢复;幂等键;取消传播。
  9. Agent:Pi AgentSession 封装;能力注册中心(ID/版本/schema/权限/风险/幂等/预览/处理器),首批能力:catalog.lookup、release.search、release.inspect、identity.resolve、download.plan、download.submit、organize.plan、organize.execute、task.inspect、task.retry、task.cancel、policy.preview、policy.apply、inventory.query;授权校验在服务端;agent_run 持久化 + SSE 增量;后台事件触发有界 Agent 任务(识别歧义、下载失败诊断);设置页可配上游/模型/思考档位/上下文预算/压缩/子代理开关。
  10. 控制台页面(REQ §13):首页六区块(自动化概览/当前工作/需要我处理/缓存与保留/来源健康/最近产出)、媒体库(列表+详情:路径/身份映射/元数据来源/Slot/候选拒绝理由/下载历史)、订阅与收录规则、偏好标签(基础 CRUD+抑制记录)、PT 站点工作台(整理视图:列表/搜索/详情/库存叠加/统一下载入口;原站视图首版只留占位与说明)、来源/Feed/快照、下载与任务(含业务时间线)、整理记录、待处理中心、身份与元数据、系统设置(实例/路径映射/API Key/Pi 上游与预算/自动化开关)、Agent 会话页 + 侧栏、工作流引擎面板(用户 2026-09-27 明确:把 OpenWorkflow 自带 Dashboard 的功能用本项目组件复刻并集成进控制台,走管理员登录;runs 列表/筛选、run 详情(步骤/attempts/输入输出/错误/时间线)、workers 与队列统计、cancel/retry 操作;数据经服务端 API 直接查 openworkflow schema;参照 docs/design/openworkflow-dashboard-reference.md;注意:官方面板包 @openworkflow/dashboard 是 Proprietary,不能复制源码,只参考信息架构并直查同一 schema 用本项目组件重写;0.10.1 无 rerun API,重跑通过我们自己的 enqueue 实现)。
  11. 可选 Emby 兼容查询:多实例,查有无/季集/版本,未知≠缺失。
  12. 运维:scripts/backup.sh(pg_dump + 映射导出)、恢复后只读对账模式开关、docker 打包:除 PostgreSQL 外全部塞进一个容器(单镜像内跑 API + worker + 托管 web 静态产物,单端口对外;compose 只有 app + pg 两个服务)、runbook。(用户 2026-09-27 明确)
  13. 管理员登录门禁(用户 2026-09-27 明确):单管理员账号密码登录(首次启动初始化/设置向导),会话 cookie(HttpOnly、SameSite)+ 登录页 + 未登录跳转;密码哈希(argon2/scrypt)、登录限速与失败锁定、会话吊销、可选 TOTP/Passkey 二次验证;控制台走会话鉴权,外部程序走 API Key。实践参考 /opt/uhd_doc 项目(见 docs/design/auth-reference.md 调研结论)。
  14. 测试:domain 单元测试;adapters 对 mock 服务的集成测试;端到端:mock RSS → 观察 → 识别 → 计划 → mock qB 下载完成 → Copy 入库 → 整理记录 API 可读;Agent e2e:fake 模型按脚本调用能力完成"把 X 电影 1080p 收进来"闭环;崩溃恢复注入(worker 中断后续跑)。

3.2 v0.1 明确不做(留接口/占位)

国产综艺分段建模与正片覆盖(M2)、双版本 require_distinct_asset 组合校验(M2,但 Slot 多目标数据结构先建好)、浏览器/camofox 接入与原站视图(M2,BrowserProvider 接口定义先落)、HHClub/CHD 适配(M2)、旧库分范围接管预览(M2)、Agent 主观选片与规则学习回放(M2)、媒体级主动整理 UI(M2,organize.plan 能力可用)、多用户。

4. 里程碑与派工波次

  • W0 底座(并行):A 脚手架与设计系统迁入;B OpenWorkflow+Pi 兼容性 spike(结论进 ADR-002);C MoviePilot 迁移对照账本(识别/刮削 + 转移入库)。
  • W1 领域与适配(并行):domain(解析/身份/Slot/路径/整理计划)、adapters(qB/RSS/站点/TMDB/Emby)+ testkit mocks、db schema 全量迁移 + contracts 全量 schema、tasks 引擎接入。
  • W2 服务编排:server API 全量路由 + 任务处理器串起纵切 + Agent 能力注册与 Pi 封装。
  • W3 控制台(按页面分组并行)+ e2e。
  • W4 集成验收与修复:跑 §3.1 第 13 条全部;补 runbook;打 tag v0.1.0。

每波结束的验收由独立审查子代理执行:deno task ci 绿 + 对照本文件逐条勾选 + 抽查 REQ §2.1 五原则未被破坏。

5. W2 服务编排拆分(2026-09-27 定稿)

服务端模块布局:apps/server/src/modules/<area>/{routes.ts,service.ts,handlers/*.ts},每个模块导出 registerRoutes(app) 与任务处理器注册函数;http/app.ts 与 worker/index.ts 各维护一个模块列表,每个子任务只追加自己的一行。跨模块只通过 DB 表 + outbox_event(事件类型在 contracts/events.ts)+ contracts 类型耦合,不互相 import service。

子任务 范围 关键交付
W2-A 认证/设置/实例/引擎面板 管理员登录门禁(照 docs/design/auth-reference.md:argon2id、session 表、setup token、限速落表、改密吊销)、settings、api_key 管理、secret 加密服务、downloader/media_server 实例与 library_root/path_mapping CRUD、审计查询、SSE 总线改 PG 通知(多进程)、引擎面板只读 API(openworkflow schema)、自动化总开关 登录/会话中间件供其他模块用
W2-B 来源/身份/元数据 site、site_account、feed_source CRUD 与启停;站点快照缓存与实时补查;ingestFeed/resolveObservation/refreshMetadata 处理器;observation/source_release 写入与多层去重;identity 解析(TMDB + title_alias 召回 + domain.resolveIdentity)→ media_entity/content_unit/external_identity;待识别池与 decision API;人工纠错映射 API;站点工作台数据 API(列表/搜索/详情 + 库存叠加) 发出 release.resolved、decision.created 事件
W2-C 规则/下载/入库/整理记录 subscription、acquisition_slot、policy_revision、preference_tag(+suppression)CRUD;evaluateAcquisition/submitDownload/verifyAndImport/cleanupDownloadCache/reconcileLibrary 处理器;download_task 与 qB 同步轮询、标签接管、缓存卷硬阈值与恢复水位;Copy/Move 执行(adapters/fs + domain/organize)、path_binding 固定;organization_record 写入与公开增量 API(API Key);Emby 库存查询接入;媒体库列表/详情 API;首页六区块聚合 API 消费 release.resolved;发出 download./organization. 事件
W2-D Agent 装配 + e2e 14 个能力的 handler 接到 A/B/C 的服务;authorize(grant/approval)与 audit 注入;Agent 会话 API + SSE 增量;后台触发(识别歧义、下载失败诊断→有界 agent 任务);resolveDecision 处理器;fake 模型 e2e:"把 X 电影 1080p 收进来"闭环;RSS→入库 e2e;崩溃恢复注入 e2e W2-A/B/C 完成后开始

6. v0.1 追加范围(用户 2026-09-27 晚间确认)

  • 订阅业务逻辑对标 MP 并增强:补 docs/porting/moviepilot-subscribe.md 迁移账本 + docs/plan/05-subscription-gap.md 差距清单,按清单补做(缺集计算、洗版、状态机、规则组、自动停止等),REQ §6 的增强点须落地。
  • 文件管理页 /console/files:对标 MP 文件管理全部功能(目录浏览、重命名/移动/删除/新建目录、识别、整理、刮削、探测)并更好用(批量整理向导、dryRun 预览、拖拽、虚拟滚动),规格 docs/plan/06-file-manager-spec.md;安全:路径守卫、回收站、授权、审计。
  • Agent 会话页体验参考 https://www.agentui.pro/(docs/design/agent-ui-reference.md)。
  • 转移语义补齐(来自 docs/porting/moviepilot-rust-transfer.md):挂死隔离、partial 清理、EEXIST 误报修复、onExisting 接线、TIMEOUT 错误码;空目录清理/hardlink/蓝光原盘留 W5。
  • MP Rust 加速函数的产品逻辑差分核对(docs/porting/mp-rust-logic-parity.md)后按漏迁/bug 清单补迁。

7. v0.2 方向(用户 2026-09-28)

  • Pi 上游全覆盖:pi-ai 全部 provider + 订阅式 OAuth 登录(Codex/ChatGPT、OpenCode Go、Claude、Copilot、Google 等),多上游共存与默认上游,服务端 token 刷新;方案 docs/design/pi-providers.md。
  • 控制台信息架构重构:参考 MoviePilot 前端("发现→订阅→下载→整理→设定"流程;设定按接入对象分区),方案 docs/design/console-ia.md,用户审阅后实施(nav/路由重定向、设置页重构 + settings 迁移、页面合并)。
  • Pi 子代理(用户 2026-09-28):SDK 无子代理,自研 agent.spawn 能力:父 run 派生有界子 run(同 runAgent 任务、独立会话文件),继承父授权上限、共享总预算与取消状态、并发上限(settings.pi.subagents{enabled,maxConcurrent,maxDepth}),子结果回填父会话为工具输出;UI 在会话页显示子会话树。
  • 定时任务看板(用户 2026-09-28,参考 MP「服务」页):scheduled_job 表 + 注册表统一管理所有周期任务(feed 轮询、站点快照、订阅搜索、qB 同步、对账、缓存清理、回收站清理、Pi token 刷新、备份、待识别复查)与「Agent 巡检」(目标模板、能力白名单、预算、触发条件);每项:间隔/cron、开关、立即执行、上次/下次运行、最近结果与耗时、失败原因、历史;各模块的 start() 计时器改为向注册表登记;页面做成看板(卡片分组:采集/下载/整理/维护/Agent 巡检)。

8. v0.2.1 方向(用户 2026-09-28 上午)

  • 站点中心一处搞定:资源 → 站点页 = 添加站点 + 凭证管理(账密 / Cookie / API Key,馒头 API Key)+ 站点卡片/列表(上次登录时间、上传/下载、分享率、用户等级、VIP、账号状态,数据来自 sites/user-parsers 的 refreshSiteUserData)+ 手动"检测健康"与"用凭证刷新登录状态";账密登录走 NexusPHP takelogin(验证码/二次验证失败 → 待处理并提示改用 Cookie);设置里只留全局默认(限流、快照周期)。参考 MP 站点管理页与 MovieClaw 站点卡片。
  • 概览/仪表盘对照 MP:保留 REQ 六区块,补 MP 仪表盘有价值的区块(媒体库统计、存储用量、下载器实时状态、最近入库、定时任务状态),砍重复。
  • 订阅重做(用户 2026-09-28):参考 MP 订阅页再增强——总览按状态(追更中/待搜索/已完成/暂停/待定)与上次更新时间分组;每条订阅显示库内已有 vs 订阅要求的对比(季/集覆盖、版本目标);多版本目标逐个显示缺失并可配置"自动补全其他版本";日历/即将播出可选。规格 docs/design/subscriptions.md。
  • 收录策略 + 偏好标签二合一:参考 MP 规则组(过滤规则字符串 + 优先级 + 订阅默认规则),做成一个"规则"页:硬条件/软偏好/优先级阶梯/排除,订阅与 Agent 引用;偏好标签作为规则的展示形态保留抑制记录语义。
  • 整理命名模板语法:对标 MP 重命名格式(Jinja 风格变量:title/year/season/episode/资源信息…),实现模板引擎(安全子集)+ 设置页表单(变量清单、示例、实时预览)+ 库根/作品级覆盖;整理与文件管理按模板生成路径。规格并入 docs/design/subscriptions.md 或单独 naming-template.md。
  • 导航定稿(IA-3,用户 2026-09-28 两次意见):概览(首页、Agent 会话)/ 资源(站点、RSS 订阅)/ 订阅(订阅、规则)/ 整理(下载面板、整理记录[已整理/队列中/成功/失败/重名拦截,参考 MP 历史记录]、文件管理、媒体概览[原媒体库:本地账本=实体/外部映射/字段锁/资产与路径绑定/版本目标状态;筛选含待识别;详情含身份映射/历史])/ 系统(设置、定时任务、引擎面板、审计)。待处理不作分类:顶栏收件箱(角标)+ 首页区块 + 页面内联;"身份与元数据"取消;"业务任务"并入引擎面板;下载计划/缓存水位并入下载面板;整理记录公开接口不变。一级导航 19 → 13 项。
  • 文件管理再做一轮:对照 MP 文件管理逐功能比,按我们的逻辑重整前端(规格 06 基础上补 docs/design/file-manager-v2.md)。
  • 全局搜索入口(用户 2026-09-28,对标 MP 顶栏搜索 + 资源搜索页):顶栏搜索框 + Ctrl/⌘+K 命令面板;GET /search?q=&scope=聚合:本地作品(title_alias trgm)、TMDB 候选(可订阅/查看)、跨站资源(已启用站点搜索,限流 + 15s 超时 + 并发合并 + 短缓存,库存叠加,可下载/委托 Agent)、页面与操作跳转;结果页 /console/search?q= 支持筛选(站点/分辨率/来源/大小/免费/HR)与排序,资源行操作同站点工作台。
  • 系统组收敛(用户 2026-09-28 讨论):设置 / 定时任务 / 运行日志(Tab:任务运行=引擎 runs 补业务字段与触发来源、审计、进程与健康=api/io worker/agent worker 心跳、事件循环延迟、SSE 连接数、DB、磁盘与挂载根状态)。定时任务卡片历史跳运行日志对应 run。最终一级导航 12 项。
  • IA-3 最终定稿(用户 2026-09-28 认可):概览(首页、任务、Agent 会话)/ 资源(站点、RSS 订阅)/ 订阅(订阅、规则)/ 整理(下载面板、整理记录、文件管理、媒体概览)/ 系统(设置、审计、运行状态)。统一"任务"概念:每次运行不分来源(定时/事件/手动/Agent)都是一条任务,带业务含义与时间线,引擎 step/attempt 只是详情折叠区;引擎面板与业务任务页取消;任务页 Tab"计划"承载定时任务配置(看板迁入),运行历史即任务流;首页增加"计划"带(下一次运行/启用数/快速开关)与正在进行/最近完成失败/待处理区块;待处理为顶栏收件箱。系统:设置、审计(任务详情链到相关审计)、运行状态(进程与健康)。共 12 项。