From f7495650aa7067dfbb587a1af76c90b12bc5a40a Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 11 Jun 2026 20:58:44 +0800
Subject: [PATCH] Add 7.9 app ordering planning docs

---
 docs/7.90/05-技术设计方案.md  |  262 +++++++++++++++++++++++++++++
 docs/7.90/04-QA测试用例集.md |  123 +++++++++++++
 docs/7.90/03-产品PRD.md   |  125 +++++++++++++
 docs/7.90/README.md     |    3 
 4 files changed, 513 insertions(+), 0 deletions(-)

diff --git "a/docs/7.90/03-\344\272\247\345\223\201PRD.md" "b/docs/7.90/03-\344\272\247\345\223\201PRD.md"
new file mode 100644
index 0000000..8928cb7
--- /dev/null
+++ "b/docs/7.90/03-\344\272\247\345\223\201PRD.md"
@@ -0,0 +1,125 @@
+# 7.9.0 产品 PRD:容器内 App 手动排序
+
+## 1. 背景
+
+TagLauncher 当前支持按标签/容器展示 App,也支持拖动 App 改变标签归属。但在同一个容器内,App 的显示顺序主要来自扫描后的默认名称排序,用户无法把高频 App 固定到自己习惯的位置。
+
+对重度用户来说,容器不仅是分类,也是工作流入口。用户希望像整理桌面图标一样,在每个容器中把 App 摆成自己的顺序,并且这个顺序能随“分类与布局”一起保存、导入、恢复。
+
+## 2. 目标
+
+- 用户可以在同一个容器/分组内拖动 App,改变该容器内显示顺序。
+- 自定义顺序在刷新、重启、语言切换、导入导出、恢复上一方案、SmartStart 回滚后保持一致。
+- 不破坏现有跨容器拖动改标签、Option 复制、拖到空白移除标签、Apple 内置组保护等既有行为。
+- 将该需求作为 `7.9.0` 大版本需求管理。
+
+## 3. 用户价值
+
+- 高频 App 可以放到容器最前面,减少寻找成本。
+- 每个标签/容器可以形成独立工作流顺序。
+- 多标签 App 在不同容器里可以有不同位置,符合不同使用语境。
+- 导出“分类与布局”时真正包含布局顺序,便于迁移和恢复。
+
+## 4. 适用用户
+
+- 安装 App 数量较多、依赖 TagLauncher 做日常启动入口的用户。
+- 已经维护多个标签/容器,并希望在容器内进一步精细整理的用户。
+- 需要在多台 Mac 或重装后恢复分类与布局的用户。
+
+## 5. 范围
+
+### 5.1 版本 7.9.0 必做
+
+- 同一容器内拖动 App 改变顺序。
+- 每个容器独立保存顺序。
+- 多标签 App 在不同容器中的顺序互不影响。
+- 新 App 或未记录 App 在自定义顺序之后按默认规则显示。
+- 删除/卸载 App 后不显示空位、不崩溃。
+- 顺序纳入分类与布局数据,可导出、导入、恢复。
+- 旧用户数据无顺序字段时保持原有默认排序。
+
+### 5.2 版本 7.9.0 不做
+
+- 不做跨容器插入位置排序。
+- 不改变跨容器拖动的标签归属语义。
+- 不改变 Quick Search 结果排序。
+- 不提供“按名称重新排序”“重置单个容器顺序”等高级管理入口。
+- 不做跨机器 bundle id/name fallback 的完整稳定匹配;第一版以 path 为 App 顺序身份。
+
+## 6. 核心交互
+
+### 6.1 同容器排序
+
+用户在 App Grid 普通展示态中,长按并拖动某个 App 到同一容器中的另一个位置。
+
+期望:
+
+- 拖动过程中显示清晰的插入位置提示。
+- 松手后该 App 移动到目标位置。
+- 不改变该 App 的标签归属。
+- 不触发 App 启动。
+
+### 6.2 跨容器拖动
+
+用户把 App 拖到其他容器/标签。
+
+期望:
+
+- 沿用现有移动/复制标签逻辑。
+- 按住 Option 时继续执行复制标签语义。
+- 不把跨容器拖动解释为排序。
+
+### 6.3 拖到空白区域
+
+用户把 App 拖到容器外空白区域。
+
+期望:
+
+- 继续沿用现有移除来源标签或归为未分类确认逻辑。
+- 不因为新增排序功能改变提醒、确认或“不再提醒”逻辑。
+
+### 6.4 特殊容器
+
+- “未分类”容器:第一版允许读取排序;是否开放拖动排序按实现风险在开发阶段确认。
+- “Mac 自带 / Apple 内置”容器:保持现有保护逻辑,不允许通过拖动改变系统标签归属;排序是否开放需单独评估,默认不作为第一优先级。
+
+## 7. 数据行为
+
+- 自定义顺序属于“分类与布局方案”。
+- 导出分类与布局时必须包含顺序。
+- 导入分类与布局时必须恢复顺序。
+- 恢复上一方案时必须恢复顺序。
+- SmartStart 应用新方案前的备份必须包含顺序。
+- “重置为未分类”应清理旧容器顺序,避免旧布局在未来意外复活。
+
+## 8. 兼容性要求
+
+- macOS 14 起可用。
+- 旧 `tags.json` 无新增字段时可正常读取。
+- 旧版本 App 读取新 JSON 时不应破坏已知字段;新版本 App 重新读取后仍应尽量保留顺序。
+- 语言切换不影响顺序,因为顺序 key 不能依赖本地化显示名。
+
+## 9. 验收标准
+
+- 用户可在同容器内完成拖动排序。
+- 排序结果立即显示。
+- 关闭并重新打开 App Grid 后顺序保持。
+- 重启 App 后顺序保持。
+- 切换语言后顺序保持。
+- 导出再导入后顺序保持。
+- 恢复上一方案后顺序恢复。
+- 跨容器拖动、Option 复制、拖到空白、Apple 内置保护保持现有行为。
+- 旧数据用户升级后默认顺序不变。
+
+## 10. 发布要求
+
+- 版本号从 `7.9.0` 开始。
+- `CHANGELOG.md` 必须记录数据模型、交互范围和兼容性说明。
+- 发布前必须有 QA 报告,覆盖数据层、UI 手工拖拽、macOS 14、导入导出、恢复、SmartStart 回归。
+
+## 11. 未决问题
+
+- “未分类”容器是否开放拖动排序。
+- “Mac 自带 / Apple 内置”容器是否开放仅显示顺序排序。
+- 是否需要在后续版本提供“重置当前容器顺序”入口。
+- 是否需要在后续版本支持跨机器导入时基于 bundle id/name 匹配顺序。
diff --git "a/docs/7.90/04-QA\346\265\213\350\257\225\347\224\250\344\276\213\351\233\206.md" "b/docs/7.90/04-QA\346\265\213\350\257\225\347\224\250\344\276\213\351\233\206.md"
new file mode 100644
index 0000000..a1f92eb
--- /dev/null
+++ "b/docs/7.90/04-QA\346\265\213\350\257\225\347\224\250\344\276\213\351\233\206.md"
@@ -0,0 +1,123 @@
+# 7.9.0 QA 测试用例集:容器内 App 手动排序
+
+## 1. 测试目标
+
+验证用户可以在同一容器内拖动 App 改变显示顺序,并确保顺序在刷新、重启、语言切换、导入导出、恢复、SmartStart 等路径中保持一致,同时不破坏现有跨容器拖动改标签行为。
+
+## 2. 测试范围
+
+- 数据模型兼容性。
+- 同容器拖动排序。
+- 旧拖拽行为回归。
+- 多显示模式和标签位置。
+- 导入导出、恢复、重置、SmartStart。
+- macOS 14 兼容性。
+
+## 3. 测试环境
+
+- macOS 14 Apple Silicon 真机。
+- 当前开发机最新 macOS。
+- 干净用户数据一份。
+- 旧版 `tags.json` fixture 一份。
+- 含多标签 App、未分类 App、Apple 内置 App、已卸载 path 的测试数据一份。
+
+## 4. 自动化用例
+
+| ID | 优先级 | 类型 | 用例 | 期望结果 |
+| --- | --- | --- | --- | --- |
+| DATA-001 | P0 | 自动 | 旧 `tags.json` 无 `containerAppOrder` 字段时解码 | 加载成功,默认顺序与旧版本一致 |
+| DATA-002 | P0 | 自动 | 新 `tags.json` 含 `containerAppOrder` 字段时解码 | 加载成功,顺序字段保留 |
+| DATA-003 | P0 | 自动 | 导出后再导入含顺序的分类与布局 | 导入后每个容器顺序一致 |
+| DATA-004 | P0 | 自动 | `CategorySchemeFingerprint` 包含顺序字段 | 只改变顺序也能触发上一方案快照 |
+| DATA-005 | P0 | 自动 | 恢复上一方案 | 标签、App 归属、容器内顺序都恢复 |
+| DATA-006 | P0 | 自动 | 重置为未分类 | 清空旧普通标签归属,并按既定策略清理旧容器顺序 |
+| DATA-007 | P0 | 自动 | SmartStart replace | 新方案顺序可预测,不复用旧容器顺序 |
+| DATA-008 | P1 | 自动 | tag rename/delete/relocalize | 顺序 key 正确迁移或清理 |
+| DATA-009 | P1 | 自动 | 卸载 App path 出现在顺序字段 | 不显示空位,不崩溃,必要时懒清理 |
+| DATA-010 | P1 | 自动 | 新 App 不在顺序字段内 | 已排序 App 保持,新增 App 追加并按默认名称排序 |
+
+## 5. 手工功能用例
+
+| ID | 优先级 | 用例 | 步骤 | 期望结果 |
+| --- | --- | --- | --- | --- |
+| UI-001 | P0 | 同容器拖动到最前 | 在某容器中把第 3 个 App 拖到第 1 个位置 | App 顺序立即改变,不启动 App |
+| UI-002 | P0 | 同容器拖动到中间 | 把最后一个 App 拖到中间位置 | 插入位置正确,顺序保存 |
+| UI-003 | P0 | 跨行/跨列拖动 | 在网格容器中跨行拖动 App | 目标位置正确,无错位 |
+| UI-004 | P0 | 拖回原位 | 长按拖动后放回原位置 | 不写入无意义变更,不闪烁 |
+| UI-005 | P0 | 松手未移动 | 长按 App 后直接松手 | 不启动 App,不改变顺序 |
+| UI-006 | P0 | 多标签 App 独立顺序 | App 同时在 A/B 容器,重排 A | A 顺序改变,B 顺序不变 |
+| UI-007 | P0 | 重开 App Grid | 排序后关闭再打开 App Grid | 顺序保持 |
+| UI-008 | P0 | 重启 App | 排序后退出并重启 TagLauncher | 顺序保持 |
+| UI-009 | P1 | 语言切换 | 排序后切换中英文/日文 | 顺序保持,显示名变化不影响位置 |
+| UI-010 | P1 | 新安装 App | 排序后新增一个 App 并刷新 | 旧顺序保持,新 App 按默认规则追加 |
+
+## 6. 旧拖拽行为回归
+
+| ID | 优先级 | 用例 | 步骤 | 期望结果 |
+| --- | --- | --- | --- | --- |
+| DRAG-001 | P0 | 跨容器移动标签 | 从 A 容器拖 App 到 B 容器 | App 获得/移动到 B 标签,旧逻辑保持 |
+| DRAG-002 | P0 | Option 复制标签 | 按住 Option 从 A 拖到 B | App 同时保留 A/B 标签 |
+| DRAG-003 | P0 | 拖到空白移除来源标签 | 从容器拖到空白区域 | 继续出现现有确认逻辑 |
+| DRAG-004 | P0 | 拖到未分类 | 拖到未分类目标 | 继续走未分类确认与记忆逻辑 |
+| DRAG-005 | P0 | 拖到 Apple 内置组 | 拖到 Mac 自带 / Apple 内置组 | 继续被保护,不改变标签 |
+| DRAG-006 | P1 | 标签栏拖拽排序 | 拖动顶部/侧边标签排序 | 不受 App 排序拖拽影响 |
+
+## 7. 显示模式矩阵
+
+| ID | 优先级 | displayMode | 验收 |
+| --- | --- | --- | --- |
+| MODE-001 | P0 | `flat` | 顺序读取一致;是否允许拖动按产品最终边界验收 |
+| MODE-002 | P0 | `container` | 可同容器排序 |
+| MODE-003 | P0 | `coloredContainer` | 可同容器排序,颜色填充不遮挡插入提示 |
+| MODE-004 | P0 | `gridContainer` | 可同容器排序,跨行插入正确 |
+| MODE-005 | P0 | `coloredGridContainer` | 可同容器排序,跨行插入正确 |
+
+## 8. 标签位置矩阵
+
+| ID | 优先级 | 标签位置 | 验收 |
+| --- | --- | --- | --- |
+| NAV-001 | P1 | 左侧 | App 排序和标签导航互不冲突 |
+| NAV-002 | P1 | 右侧 | App 排序和标签导航互不冲突 |
+| NAV-003 | P1 | 顶部 | App 排序和标签导航互不冲突 |
+
+## 9. 尺寸与显示矩阵
+
+| ID | 优先级 | 条件 | 验收 |
+| --- | --- | --- | --- |
+| VIEW-001 | P1 | hide app names 开 | 拖动排序时不因名称隐藏误触发气泡 |
+| VIEW-002 | P1 | hide app names 关 | 名称不遮挡插入提示 |
+| VIEW-003 | P1 | icon size 40 | 小图标可拖动,命中正确 |
+| VIEW-004 | P1 | icon size 64 | 默认尺寸可拖动 |
+| VIEW-005 | P1 | icon size 80 | 大图标可拖动,布局不重叠 |
+
+## 10. 异常与取消
+
+| ID | 优先级 | 用例 | 期望结果 |
+| --- | --- | --- | --- |
+| EDGE-001 | P0 | 拖出窗口后松手 | 状态清理干净,不残留拖拽影子 |
+| EDGE-002 | P1 | 拖动中按 Esc | 取消拖动,顺序不变 |
+| EDGE-003 | P1 | 拖动中滚动 | 不出现错位插入;若暂不支持滚动拖拽,边界表现明确 |
+| EDGE-004 | P1 | 拖动中切换 Space/窗口 | 不崩溃,不残留 hover/bubble 状态 |
+| EDGE-005 | P1 | 拖动中打开 Quick Search/Settings | 拖动状态清理,窗口行为正常 |
+
+## 11. 现有 QA 脚本
+
+实现完成后至少运行:
+
+```bash
+cd /Users/ar/Projects/Taglauncher/src
+bash Scripts/macos14_availability_typecheck_qa.sh
+bash Scripts/macos14_build_metadata_qa.sh
+bash Scripts/quick_search_app_name_qa.sh
+bash Scripts/quick_search_system_app_qa.sh
+bash Scripts/smartstart_catalog_resource_qa.sh
+bash Scripts/window_logic_qa.sh
+```
+
+## 12. 发布阻断条件
+
+- 顺序在刷新、重启、语言切换、导入导出、恢复上一方案任一路径丢失。
+- 同容器排序破坏跨容器移动、Option 复制、拖空白移除、Apple 内置保护。
+- 旧数据无法加载或升级后默认顺序改变。
+- macOS 14 typecheck/build metadata/window logic 任一失败。
+- 手工发现拖拽残影、误启动 App、窗口关闭、UI 重叠或插入位置不可理解。
diff --git "a/docs/7.90/05-\346\212\200\346\234\257\350\256\276\350\256\241\346\226\271\346\241\210.md" "b/docs/7.90/05-\346\212\200\346\234\257\350\256\276\350\256\241\346\226\271\346\241\210.md"
new file mode 100644
index 0000000..c743065
--- /dev/null
+++ "b/docs/7.90/05-\346\212\200\346\234\257\350\256\276\350\256\241\346\226\271\346\241\210.md"
@@ -0,0 +1,262 @@
+# 7.9.0 技术设计方案:容器内 App 手动排序
+
+## 1. 目标
+
+在现有 TagLauncher App Grid 中支持同一容器内 App 拖动排序,并将顺序作为“分类与布局方案”的一部分持久化。
+
+## 2. 当前架构现状
+
+- `AppInfo` 不包含用户顺序字段,定义在 `src/Apptag/DataLayer.swift`。
+- `TagDatabase.Store` 当前有 `appTags` 和 `tagOrder`,没有容器内 App 顺序字段。
+- `AppIndexer.group()` 负责按 tag 分组,组内 App 顺序来自扫描结果 append 顺序。
+- `ContentView.makeDisplayGroups()` 将分组名本地化后传给 App Grid。
+- `AppGridCollectionView` 是 `NSViewRepresentable` + AppKit 自绘 grid。
+- `AppGridGroupCardView` 按 `group.apps.indices` 布局 icon。
+- `AppGridIconNSView` 当前长按拖动表示跨 tag 移动/复制,不包含目标插入 index。
+
+## 3. 设计原则
+
+- 顺序是数据,不是临时 UI 状态。
+- 容器 ID 必须稳定,不能依赖本地化显示名。
+- 同容器排序不改变 `appTags`。
+- 旧拖拽语义优先保护,不为排序重写跨容器拖动。
+- 第一版以 path 作为 App 顺序身份,降低实现复杂度。
+- 不存像素坐标、row/column、`IndexPath`,因为布局会随窗口尺寸、displayMode、iconSize 改变。
+
+## 4. 数据模型
+
+### 4.1 Store 新字段
+
+建议在 `TagDatabase.Store` 增加:
+
+```swift
+var containerAppOrder: [String: [String]] = [:]
+```
+
+含义:
+
+- key:稳定容器 ID。
+- value:该容器内 app path 的完整或部分顺序。
+
+旧数据兼容:
+
+```swift
+containerAppOrder = try container.decodeIfPresent(
+    [String: [String]].self,
+    forKey: .containerAppOrder
+) ?? [:]
+```
+
+### 4.2 容器 ID
+
+建议新增 helper,统一生成容器 ID:
+
+```swift
+enum AppContainerID {
+    static let uncategorized = "__container.uncategorized"
+    static let appleBuiltIn = "__container.appleBuiltIn"
+
+    static func tag(_ name: String) -> String {
+        "tag:\(name)"
+    }
+
+    static func system(_ id: SmartCategoryID) -> String {
+        "system:\(id.rawValue)"
+    }
+}
+```
+
+第一版可以先支持普通 tag 和特殊容器,系统分类 ID 映射按现有 `TagDef.systemCategoryID` 补齐。
+
+### 4.3 TagGroup 扩展
+
+当前 `TagGroup.id` 使用 `name`。建议增加:
+
+```swift
+struct TagGroup: Identifiable {
+    var id: String { containerID }
+    let containerID: String
+    let name: String
+    let apps: [AppInfo]
+}
+```
+
+这样 UI 显示名可以本地化,但排序和滚动定位使用稳定 ID。
+
+兼容注意:
+
+- 现有按 `group.name` 判断特殊组的逻辑要逐步改为 container ID。
+- 滚动目标如果仍传显示名,需增加兼容查找。
+
+## 5. 排序算法
+
+输入:
+
+- 某个容器原始 apps。
+- `containerAppOrder[containerID]`。
+
+输出:
+
+- 已命中顺序的 App 先按记录顺序排列。
+- 未命中记录的新 App 追加到后面,按现有默认名称排序。
+- 顺序字段中不存在的 path 忽略,可在保存或 reconcile 时清理。
+
+伪代码:
+
+```swift
+func applyAppOrder(apps: [AppInfo], order: [String]) -> [AppInfo] {
+    let byPath = Dictionary(uniqueKeysWithValues: apps.map { ($0.path.path, $0) })
+    let ordered = order.compactMap { byPath[$0] }
+    let orderedPaths = Set(ordered.map { $0.path.path })
+    let remaining = apps
+        .filter { !orderedPaths.contains($0.path.path) }
+        .sorted { $0.name.localizedStandardCompare($1.name) == .orderedAscending }
+    return ordered + remaining
+}
+```
+
+## 6. 写入 API
+
+建议新增:
+
+```swift
+extension TagEditor {
+    static func reorderApps(inContainer containerID: String, orderedPaths: [String])
+}
+```
+
+写入规则:
+
+- 只保存当前容器内可见 App 的完整 path 顺序。
+- 去重。
+- 过滤空 path。
+- 如结果等于当前有效顺序则不写。
+- 走 `TagDatabase.saveUserCategorySchemeMutation(reason: "reorder-apps")`。
+
+## 7. 分类方案与导入导出
+
+必须更新:
+
+- `TagDatabase.Store.CodingKeys`:加入 `containerAppOrder`。
+- `CategorySchemeFingerprint`:加入规范化后的 `containerAppOrder`。
+- `exportTo` / `importFrom`:自动随 Store 编码,但要补 roundtrip QA。
+- `restore(fromBackupAt:)`:恢复顺序字段。
+- `resetAppTagAssignmentsToUncategorized()`:清理或重建顺序字段,建议清空旧普通容器顺序。
+- `SmartStartService.applyDraft(replaceExistingScheme: true)`:清空旧顺序。
+- tag rename/delete/relocalize:迁移或清理 `tag:<name>` 对应顺序。
+- reconcile removed apps:清理顺序字段里的 orphan path。
+
+## 8. UI 集成
+
+### 8.1 回调
+
+`AppGridCollectionView` 增加:
+
+```swift
+let onReorderApps: (String, [String]) -> Void
+```
+
+其中:
+
+- 第一个参数为 `containerID`。
+- 第二个参数为排序后的 app path 列表。
+
+`ContentView` 接收后调用 `TagEditor.reorderApps`,再 `refreshApps(forceLayoutRefresh: true)` 或局部刷新。
+
+### 8.2 Hit-test
+
+在 `AppGridGroupCardView` 内根据鼠标位置计算 insertion index:
+
+- 使用当前 `iconViews` frame。
+- 同容器内拖动时显示插入线/占位。
+- 松手时生成新 path 顺序。
+- 拖出当前 group 或命中其他 drop target 时走旧拖拽逻辑。
+
+### 8.3 拖拽 intent
+
+现有 payload 是 `path + sourceTag` 字符串,不适合继续扩展复杂状态。建议内部引入结构化状态:
+
+```swift
+struct AppDragPayload {
+    let path: String
+    let sourceContainerID: String
+    let sourceDisplayName: String
+}
+```
+
+第一版如果为了控制改动范围暂不完全替换 `AppDragCoordinator` payload,也必须在同容器排序分支中独立判断 source/target 和 insertion index,避免误触发旧 drop。
+
+### 8.4 状态清理
+
+排序开始:
+
+- 抑制 hover bubble。
+- 结束 tag nav reorder。
+- 标记 app drag mode active。
+
+排序结束或取消:
+
+- 清除插入提示。
+- 恢复 bubble 状态。
+- 清理 drag image / hover target。
+
+## 9. 不改范围
+
+- 不改 Quick Search rank。
+- 不改 App 扫描规则。
+- 不改 SmartStart 分类匹配逻辑。
+- 不改跨容器拖动的标签归属规则。
+- 不改设置页现有数据面板结构。
+
+## 10. 迁移策略
+
+- 不需要一次性迁移用户数据。
+- 新字段缺省为空,表示使用旧默认顺序。
+- 第一次用户在某容器排序后,只写该容器顺序。
+- 版本升级到 `7.9.0` 时在 changelog 说明新增布局顺序字段。
+
+## 11. 开发顺序
+
+1. 数据层:
+   - Store 字段、容器 ID、排序 helper、写入 API、fingerprint、导入导出/恢复/重置/SmartStart 处理。
+   - 配套数据 QA。
+
+2. UI 层:
+   - 同容器 insertion index hit-test。
+   - 插入提示。
+   - 本地顺序预览。
+
+3. 集成:
+   - drop/end 写入。
+   - refresh 后顺序保持。
+   - 旧拖拽行为回归。
+
+4. 发布:
+   - 版本号 `7.9.0`。
+   - `CHANGELOG.md`。
+   - DMG / App Store 资料按实际发布目标准备。
+
+## 12. 风险与控制
+
+| 风险 | 等级 | 控制 |
+| --- | --- | --- |
+| 顺序未持久化导致刷新丢失 | 高 | 数据层先行,QA roundtrip |
+| 本地化显示名作为 key 导致语言切换错位 | 高 | 统一 container ID |
+| 同容器排序误触发跨标签移动 | 高 | 独立 intent 和 hit-test |
+| 导入导出/恢复漏字段 | 高 | fingerprint + export/import QA |
+| 拖拽状态残留 | 中 | 统一 cancel/cleanup |
+| 新字段污染旧用户默认顺序 | 中 | 空字段即旧排序 |
+
+## 13. 必跑验证
+
+```bash
+cd /Users/ar/Projects/Taglauncher/src
+bash Scripts/macos14_availability_typecheck_qa.sh
+bash Scripts/macos14_build_metadata_qa.sh
+bash Scripts/quick_search_app_name_qa.sh
+bash Scripts/quick_search_system_app_qa.sh
+bash Scripts/smartstart_catalog_resource_qa.sh
+bash Scripts/window_logic_qa.sh
+```
+
+同时必须做真实鼠标手工验证,覆盖同容器排序、跨容器拖动、Option 复制、拖空白移除、macOS 14、5 种 displayMode 和 3 种标签位置。
diff --git a/docs/7.90/README.md b/docs/7.90/README.md
index 5b8d181..58ff82e 100644
--- a/docs/7.90/README.md
+++ b/docs/7.90/README.md
@@ -21,6 +21,9 @@
 
 - [01-容器内App手动排序-TODO.md](./01-容器内App手动排序-TODO.md):可执行开发 TODO、切分和 QA 阻断项。
 - [02-专题讨论纪要.md](./02-专题讨论纪要.md):2 个架构师、1 个代码审核员、1 个 QA 的专题讨论结论。
+- [03-产品PRD.md](./03-产品PRD.md):产品目标、范围、交互、验收标准和发布要求。
+- [04-QA测试用例集.md](./04-QA测试用例集.md):QA 测试矩阵、自动化用例、手工用例和发布阻断条件。
+- [05-技术设计方案.md](./05-技术设计方案.md):数据模型、UI 集成、迁移策略和技术风险控制。
 
 ## 后续记录规则
 

--
Gitblit v1.9.3