Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
7360939
docs: add local file organization architecture v2 integrated with exi…
claude Jul 21, 2026
46a517e
docs(organizer): decompose domain plugins into component palette + da…
claude Jul 21, 2026
e939e40
docs(organizer): add built-in pipeline composition appendix (12.1)
claude Jul 21, 2026
ac97c66
docs(organizer): user-defined signal rules, two-phase matching, resol…
claude Jul 21, 2026
d9f758a
docs(organizer): split architecture into linked per-module design docs
claude Jul 21, 2026
8619fba
docs(organizer): redesign resolution as candidate generators + fixed …
claude Jul 21, 2026
ed40417
docs(organizer): generalize candidate fields to typed features, add f…
claude Jul 21, 2026
b5eeab0
docs(organizer): consolidation closure semantics, identity assertions…
claude Jul 21, 2026
44af560
docs: park organizer design, add file-cleaning workflow design as cur…
claude Jul 21, 2026
e20edfb
docs(file-cleaning): add multi-level linked workflow example, adopt e…
claude Jul 22, 2026
2670ad4
docs(file-cleaning): id-based custom text types, per-node workflow I/…
claude Jul 22, 2026
1f9a459
docs(file-cleaning): rename text transforms to fs namespace, add capa…
claude Jul 22, 2026
32ef5d9
docs(file-cleaning): make text nodes truly generic via ITextWorkpiece…
claude Jul 22, 2026
5f9a3da
docs(file-cleaning): specify facet-as-predicate rule and mandatory pa…
claude Jul 22, 2026
5d932b0
docs(workflow): add module-wide capability map and rename trigger to …
claude Jul 22, 2026
8ae2147
docs(workflow): convert active design docs to HTML, apply E2/E3/E4 re…
claude Jul 22, 2026
8265b7b
docs(text): add SpecialText extension architecture design
claude Jul 22, 2026
7f756a4
docs(text): unify builtin and custom text types into a single TextTyp…
claude Jul 22, 2026
9fd0d1e
docs(text): correct SpecialText design against a full code audit
claude Aug 26, 2026
c6862c8
feat(text): add TextType and TextEntry schema
claude Aug 26, 2026
edbf183
refactor(text): replace SpecialText service with vocabulary + ops split
claude Aug 26, 2026
1b60d5f
feat(text): unified text management UI and SDK
claude Aug 26, 2026
c779c62
fix(text): make builtin types an invariant and retire the legacy surface
claude Aug 26, 2026
16555f5
fix(text): disable the pretreatment run button on empty input
claude Aug 26, 2026
dee2ee1
docs(workflow): record the SpecialText extension as done [skip ci]
claude Aug 26, 2026
62e3711
refactor(workflow): give payload serialization one home
claude Aug 27, 2026
39f97bb
feat(workflow): run a definition manually with a supplied payload
claude Aug 26, 2026
44da07e
docs(workflow): fold the code review into the capability map [skip ci]
claude Aug 26, 2026
3d5c6c4
docs(workflow): open the capability map with a concept map [skip ci]
claude Sep 1, 2026
840f0e3
docs(workflow): record the generality audit in the capability map [sk…
claude Sep 1, 2026
de87a89
docs(workflow): record the five owner decisions [skip ci]
claude Sep 1, 2026
7164c6a
feat(workflow): file cleaning batch 1 — scan, rename ops, preview plan
claude Sep 1, 2026
a8df95a
chore: link file cleaning batch 1 to its issue [skip ci]
claude Sep 1, 2026
7a0b346
feat(workflow): file cleaning batch 2 — apply/undo on disk, engine ha…
claude Sep 1, 2026
018a5fc
feat(workflow): file cleaning batch 3 — text family (E3) + type-infer…
claude Sep 1, 2026
ab1485a
feat(workflow): file cleaning batch 4 — variables (E4) + chain expans…
claude Sep 1, 2026
4bf37c3
feat(workflow): file cleaning batch 5 — automation (E6): scheduled sc…
claude Sep 1, 2026
6460a9d
chore: link file cleaning batches 2-5 to their issues [skip ci]
claude Sep 1, 2026
8043a17
feat(help): workflow guide in the help center
claude Sep 1, 2026
1f0118f
docs(workflow): editor redesign proposal with interactive prototype […
claude Sep 1, 2026
84d598c
feat(workflow): full-page canvas editor with magnetic node drag
claude Sep 1, 2026
b30a922
chore: link help-center guide and canvas editor to their issues [skip…
claude Sep 1, 2026
fddb084
fix(workflow): drag ghosts stayed frozen on the canvas after drop
claude Sep 1, 2026
4e97221
feat(workflow): canvas pan, zoom, and centered fit view
claude Sep 1, 2026
d342e50
feat: whole-block drag for the resource detail layout editor
claude Sep 1, 2026
aba7dc7
fix: frontend CI failures — type-only imports and missing locale key
claude Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 231 additions & 0 deletions docs/file-cleaning-workflow-example.html

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions docs/file-cleaning-workflow.html

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions docs/local-file-organization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# 本地文件自动整理(Organizer)· 设计文档

> 状态:**Pending(挂起)**。设计讨论在身份判定层(04 Consolidate 的等价语义/粒度问题)尚未收敛,决定先落地范围更小、边界清晰的**[文件清洗(File Cleaning Workflow)](../file-cleaning-workflow.html)**——它吸收了本设计 [01 文本处理规则](modules/01-text-processing.md)的方向(SpecialText 用户自定义类型 + FileNameModifier 节点化),并直接构建在现有 Workflow 模块上。恢复讨论时本目录仍是唯一真相源:每个概念只在其归属文档中定义一次,其余文档以链接引用,不做内容复制。

## 目标

把任意混乱的本地目录,按用户可定制的规则整理成结构化媒体库:

```
扫描 → 提取线索 → 匹配身份 → 富集字段 → 按模板计划目标路径 → 干跑确认 → 执行/回滚
(循环处理,人工裁定持久化,每轮待处理集合单调缩小,直至收敛)
```

支持混合类型目录(动画/漫画/音乐/音声混放各归其所),支持按 IP 跨域聚合成合集。

## 设计原则

1. **干跑默认**:计划只读,执行需确认,一切已执行操作可回滚。
2. **资源一致性**:整理不是裸文件操作。`Resource.Path`、PathMark、属性值、播放记录随移动保持;匹配到的元数据落库复用。
3. **组件化,骨架固定、槽内自由**:流水线阶段顺序固定;每个槽位的组件用户可选换。内置能力一律做成"只读种子数据 + 可 fork"。
4. **收敛**:Override(人工裁定持久化)+ 元数据缓存 + 条目状态机,使重跑不重复劳动。
5. **复用优先**:ThirdParty(33 个站点客户端)、Enhancer 转换链、Property/StandardValue 类型系统、BTask、Comparison、Alias、SpecialText 直接使用,见[复用总表](foundations.md#现有资产复用总表)。

## 分层与文档地图

自底向上(构建顺序即阅读顺序):

| 层 | 模块 | 一句话职责 |
|---|---|---|
| 基础定义 | [foundations](foundations.md) | 概念表、组件模型、类型系统、复用总表 |
| 原子能力 | [01 文本处理规则](modules/01-text-processing.md) | 用户定义规则,对"一段文本"清洗 + 类型化提取(来源无关) |
| 原子能力 | [02 条目提取器](modules/02-extractors.md) | 面向文件/目录采集线索:文本规则应用 + 结构化读取 |
| 原子能力 | [03 元数据 Provider](modules/03-providers.md) | 外部站点统一适配:搜候选 / 精确码取 / 按身份富集 |
| 决策能力 | [04 身份判定](modules/04-resolution.md) | 候选生成 → 归拢 → 裁决:线索 → 身份 + 置信档 + 解释 |
| 决策能力 | [05 字段富集](modules/05-enrichment.md) | 多库并行取详情,per-field 合并,带来源追溯 |
| 落盘能力 | [06 布局](modules/06-layout.md) | 路径模板 DSL + 整理规则集:完全自由的目录/命名表达 |
| 落盘能力 | [07 执行](modules/07-execution.md) | 计划 / journal / 回滚 / 资源一致性联动 |
| 顶层编排 | [08 编排](modules/08-orchestration.md) | Pipeline 组合、路由、条目状态机、BTask 宿主、复核 |
| 顶层编排 | [09 合集](modules/09-collections.md) | franchise/IP 解析与跨域聚合布局 |

依赖只允许**上层引用下层**;下层模块不感知上层(01 甚至不知道整理器的存在)。

## 执行计划

按底层 → 顶层构建。**每个阶段完成后都有独立可用、可验证的能力**(详见各模块文档的"完成后获得的能力"节);最终交付仍可垂直组合——例如 01+02+03(仅 DLsite)+04(仅 exact-code 环)+06(单条规则)+07 就构成"音声整理"最小闭环。

| 阶段 | 模块 | 完成后获得的能力(摘要) |
|---|---|---|
| P1 原子能力 | 01, 02, 03 | 独立的文本规则管理与试跑页;对任意条目产出类型化线索;对已适配站点统一查询(可做成调试页直接验证) |
| P2 决策能力 | 04, 05 | 给定线索集返回可解释的身份判定;多库字段合并含来源。纯逻辑层,可全量单测 |
| P3 落盘能力 | 06, 07 | 模板渲染纯函数 + 规则预览;安全执行与完整回滚,资源零丢失 |
| P4 顶层编排 | 08, 09 | 端到端 Pipeline(内置种子 + fork)、断点续跑、复核收敛、IP 合集 |

## 当前进度

> 维护规则:进度**只在本表**更新,模块文档内不写进度。

| 模块 | 概要设计 | 详细设计 | 实现 |
|---|---|---|---|
| foundations | ✅ | 🚧 | ⬜ |
| 01 文本处理规则 | ✅ | 🚧(UI 交互细节待定) | ⬜ |
| 02 条目提取器 | ✅ | ⬜ | ⬜ |
| 03 元数据 Provider | ✅ | ⬜ | ⬜ |
| 04 身份判定 | ✅ | ⬜ | ⬜ |
| 05 字段富集 | ✅ | ⬜ | ⬜ |
| 06 布局 | ✅ | ⬜ | ⬜ |
| 07 执行 | ✅ | ⬜ | ⬜ |
| 08 编排 | ✅ | ⬜ | ⬜ |
| 09 合集 | ✅ | ⬜(依赖最多,最后细化) | ⬜ |
105 changes: 105 additions & 0 deletions docs/local-file-organization/foundations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# 基础定义

> 被所有模块引用的共享概念、组件模型与类型系统。本文件不含任何流程编排——流程见[08 编排](modules/08-orchestration.md)。

## 核心概念

| 概念 | 定义 | 详见 |
|---|---|---|
| Item(条目) | 一次整理的处理单位:一个文件或目录(含压缩包),带稳定指纹(路径+大小+mtime 摘要),用于断点续跑与 Override 定位 | [08](modules/08-orchestration.md) |
| Clue(线索) | 从条目上提取出的**类型化**键值:`title/year/code/episode…` 或域字段,绑定 `StandardValueType` | [02](modules/02-extractors.md) |
| TextRuleSet(文本规则集) | 用户定义的清洗 + 提取规则,作用于"一段文本",来源无关 | [01](modules/01-text-processing.md) |
| Extractor(提取器) | 面向条目产出 Clue 的组件:文本规则应用器或结构化读取器 | [02](modules/02-extractors.md) |
| Provider(数据源) | 一个外部元数据库的统一适配:搜候选 / 精确码取 / 按身份富集 | [03](modules/03-providers.md) |
| Candidate / WorkIdentity | 匹配候选;定案后的作品身份是 **(source, key) 的集合**(同一作品在多库的 id) | [04](modules/04-resolution.md) |
| Band(置信档) | High / Medium / Low / None。分数→档位映射是 Pipeline 配置 | [04](modules/04-resolution.md) |
| FieldBag(字段袋) | 类型安全的域字段容器,每个值带 provenance(来源 Provider) | 本文件[类型系统](#类型系统) |
| Rule / RuleSet(整理规则) | 作用域 + 路径模板 + 冲突策略;有序首中生效 | [06](modules/06-layout.md) |
| Journal(执行账本) | 逐操作 Intent/Done 两段记录;回滚 = 逆序回放 | [07](modules/07-execution.md) |
| Pipeline(流水线) | 一条可运行的整理配置:各槽位组件实例的组合,**数据而非代码** | [08](modules/08-orchestration.md) |
| Override(人工裁定) | 复核时人的决定,按条目指纹持久化、跨轮生效 | [04](modules/04-resolution.md) |
| Franchise(IP/系列) | 跨域的作品归属,规范化为一个资源属性 | [09](modules/09-collections.md) |

### 命名约定:为什么不叫 Signal

早期草稿把线索采集层叫 "Signal"。弃用理由:signal 暗示"信号/触发/流",而这一层实际做的是**从原始材料中提取类型化线索**。现命名:通用文本层 = TextRule,条目层组件 = Extractor,产物 = Clue,对应的条目状态 = `Extracted`。

## 组件模型(所有槽位共享)

Extractor、Provider、Resolver 策略、Detector 都遵循同一套组件机制(注册表/描述符/配置表单三件套借鉴 Workflow 模块的 `WorkflowActivityRegistry` 模式,但**不复用其执行引擎**,理由见 [08](modules/08-orchestration.md#与-workflow-模块的关系)):

```csharp
public interface IOrganizerComponentDescriptor
{
string Kind { get; } // "extractor.pattern" / "provider.dlsite" / "resolver.fuzzy-search"
OrganizerSlot Slot { get; } // Detector / Extractor / Provider / CandidateGenerator
string DisplayName { get; }
Type? ConfigType { get; } // 配置 schema,编辑器据此渲染表单
ComponentApplicability Applicability { get; } // 适用形态:音频/压缩包/任意…(编辑器校验)
FieldDefinition[] Fields { get; } // 该组件产出的域字段 → "字段随组件走"
}
```

- **组件 = 代码,实例 = 数据**:同一组件可在多处以不同配置实例化(configJson)。
- **内置皆种子**:内置组件实例、内置 TextRuleSet、内置 Pipeline 都是只读种子数据;用户 fork(copy-on-write)后自由修改。上游更新时 fork 收到提示,不强制同步。
- **可分享**:种子数据形态的配置(TextRuleSet、Pipeline、规则集)走现有 Sharable 体系分享。
- **DI 注册**:同 Enhancer 的多实现枚举注册模式;不做独立程序集/热插拔。

## 类型系统

**唯一类型骨架是 `StandardValueType`(9 种)**,不发明第二套类型系统。先例:`IEnhancerTargetDescriptor` 已同时携带 `StandardValueType ValueType` + `PropertyType PropertyType`。

```csharp
public sealed record FieldDefinition(
string Key, // "circle";模板中经 "{域标签.Key}" 引用
StandardValueType ValueType, // String / ListString / Decimal / DateTime…
PropertyType SuggestedPropertyType, // 写回资源属性时的建议类型
bool Multilingual = false); // true → 值为多语言文本,模板可 :lang() 选取

public sealed class TypedField<T>(string key, StandardValueType type) { /* 编译期检查的字段句柄 */ }

public sealed class FieldBag // 域字段容器
{
public T? Get<T>(TypedField<T> field);
public void Set<T>(TypedField<T> field, T? value, string providerName); // 写入校验 ValueType;记录 provenance
public string SerializeToJson(); // 持久化进 MetadataJson
}
```

- **通用规范字段**(title/year/code/workType/franchise)是 `MatchedWork` 的强类型属性;FieldBag 只装真正域特定的部分(circle/cv/albumArtist…)。
- **provenance**:每个值记录来源 Provider——复核 UI 展示依据;"换合并策略重算"零网络请求(见 [05](modules/05-enrichment.md))。
- **与资源属性双向转换**:字段映射到属性(缺省按 `SuggestedPropertyType` 自动建属性,Enhancer target options 已是同一模式);写入走 `PropertyValueFactory`,跨类型走 `StandardValueSystem.GetConversionRule` 既有转换规则。
- **字段随组件走**:一条 Pipeline 可用的域字段 = 其组件 `Fields` 声明的并集;模板占位符按此提示与校验(见 [06](modules/06-layout.md))。

## 数据表索引

表定义写在归属模块内,此处仅索引。所有表经 EF 迁移生成(禁手写,见仓库根 `CLAUDE.md`);文件类产物一律入 `IAppService.AppDataDirectory`(见 `.claude/rules/appdata-paths.md`)。

| 表 | 归属 |
|---|---|
| TextRuleSet / TextRule | [01](modules/01-text-processing.md) |
| OrganizeOverride | [04](modules/04-resolution.md) |
| OrganizeRuleSet / OrganizeRule | [06](modules/06-layout.md) |
| OrganizeJournalEntry | [07](modules/07-execution.md) |
| OrganizePipeline / OrganizeJob / OrganizeItem | [08](modules/08-orchestration.md) |

## 现有资产复用总表

以下路径与类型均已在代码库核实:

| 现有资产 | 位置 | 被谁复用 |
|---|---|---|
| 33 个第三方客户端 + 统一 HTTP 基建(`AddBakabaseHttpClient`、站点专属 Handler:限流/Cookie/代理) | `src/modules/Bakabase.Modules.ThirdParty/ThirdParties/` | [03](modules/03-providers.md) |
| Enhancer 转换链(context→StandardValue→属性,含选项自动建属性);`AbstractEnhancer<,,>` | `src/modules/Bakabase.Modules.Enhancer/` | [05](modules/05-enrichment.md)、[07](modules/07-execution.md) |
| `ResourceSourceLink`(Source + SourceKey + MetadataJson + 封面缓存),一资源多行 | `src/abstractions/.../Models/Domain/ResourceSourceLink.cs` | [04](modules/04-resolution.md)、[07](modules/07-execution.md) |
| `ISpecialTextService`:固定枚举清洗词汇表(Useless/Wrapper/Standardization/Volume/Trim/DateTime/Language) | legacy | [01](modules/01-text-processing.md)、[04](modules/04-resolution.md) |
| Alias 模块(别名解析) | `src/modules/Bakabase.Modules.Alias/` | [04](modules/04-resolution.md)、[09](modules/09-collections.md) |
| Comparison 模块(加权规则去重,11 种策略含文本相似度) | `src/modules/Bakabase.Modules.Comparison/` | [04](modules/04-resolution.md)、[07](modules/07-execution.md) |
| `ResourceSearchFilterGroup` + `PathFilter`(过滤模型与 UI) | `src/abstractions/.../Models/Domain/` | [06](modules/06-layout.md)、[08](modules/08-orchestration.md) |
| 显示名模板引擎(`{属性名}` 占位 + 包装符空值丢弃,`ResourceUtils.SplitDisplayNameTemplateIntoSegments`,有测试) | legacy `ResourceService` | [06](modules/06-layout.md) |
| BTask(一次性 fluent builder、进度/暂停/取消、冲突键、SignalR) | `src/abstractions/.../Components/Tasks/` | [08](modules/08-orchestration.md) |
| Workflow 模块(注册表/描述符/配置表单模式;触发器与活动) | `src/modules/Bakabase.Modules.Workflow/` | 本文件组件模型、[08](modules/08-orchestration.md) |
| `CompressedFileService`(压缩包处理) | legacy | [02](modules/02-extractors.md)、[07](modules/07-execution.md) |
| FileMover / FileNameModifier / file-processor 页 | legacy + `src/web/src/pages/` | [08](modules/08-orchestration.md)(触发形态)、[07](modules/07-execution.md) |
| Sharable 体系(配置分享) | `src/abstractions/.../Models/Domain/Sharable/` | 组件模型(种子分享) |
| AI 模块(多 Provider、缓存、Enhancer 桥接) | `src/modules/Bakabase.Modules.AI/` | [04](modules/04-resolution.md)(后期辅助消歧) |
59 changes: 59 additions & 0 deletions docs/local-file-organization/modules/01-text-processing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 01 · 文本处理规则(TextRule)

> 层级:原子能力 | 依赖:无([SpecialText 词汇表](../foundations.md#现有资产复用总表)为可选引用) | 被依赖:[02 条目提取器](02-extractors.md)
>
> 职责:让用户创建规则,对**一段文本**执行清洗与类型化提取。目标抽象为 text,**来源无关**——可能是文件名、目录名、相对路径、伴随文本,或未来任何调用方传入的字符串。

## 与 SpecialText 的关系

现状:SpecialText 是**固定枚举的清洗词汇表**(`Useless/Wrapper/Standardization/Volume/Trim/DateTime/Language` 七种,值为字符串对,语义硬编码在各消费点)。它是"词汇",不是"提取规则"。

决策:**不动 SpecialText 的表与枚举**(legacy、消费点多)。TextRule 是它的概念泛化——SpecialText 的每个枚举值是硬编码的 token 类型,TextRule 的具名捕获组就是**用户定义的动态 token 类型**。TextRule 的清洗步骤可引用 SpecialText 词汇(包装符剥离、无用词、标准化替换)。

## 模型

```
TextRuleSet 名称 + 有序规则列表 + (可选)残余清洗开关(引用 SpecialText 词汇)
TextRule Pattern:带具名捕获组的正则(强制 MatchTimeout 防 ReDoS)
Bindings:捕获组 → 绑定目标
Cleanup:命中后是否从待处理文本中剥离
Binding 目标二选一:
a) 规范线索槽:title / year / code / episode / volume / …
b) 域字段:FieldDefinition(Key + StandardValueType,附解析器如日期格式)
```

处理语义:规则依序执行;`Cleanup=true` 的命中从文本中剥离;全部规则跑完后,剩余文本经 SpecialText 清洗成为"残余标题"候选。

输出:

```csharp
public sealed record TextExtractionResult(
IReadOnlyList<Clue> Clues, // 类型化线索(绑定校验过 StandardValueType)
string CleanedText); // 残余文本
```

类型安全:Binding 声明了 `StandardValueType`,捕获值在产出时解析校验(如 `year` 必须能进 Decimal、日期按声明格式解析),失败的捕获丢弃并在试跑 UI 中标红——见 [foundations · 类型系统](../foundations.md#类型系统)。

## 数据表

```
TextRuleSet Name, BuiltinKind?(内置种子来源), Rules(JSON), Enabled, CreatedAt/UpdatedAt
```

内置种子(只读,可 fork,语义见 [foundations · 组件模型](../foundations.md#组件模型所有槽位共享)):`rj-code`(`[BVR]J\d{6,10}` → code)、`imdb-code`(`tt\d+` → code)、`sxxeyy`(→ season/episode)、`av-code`(番号 → code)、`volume`(卷号)等。可经 Sharable 体系分享。

## UI

独立管理页(不依赖整理器的任何其他部分):规则集列表 + 规则编辑器 + **试跑区**——粘贴若干样例文本,实时显示每条规则的命中高亮、提取出的类型化值、残余文本。

## 完成后获得的能力

- 用户可为私有编号体系建规则:新建规则集「我的编号」,Pattern `(?<code>GB\d{4})` 绑定到 `code:String`;试跑 `[GB0421] 某标题 (2023)` → `code=GB0421, year=2023, cleaned="某标题"`。
- 内置 `rj-code` 等规则集开箱可用、可 fork 改造(如放宽位数)。
- 该能力**独立成立**:即使整理器一行未写,它已是一个可用的"文本规则工具",并可被未来其他功能(文件名批量清洗、对比归一预处理)复用。
- 全量单测:规则引擎是纯函数(文本进、结果出)。

## 开放问题

- 多规则集组合时的优先级语义(02 中由提取器实例的顺序决定,是否够用)。
- 正则之外是否需要第二种规则形式(分隔符切段/模板反推)——倾向于先不做,用数据说话。
Loading
Loading