Files

686 lines
49 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 多账号助手 UI 与调用逻辑细化方案
> 本文在原始 `plan01` 草案基础上整理,依据 `docs/2026-09-06-11-05-PLAN.md` 及后续 0.1.50.1.8 的实现和验证记录细化。本文描述目标交互、状态和调用边界,不代表所有目标 UI 已完成验收。
>
> 已纳入 [2026-09-08 评审](2026-09-08-15-56-plan01-review.md) 的十项补充。后续 UI、生命周期和任务安全实现以本文及 `AGENTS.md` 为准;早期计划中的恢复顺序、动作串并行和待确认项不再覆盖本文。新增字段、命令与交互仍须实施并验收,不能因写入方案就标记已完成。
>
> **用户最新调整**:任务不需要人工核定。`unknown` 仅作结果不确定的只读记录,不提供人工判定成功/失败、提交核定说明或据此修改状态的操作;不自动重发和既有安全保护不变。此决定覆盖原评审的人工核对建议,见 [变更记录](2026-09-08-16-40-unknown-readonly.md)。
>
> **2026-09-20 用户确认的生命周期调整**:大号成功完成登录和身份核验后,自动启动该组中已绑定且未被手动停止的小号;未登录小号等待登录,不阻塞大号监听。小号右键提供“启动任务 / 停止任务”;手动停止标记写入 SQLite,应用重启和大号再次登录都不得自动恢复,必须由小号右键显式启动。
## 1. 目标
将主窗口调整为“账号树 + 账号详情 + 全局日志”的工作台:
- 左侧统一管理大号、小号及其归属关系。
- 账号节点直接显示登录、身份、监听/执行等状态。
- 账号操作收纳到右键菜单,按账号角色只显示可用操作。
- 选中大号后,右侧查看历史事件和作品列表。
- 选中小号后,右侧查看当前任务和历史执行记录。
- 窗口底部持续显示全局运行日志。
- 不改变已有业务约束:不自动登录,身份不匹配不执行,unknown 结果不自动重发;大号身份核验成功后,仅自动启动已绑定且未手动停止的小号。
## 2. 总体布局
```text
┌─────────────────────────────────────────────────────────────────────┐
│ 添加账号 │ 恢复上次选择 / 启动勾选组 │ 停止全部 │ 异常任务 │ 设置 │
├───────────────────────┬─────────────────────────────────────────────┤
│ 账号树 │ 账号详情区 │
│ │ │
│ ● 大号01 │ 大号01 │
│ 监听:运行中 │ 状态摘要 / 规则摘要 │
│ ├─ ● 小号01 │ ┌────────────┬────────────┐ │
│ │ 执行:空闲 │ │ 历史事件 │ 作品列表 │ │
│ └─ ○ 小号02 │ └────────────┴────────────┘ │
│ 执行:待登录 │ │
│ │ │
│ ● 大号02 │ │
│ └─ ● 小号03 │ │
│ │ │
│ ○ 未分配小号 │ │
├───────────────────────┴─────────────────────────────────────────────┤
│ 全局运行日志:推送、详情、分配、任务结果、异常和恢复信息 │
└─────────────────────────────────────────────────────────────────────┘
```
### 2.1 区域职责
| 区域 | 内容 | 交互原则 |
| --- | --- | --- |
| 顶部工具栏 | 添加/恢复账号、恢复选择、启动、停止、异常任务、浏览器设置 | 只保留跨账号或创建类操作 |
| 左侧账号树 | 大号、小号、归属和状态 | 选择账号查看详情;大号复选框用于批量启动 |
| 右侧详情区 | 当前账号资料、规则、事件、作品或任务 | 内容随角色切换,不显示无关操作 |
| 底部日志区 | 最近 2000 条运行记录 | 只读、默认滚动到最新,可打开完整日志目录 |
## 3. 账号树
### 3.1 节点层级
```text
[复选框] [状态点] 大号名称
监听状态:运行中 / 已停止 / 连接中 / 需要登录 / 出错
├── [状态点] 小号名称
│ 执行状态:空闲 / 执行中 / 等待任务 / 需要登录 / 出错
└── [状态点] 小号名称
执行状态:已暂停 / 未分配 / 已删除(历史记录中保留)
```
- 大号为顶层节点,复选框只对大号生效;“恢复上次选择”只恢复勾选,“启动勾选组”才进入确认和启动流程。
- 小号显示在所属大号下;未归属小号放入“未分配小号”节点或单独分组。
- 一个小号最多归属一个大号;未归属小号不接收任务。
- 不使用昵称或 UID 作为内部节点 ID,节点操作始终使用内部账号 ID。
- 删除的小号从活动树移除,但历史任务仍显示原本地名称并标记为已删除。
### 3.2 状态点
状态点只表达粗粒度状态,详细原因放在节点第二行和右侧详情中:
| 颜色 | 状态 | 含义 |
| --- | --- | --- |
| 绿色 | 在线 / 可用 | 已连接且身份核验通过 |
| 灰色 | 已停止 / 离线 | 未运行监听或执行,或连接已断开 |
| 橙色 | 需要登录 / 需要验证 | 浏览器可打开,但需要用户手动处理 |
| 红色 | 身份不匹配 / 错误 | 实际 UID 与绑定 UID 不一致,停止所有写操作 |
| 蓝色 | 启动中 / 停止中 / 重连中 | 正在进行生命周期操作 |
必须分别显示以下三个维度,不能把“已登录”直接显示为“正在监听”:
1. **登录状态**:已登录、未登录、需要验证。
2. **身份核验**:未绑定、核验通过、UID 不匹配、核验失败。
3. **运行状态**:未运行、启动中、监听中、执行中、已暂停、停止中、错误。
### 3.3 节点文案
大号节点至少显示:
- 自定义名称;
- 昵称和 UID
- 登录状态、身份核验状态;
- 监听运行状态;
- 自动规则:已启用 / 已关闭;
- 任务计数:待执行、执行中、结果不确定、失败;
- 作品缓存数量和最近更新时间(有缓存时)。
小号节点至少显示:
- 自定义名称;
- 昵称和 UID
- 所属大号;
- 登录状态、身份核验状态;
- 执行状态;
- 当前待执行、执行中和结果不确定任务数量。
### 3.4 生命周期状态与转换
身份、运行状态与任务结果是三个独立维度。已绑定 UID、命令返回“已受理”、浏览器已打开,都不等于本次运行已就绪。
| 阶段/状态 | 进入条件与允许行为 | 退出条件与约束 |
| --- | --- | --- |
| 启动恢复 | 获得本地数据库单实例使用权、完成必要迁移;此时不存在 worker | 遗留 running 先转 unknown,恢复失败则停在错误状态,不开放启动 |
| 已停止 | 可以查看本地数据、编辑规则、显式登录或只读同步 | 大号核验成功后自动启动可用小号;手动停止的小号只能由其右键显式启动;恢复选择本身不启动 |
| 启动中 | 建立账号连接,核验实际 UID 和所需能力;禁止小号领取 | 大号就绪后才放行通过核验的小号;失败显示具体原因;停止请求随时有效 |
| 监听中/等待任务/执行中 | 大号已就绪,小号身份与归属有效,当前安全限制允许 | 小号每次只领取一个通知批次;批内关注/私信独立并行 |
| 已暂停/需要登录/身份异常 | 立即关闭对应领取入口;大号异常影响整组,小号异常只影响自身 | 不自动登录、改派或解除风控;恢复需显式操作及重新核验 |
| 停止中 | 立即禁止新增调度和领取,取消只读同步,收尾在途动作 | 重复停止幂等;拒绝再次启动、转移和删除,直到收尾完成 |
| 已停止且有不确定结果 | 调度已停止,但存在 unknown;浏览器可以保留 | 只读展示数量和原结果,不要求用户核定;不得把“已停止”解释为所有动作已确定结束 |
| 删除处理中/删除异常 | 已持久化删除意图,账号禁止启动和领取 | 仅允许查看和显式重试清理;不得自动恢复业务 |
- 运行状态由引擎报告,UI 不通过按钮点击或超时自行推断成功。
- 批量启动返回逐账号结果;部分小号失败不能显示为全组全部成功,也不回滚其它独立组。
- 启停使用账号级操作标志/运行代次防止迟到回调重新放行;停止后旧代次不能启动 worker。无需引入通用状态机框架。
## 4. 顶部工具栏
顶部只放全局或创建类操作,不重复放账号专属操作:
| 按钮 | 行为 |
| --- | --- |
| 添加大号 | 创建大号记录,随后打开独立浏览器,等待用户手动登录 |
| 添加小号 | 提供新建及“恢复已删除小号”入口;新建时可选择归属,恢复保留原内部 ID 和 UID,见 §8.7 |
| 恢复上次选择 | 只恢复有效大号的复选框,不连接浏览器、不启动监听或执行 |
| 启动勾选组 | 无选择则提示;先展示旧 pending 数量、最早时间和规则快照提示,再由用户确认启动 |
| 停止全部 | 优先禁止监听调度和任务领取,在有限时限内收尾,保留 Chrome 浏览器 |
| 异常任务 | 只读查询 unknown,包含已删除和已转移小号的原任务,支持按原组筛选;不提供人工核定操作 |
| 浏览器设置 | 编辑全局浏览器可执行文件和高级参数;单账号覆盖设置放入账号右键菜单 |
只禁用同一账号的冲突操作,不全局锁住工具栏。长同步期间“停止全部”、查看本地数据和状态更新仍可用;状态栏区分“已受理 / 启动中 / 停止中 / 已完成 / 部分失败”。停止期间提示在途动作仍可能生效,具体收尾期限和 unknown 处理见 §8.6。
## 5. 右键菜单
原页面下方的账号操作按钮移入账号树右键菜单。右键菜单只承载账号生命周期、归属和配置类操作;历史事件和作品监控已经在选中账号后的右侧详情区提供入口,不在右键菜单重复提供。菜单根据角色、登录状态、归属和运行状态动态裁剪;不可用操作可以隐藏,也可以保留为禁用项并显示原因,但不能让用户提交必然失败的请求。
### 5.1 大号菜单
```text
大号01
├─ 登录 / 刷新账号信息
├─ 启动本组
├─ 停止本组
├─ 配置自动操作规则
├─ 打开账号浏览器
├─ 关闭浏览器
└─ 删除登录数据
```
说明:
- 历史事件和作品监控请先点击大号,在右侧详情区进入对应 TAB;右键不提供重复入口。
- 动作内容及作品范围只影响新入队事件,已创建任务保留快照;规则总开关、暂停和当前安全限制按 §6.4 即时约束领取,不能用旧快照绕过。
- “删除登录数据”关闭并清空该账号浏览器登录目录,但保留账号、历史事件、任务和规则。
- 大号不显示“切换归属”和“删除小号”。
### 5.2 小号菜单
```text
小号01
├─ 登录 / 刷新账号信息
├─ 切换 / 解除归属
├─ 打开账号浏览器
├─ 关闭浏览器
├─ 删除登录数据
└─ 删除小号
```
说明:
- 小号提供“启动任务 / 停止任务”,只控制自身任务领取和执行,不改变所属大号监听;停止标记持久化,应用重启、大号重新登录和组启动都不会自动恢复,菜单与详情明确显示“已手动停止”。
- 小号不显示大号专属的规则配置、历史事件同步和作品监控;执行记录直接在选中小号后的右侧详情区查看。
- “切换 / 解除归属”先停止原所属组(未分配小号无需此步);有 running 或处于启停/删除中时拒绝。确认后在事务中取消旧组 pending 并更新归属,不改派、不重发,保留历史和 unknown;转移后不自动启动。
- “删除小号”必须先停止所属组并等待在途任务结束;关闭浏览器、删除独立 profile 成功后才从活动列表移除。
- 删除小号只取消 pending 任务,保留 succeeded、failed、unknown、cancelled 历史;确认框展示结果不确定的任务数量及删除后的只读查找入口。删除意图和部分失败处理见 §8.6,重新添加同 UID 见 §8.7。
- “打开账号浏览器”只打开或连接对应独立 profile,不切换到其它账号。
### 5.3 空白区菜单
不显示账号专属操作,只可提供:
- 刷新账号树;
- 打开日志目录;
- 打开全局浏览器设置。
### 5.4 操作允许条件与互斥矩阵
UI 禁用仅用于提示,后端仍须按当前状态、角色和内部账号 ID 校验。归属更新、任务领取和 pending 取消在数据库事务内重查条件。
| 操作 | 允许条件 | 冲突/异常行为 |
| --- | --- | --- |
| 启动组 | 恢复已完成;组非启动中/停止中/删除中;积压确认有效 | 重复请求不创建第二套 worker;逐账号报告就绪或失败;已手动停止的小号不加入 |
| 停止/退出 | 任意运行阶段,包括登录等待和长同步 | 优先关闭领取入口;重复提交返回同一收尾状态,不排在同步后 |
| 登录/打开浏览器 | 用户显式发起;身份变更前停止对应组 | 不自动登录;普通只读资料刷新不等于允许换号 |
| 历史/作品同步 | 有效大号,当前 UID 核验通过 | 同账号同步合并/拒绝重复请求;不同账号可并发;停止可取消只读任务 |
| 保存规则/作品范围 | 所选账号有效,提交基线未过期 | 拒绝覆盖其它配置入口或后台已更新的配置;按 §6.4 生效 |
| 取消 pending | 明确列出待取消 task ID 并确认 | 只取消仍为 pending 的本组任务;已变为 running/unknown 的返回跳过原因 |
| 转移/解除归属 | 原组停止、无 running,目标大号有效 | 事务重查后取消旧 pending;原任务来源不改写;新组即使运行也不自动启用转入小号 |
| 删除登录数据/小号 | 停止收尾完成,明确确认影响范围 | 持久化删除意图后清理;部分失败保持禁止启动,不能显示完全成功 |
| 查看不确定结果 | task ID 存在,不要求原执行账号仍活动 | 只读展示,不判定成功/失败,不修改状态、不重发、不重新执行依赖动作 |
耗时操作返回 request ID/受理状态并异步报告完成;内部账号级互斥保护连接、页面初始化和生命周期变更。不能把整段同步挂在唯一命令消费循环上,也不能把互斥扩大成阻止批次内两个独立动作并行。
## 6. 右侧详情区
右侧顶部显示当前账号的基本资料和状态摘要,下面显示角色对应内容。账号树中的单击/选择负责切换详情;右键只负责执行账号操作,不负责重复打开历史事件、作品监控或执行记录页面。
### 6.1 通用摘要
- 头像、昵称、UID、抖音号(如有);
- 登录状态、身份核验、运行状态;
- 独立浏览器端口和 profile 路径只在设置或诊断信息中显示,不在普通列表中暴露;
- 粉丝、关注、获赞、作品数量等平台资料;
- 最近一次状态变化、错误原因和待处理数量;
- 大号摘要中的“结果不确定”计数可打开原组只读任务列表,包含已删除小号;与顶部“异常任务”入口复用同一任务表,不新增第三个大号主要 TAB。
业务字段如 UID、昵称、作品 ID、评论和结果说明可按原文展示;Cookie、Authorization、Session、Token、密码、签名参数等凭据始终隐藏。
### 6.2 选中大号:两个 TAB
#### TAB 1:历史事件
用于查看大号已缓存的实时和历史通知,并在确认后将历史事件交给小号执行。
表格列:
- 选择;
- 发生时间;
- 事件类型:点赞、关注、评论、收藏/其他作品互动;
- 来源用户 UID 和昵称;
- 作品 ID 和作品描述;
- 评论或其它内容;
- 通知 ID
- 数据来源:实时收到 / 历史同步;
- 当前处理状态或任务数量。
操作:
1. 点击“同步历史事件”执行只读同步:没有完整基线时全量补齐,有完整基线时才使用已验证的增量停止策略;另提供“完整补齐”重建基线。
2. 实时缓存非空不代表首次全量已完成。首次同步持续分页直到平台返回结束;重复游标、安全上限、接口失败都必须显示未完成,不能把截断结果称为“全部”,详见 §9.2。
3. 请求固定使用 `notice_group=700``is_mark_read=0`,不标记已读。
4. 默认不勾选任何行;支持按事件类型过滤、全选当前显示、清空当前显示。
5. 点击提交后预览选择数量、来源大号、动作组合和消息内容/规则摘要,再弹出二次确认;默认按钮为“否”。预览保存规则及作品配置的版本或内容摘要。
6. 二次确认只提交当前已加载的通知 ID、账号 ID、request ID 和预览基线;后端从缓存读取完整对象,重查身份、归属、规则开关及作品范围。基线变化则拒绝提交并要求重新预览确认,不能静默换用新规则。
7. 入队及去重在事务中完成;重复提交不产生重复任务。结果显示选择数、新增事件数、实际任务数和各类跳过数量;三者可以不同,原因写入运行日志。
历史事件进入队列后使用低优先级;实时新消息优先。历史确认前只缓存数据,不创建任务、不执行关注或私信。
#### TAB 2:作品列表
使用作品 CARD 展示,不使用宽表格作为主要视觉呈现。
每张 CARD 包含:
- 左侧封面,优先从本地 `work_covers/` 读取;
- 作品描述,默认最多两行,支持展开/收起;
- 作品 ID
- 点赞、评论、收藏、分享,分行显示;
- 发布时间;
- 本地更新时间;
- 监控选择框。
工具区:
- “监控全部作品”:默认开启,新作品自动纳入;
- 关闭后进入“指定作品”模式,至少选择一个作品;
- “强制增量刷新”:从最新页开始读取并更新 SQLite 缓存;
- “完整补齐”:显式完成/重建全量基线;显示最近成功时间、覆盖范围及失败/截断原因;
- 运行期间自动刷新间隔,默认 60 分钟,0 表示关闭,最大 7 天;
- 全选、清空选择、保存设置。
行为边界:
- 首次打开且无缓存时只读分页获取平台可返回的作品;有缓存时普通打开只读本地数据。缓存存在但基线未完成时显示“未完整同步”,由用户显式补齐,不冒充全部作品。
- 不假设列表严格按发布时间排序;置顶作品、重复页和已知作品 ID 不能独自证明后续没有新增。增量提前停止必须有验证过的连续性依据。
- 自动刷新只在对应账号组运行时执行;停止组后不再定时请求。
- 指定作品模式只影响之后入库的互动事件;已创建任务不被改写。
- 点赞、评论、收藏/其它作品互动必须有作品 ID且命中选择范围;关注通知没有作品 ID,不受作品范围限制。
- 封面下载只允许受控的抖音图片 HTTPS 域名,成功后临时文件原子替换,失败不影响作品数据。
### 6.3 选中小号:执行记录
右侧不显示历史事件和作品监控,而显示该小号实际接收和执行的任务。
建议分为两个筛选区域:
- **当前任务**pending、running、unknown
- **历史任务**succeeded、failed、cancelled,以及已完成的其它记录。
表格列:
- 任务 ID
- 来源大号;
- 通知 ID / 事件;
- 目标 UID
- 动作:关注或私信;
- 状态;
- 创建时间、开始时间、完成时间;
- 结果说明;
- 失败原因或结果不确定的只读提示。
`unknown` 仅展示原结果和诊断信息,不提供“已成功 / 未成功”核定按钮、核定说明提交或人工改状态命令,不要求用户到平台核实结果。移除人工操作不等于自动判定或放行,不确定任务仍不得重发。
关注和私信同时开启时是两个独立任务,并行执行、分别保存结果,一个失败不取消另一个。
- 当前任务提供“取消所选 pending”,确认框显示任务数、原规则摘要及取消后不重发;不得取消 running/unknown 或重新分配给其它小号。
- 全局/大号异常任务入口复用此表,只读显示原执行账号及已删除标记、原所属组、目标、动作、阶段时间和原始结果。历史来源不随当前归属变化;查询使用 task ID,不要求旧浏览器存在。
- 浏览、筛选和查看详情不能写任务状态,也不能通过按钮、快捷键或后台命令提交人工结论。停止收尾后的迟到回包不得覆盖已落库的 unknown 或终态,只追加诊断信息。
### 6.4 规则生效与积压任务
| 配置/操作 | 生效边界 | 已有任务处理 |
| --- | --- | --- |
| 规则总开关关闭 | 立即禁止新事件自动入队及后续领取;后端在领取前重查 | pending 保留,在途动作收尾;不等于取消任务 |
| 规则总开关开启 | 只恢复规则资格,不启动已停止的组 | 有旧 pending 时先按启动同样的流程确认;已运行组也不能绕过此确认恢复领取;不自动补发关闭期间已跳过事件 |
| 停止组、身份/归属异常 | 立即关闭对应调度与领取入口 | 不改变任务内容;无法确认的在途动作转 unknown |
| 动作类型、私信内容、作品范围 | 只作用于新入队事件 | 已有任务沿用原快照;保存时提示不会改写/取消旧任务 |
| 配额、执行间隔、冷却和风控暂停 | 领取/发送前按当前安全限制重查 | 原快照不能绕过收紧后的限制;修改配置不缩短已经生效的冷却 |
| 取消所选 pending | 确认后按 task ID 条件更新 | 保留取消原因及去重记录;不取消 running/unknown,不自动改派 |
| 历史预览并提交 | 使用确认时校验通过的规则及作品配置基线 | 基线变化重新确认;同一通知仍通过数据库去重 |
本版区分暂停、关闭新入队和取消任务的效果,但不增加“仅关闭入队、继续消费旧队列”的独立模式:关闭规则同时暂停后续领取,UI 必须明确显示这两个效果。规则保存成功不等于任务开始执行。
启动或重新启用规则的积压确认展示所选组的 pending 总数、最早入队时间(旧数据缺失显示未知)、动作/规则摘要和“继续 / 取消所选旧任务 / 返回”选项。预览记录旧 pending 的 ID 集合或等价队列基线;提交前旧任务集合、所属组或快照摘要变化须重新预览,不能把未确认的旧任务悄悄纳入恢复。正常启动后产生的新实时任务仍按已启用规则处理,不要求每条再次确认。当前不自动设置 TTL,只有业务另行确认有效期后再实现过期策略。
### 6.5 异步回包、草稿与查询契约
- 请求/回包携带内部 account ID、请求类型和 request ID;详情只接受当前账号、当前请求的结果。删除、转移和运行代次变化后使相关旧请求失效。
- 同一账号的重复同步返回已有任务状态或明确拒绝;完成、失败、取消分别上报,命令已受理不代表成功。
- 账号树当前选中项、用于批量启动的大号勾选集合、各账号未保存草稿分别保存。右键动作固定绑定命中的账号 ID,不临时读取可能已变化的全局选中项。
- 周期快照只刷新只读状态,不覆盖 dirty 规则/作品选择。切换账号时提供保存、放弃、取消切换;后台配置基线变化时提示冲突,不静默覆盖草稿。
- 任务、通知、作品、日志在后端先按账号/原组/状态过滤,再稳定排序分页;不能先取全局最近 N 条再前端过滤。全选/清空默认仅作用于当前已加载结果。
- 显示未同步、加载中、空结果、部分结果、失败和成功的区别;状态快照及本地查询不等待长同步结束。
## 7. 底部全局日志
整个窗口下方固定显示“运行记录(最近 2000 条)”。
### 7.1 展示内容
按业务阶段记录:
```text
启动 / 停止
→ 账号打开与身份核验
→ 推送接收与去重
→ 详情获取与入库
→ 规则匹配与跳过原因
→ 小号选择与任务入队
→ 任务领取与动作开始
→ 任务成功 / 失败 / 结果不确定
→ 重连、暂停、恢复
```
日志必须明确区分:
- “详情入库”不等于动作执行;
- “分配完成”不等于关注或私信成功;
- 只有任务结果为成功才表示已确认成功;
- unknown 表示结果不确定,不能自动重发。
### 7.2 UI 行为
- 默认自动滚动到最新记录;用户取消后允许向上查看。
- Qt 控件最多保留最近 2000 行;文件日志不受此上限影响。
- 提供“打开日志文件夹”按钮。
- 普通文件日志错误显示在日志区顶部,可以降级而不使业务线程崩溃;SQLite 任务账本写失败必须阻止后续动作,不能按日志失败处理,见 §9.4。
- 完整日志按本地日期保存到 `%LOCALAPPDATA%\\DouyinAccounts\\logs\\YYYY-MM-DD.log`
- SQLite 事务回滚时不写入“已成功”的日志。
- 清空 UI 只清展示缓冲;清理普通日志不得删除 tasks、events、cooldowns、unknown 记录或同步基线。未定义保留期前不做自动历史清理。
## 8. 端到端调用逻辑
### 8.1 添加账号与登录回填
```text
点击添加大号/小号
→ 输入自定义名称和小号归属
→ 创建账号记录、独立 profile、端口和浏览器配置
→ 打开对应浏览器
→ 用户手动登录
→ 读取当前页面资料并核验 UID
→ 绑定 UID、昵称、头像和统计
→ 更新账号树和详情区
```
- 不自动填写账号、不自动登录、不绕过验证码或风控。
- 如果登录状态丢失,暂停对应账号并提示用户手动处理。
- 实际 UID 与已绑定 UID 不一致时拒绝覆盖和写操作。
- UID 已被活动账号绑定时拒绝重复绑定;对应软删除小号时转入 §8.7 的显式恢复流程,不能清空原 UID 或创建第二条身份绕过约束。
### 8.2 启动账号组
```text
进程启动(尚不存在 worker
→ 检查数据库单实例、迁移及账本可用性
→ 遗留 running 转 unknown,保留删除处理中状态
→ 展示结果不确定和积压计数;停在未运行状态
用户恢复/勾选大号并点击启动
→ 预览并确认旧 pending 与原规则快照
→ 复用或启动大号独立浏览器,连接 loopback CDP
→ 核验真实 UID、登录及监听能力
→ 大号监听就绪,逐个核验小号身份和归属
→ 仅允许已核验小号领取任务,启用本组作品定时刷新
→ 逐账号报告成功/失败,更新账号树和日志
```
- 中断恢复只在任何 worker 启动前执行,不在每次启动组时扫描并重写全库 running;保留现有初始化先恢复的顺序。
- 大号失效时停止新任务产生并暂停整组;缓存里的已绑定 UID 不能代替本次在线核验。
- 小号失效时保留原任务等待,不自动改派其它小号;其它正常小号可继续,但组状态必须显示部分异常。
- 一个大号组失败不影响其它大号组,但不能跨组派发任务。启动中收到停止后,迟到的连接成功不能重新放行。
### 8.3 实时事件
```text
大号 SDK 推送
→ 持久化推送 ID 并去重
→ 获取详情并校验所属大号
→ 写入 cached_notices
→ 按规则、作品范围、来源 UID 和自操作保护过滤
→ 在所属小号中轮询选择一个
→ 创建关注/私信任务
→ 小号串行领取通知批次
→ 同批关注和私信并行执行
→ 分别回查并落库
→ 刷新小号记录、组计数和全局日志
```
约束:
- 一条通知只分配给一个关联小号,不向全部小号广播。
- 同一大号组和目标 UID 共用冷却,默认 4 小时;冷却从实际领取并即将发起请求时开始。
- pending、running、unknown 任务已存在时不重复创建。
- 触发者是执行小号自身,或目标是来源大号时,记录明确跳过原因,不创建任务。
### 8.4 历史事件
```text
选中大号并进入右侧“历史事件” TAB,点击“同步历史事件”
→ 按完整基线选择只读全量补齐或增量同步,写入 cached_notices
→ 在右侧历史事件 TAB 展示
→ 用户筛选、勾选
→ 第一次确定,预览动作/规则摘要及配置基线
→ 二次确认可能产生真实关注/私信
→ 后端按账号与通知 ID 从缓存读取对象
→ 原子重查配置基线、规则和安全条件;变化则重新确认
→ 创建 history 任务(优先级低于 live
→ 刷新任务计数和日志
```
实时事件到达后:
- 同 UID 的 pending 历史任务可以被取消,由实时任务替代;
- running 或 unknown 不强制中断、不重发;
- 相同通知先历史后实时时提升为 live,不创建重复事件或任务。
### 8.5 作品监控
```text
选中大号并进入右侧“作品列表” TAB
→ 读取本地缓存
→ 无缓存:分页获取平台可返回作品并记录基线是否完整
→ 有缓存:展示 CARD 和同步完整性,不把有缓存等同于全量完成
→ 用户可强制增量刷新或完整补齐
→ 用户选择全部作品或指定作品
→ 保存 work_mode、work_ids 和刷新间隔
→ 后续通知按作品范围过滤
```
### 8.6 停止、关闭和删除
```text
停止组 / 停止全部 / 退出程序
→ 优先设置禁止调度和领取标志,状态变为停止中
→ 取消只读同步/登录等待,卸载监听和定时刷新
→ 在收尾期限内等待已发出动作确认并落库
→ 无法确认的动作转 unknown,停止本地调度
→ 保留 Chrome 和登录目录,只读展示结果不确定的任务数量
关闭浏览器
→ 先完成对应组停止收尾
→ 关闭本程序拥有的浏览器;不杀死未确认归属的外部进程
→ 保留登录目录
删除登录数据 / 删除小号
→ 停止原组,确认无 running,展示 pending/unknown 数量并再次确认
→ 事务内记录删除类型和待清理对象,禁止启动/领取
→ 关闭受管浏览器,安全清理该账号 profile
→ 清理成功后事务提交最终状态
→ 删除登录数据:保留账号、UID、归属、规则、任务和历史
→ 删除小号:取消 pending,软删除账号,保留历史和 unknown
→ 失败/中断:保留删除处理中/异常及已完成步骤,等待显式重试
```
- 停止控制不能排在长同步后,也不能先等待登录结束才关闭领取入口。以现有 asyncio task、账号操作标志实现即可;快照更新独立于长任务完成。
- 默认总收尾预算为 60 秒,从接受停止请求起计算,不按阶段反复延长。该值作为统一常量并在界面提示;后续需调整时同时更新测试,不新增复杂配置页。
- 超时只取消本地等待,不声称远端请求回滚。已发出但无法确认的动作进入 unknown;若账本不可写,则保持禁止领取并显示持久化异常,不能伪称已成功记录 unknown。
- 停止收尾后的迟到回包不得覆盖已落库的 unknown 或终态,也不得触发下一批。使用 task 状态条件更新和运行代次校验;正常停止不关闭浏览器,强制结束进程不视为正常停止成功。
- profile 清理前校验路径处于受管根目录内且属于该账号,拒绝通过符号链接/junction 越界;不清理其它账号或外部 Chrome 登录目录。
- 文件系统与 SQLite 不是同一事务。删除意图须先落库;重试时目录已不存在视为该清理步骤完成。重启后仍显示未完成删除,不自动继续破坏性清理、恢复规则或登录。
### 8.7 异常任务只读查询与已删除小号恢复
**查看 unknown**:顶部“异常任务”或大号摘要 → 按原组/原执行账号筛选(包含已删除)→ 只读查看目标、动作、阶段时间及原结果。流程到查看为止,不包含用户自行核实、提交结论或修改任务状态,也不为释放队列猜测结果。
**恢复已删除小号**:添加小号中的“恢复已删除小号” → 选择原记录并查看历史/结果不确定的任务数量 → 确认归属 → 恢复原内部 ID、原绑定 UID 和历史引用 → 保持停止,按正常流程由用户手动登录并重新核验。恢复不复活 cancelled/pending 任务、不清空去重或冷却、不覆盖 unknown、不自动启动;目标归属变化按转移约束处理。
新建流程发现 UID 对应已删除记录时,提示转到上述入口,不直接合并账号或迁移浏览器登录数据。未绑定候选保持停止,可由用户取消创建;清理候选目录须确认且不得影响原记录。首版不做临时 profile 合并或 Cookie 搬运。
## 9. 数据与持久化边界
| 数据 | 用途 | UI 展示 |
| --- | --- | --- |
| `accounts` | 角色、名称、UID、资料、归属、规则 | 账号树和详情 |
| `cached_works` | 作品列表、统计、封面地址和业务对象 | 作品 CARD |
| `cached_notices` | 实时/历史事件统一缓存 | 历史事件 TAB |
| `events` | 已处理事件及来源、状态 | 任务关联和日志 |
| `tasks` | 不可变来源、执行小号、动作快照、状态、阶段时间及原结果 | 小号记录及包含已删除账号的只读异常列表 |
| `cooldowns` | 大号组与目标 UID 的共享冷却 | 状态提示和日志摘要 |
| `settings` | 上次选择、同步基线/游标及完整性、浏览器配置 | 设置、同步状态和仅恢复选择 |
| 按日日志 | 完整过程审计 | 底部最近 2000 条 |
SQLite 是任务真源,内存队列只负责唤醒和调度。事件写入和任务生成应处于可恢复事务中,避免出现“事件已处理但任务永久丢失”。以下为需要实施检查的字段/语义清单,不表示现有库已经具有这些字段;优先复用现有列或 settings,不为每种状态新建一套表。
### 9.1 最小字段与迁移契约
| 对象 | 必须保存的事实 | 约束 |
| --- | --- | --- |
| 账号 | 内部 ID、锁定 UID、当前归属、软删除标记、未完成删除意图 | UID 唯一包含软删除记录;恢复复用原身份;删除意图不能被重启状态清理掉 |
| 任务来源 | 原组、原执行账号、事件、目标、动作及规则快照 | 归属变更/软删除不改写原来源;删除账号不得级联删除任务 |
| 任务阶段时间 | `created_at``started_at``finished_at` 或等价独立字段 | 入队、领取进入执行、确定结果落库分别记录;unknown 不伪造确定结果完成时间,单一 updated 不能代替全部时间 |
| 原结果与取消 | 原不确定结果、已有诊断信息、pending 取消原因 | unknown 只读保留;pending 按状态条件取消,不新增人工核定结论、说明或时间字段 |
| 配置基线 | 规则及作品选择的持久化版本或规范化内容摘要 | 保存与入队时校验;版本变化只提示重确认,不静默改任务快照 |
| 同步状态 | 按账号和数据类型区分基线完成、游标/覆盖范围、最近成功及本次结果 | 实时缓存写入不能把历史全量标记为完成,失败不覆盖最近成功事实 |
| 删除进度 | 操作类型、受管对象、待完成步骤及异常 | 已持久化意图后才能清目录;不保存凭据,不自动重试破坏性步骤 |
迁移在没有 worker 时执行,保留单实例约束和数据库版本;需要备份时用 SQLite 一致性备份,不直接复制运行中的 WAL 主文件。新增时间字段允许旧记录为空并显示“未知”,不得用最后更新时间伪造。迁移失败不启动业务;兼容旧库读取并以离线迁移测试验证。已有库若带历史人工核定字段,仅兼容保留旧数据,不要求删除字段或新增核定写入流程。
### 9.2 同步完整性与分页
- 每个大号的通知、作品分别维护同步状态:未建基线、同步中、完整、部分/截断、失败;同时保留最近成功时间及已提交覆盖范围。
- “完整”仅表示到达本次平台接口可返回范围的正常结束,不承诺平台已删除或接口不可见的全部历史。
- 未建完整基线时不能因命中实时缓存或任意已知 ID 提前停止。已建基线也只有在接口顺序/连续性已验证时才可使用增量停止点;作品置顶、重复页不得造成漏项。
- 每页数据与对应检查点在同一事务提交;失败可保留已提交页,但完整标记只能在确认正常结束且所有数据落库后更新。游标不能领先于数据。
- 重复游标、页数上限、账号身份失效、无效响应或用户取消均不得记录为完整成功;提供从最新页完整补齐的保守路径,不强依赖失效游标续传。
- 只读同步不创建任务、不标记已读;UI 的分页条数及安全上限不得被标作平台总量。
### 9.3 冷却与时间口径
- 持久化时间统一使用 UTC 时间戳,展示时转换为本地时间;运行中的等待/截止时长使用单调时钟。
- 同一原大号组和目标 UID 共用冷却;默认 4 小时,从成功持久化领取并即将发送该通知批次时开始,批内两个动作不能重复重置。保存已生效的截止时间,配置变更不能缩短它。
- 重启从持久化期限恢复;unknown 继续保留既有去重/占用保护,不因冷却到期、只读查看、重启、删除或账号恢复而解除,不自动重发、不重置 pending、不改派,也不通过人工结论改写原领取时间或任务状态。
- 既有保护可能使同组同目标后续事件持续等待或跳过;移除人工操作不表示自动放行。本次不设计自动判定、补偿或解除保护策略,不能把它描述为等待用户完成核定的操作流程。
- 检测到时钟回拨、异常负间隔、事件/领取时间晚于当前时间或运行中墙钟跳变时保守暂停相关领取并提示核验,不用负数截断为零而直接放行;正常位于未来的冷却截止时间不属于异常。纯本地时间无法证明跨重启的大幅前跳不是正常流逝;本版不声称具有可信远端时钟或绝对跨重启防篡改能力。
### 9.4 账本失败与副作用边界
1. 领取前事务重查组就绪、身份/归属、规则开关、配额、冷却和 task 状态;成功提交运行状态及必要保护记录后才能发送关注/私信。写入失败则无外部动作。
2. 关注/私信各自持久化结果,某个确定失败不取消同批另一个动作。网络超时、确认缺失或连接中断不能直接当作确定失败。
3. 动作已发出但结果写入失败时,立即阻止继续领取并显示账本异常;保留原 running/不确定事实,待存储恢复后按恢复流程转 unknown。不得自动重放动作来“修复”账本。
4. 无法确定故障范围时暂停所有领取;只有明确账号局部问题才限于该账号。数据库恢复后仍需重新核验并显式启动,不自动解除暂停。
5. 普通诊断日志失败可降级,任务账本失败必须禁止新业务动作。日志、缓存清理与任务去重/不确定结果记录分开管理,不以静默删除历史来腾空间。
## 10. 操作安全与异常处理
- 每个账号使用独立 user-data-dir、独立浏览器实例和独立 CDP 端口。
- CDP 只允许 loopback 连接;不使用第一个标签页代替身份选择。
- 每次登录恢复、监听安装和写操作前核验实际 UID。
- 页面接口或 SDK 结构变化时暂停对应能力并显示错误,不绕过身份检查。
- 关注和私信超时不直接判定为失败;无法确认时为 unknown。
- 程序重启时在任何 worker 启动前把遗留 running 转为 unknown,不自动重新执行;恢复上次选择不等于启动业务。
- 停止优先关闭领取入口并在总预算内收尾;长同步、登录等待、UI 禁用都不能挡住停止信号。
- unknown 的只读查询独立于活动账号树,不提供人工核定或改结果操作;删除/转移/恢复不清空原身份、去重、冷却和历史来源。
- 领取状态未成功落库不得发送;结果落库失败不得继续消费或自动重试;删除目录必须先记录意图并支持人工重试部分失败。
- 归属切换、删除小号与任务领取必须由数据库事务和运行状态共同约束,不能只依赖 UI 隐藏按钮。
- 不通过多账号切换规避平台限制;关注、私信只在用户授权和平台规则允许的场景使用。
## 11. 实施拆分
### 第零阶段:安全与数据契约先行
- [ ] 保持启动前恢复及大号就绪屏障,增加启停防重入、运行代次和逐账号结果。
- [ ] 将长同步移出串行命令等待路径,保证停止优先、快照更新及 60 秒总收尾预算。
- [ ] 补任务阶段时间、同步完整性、配置基线及删除意图的最小持久化迁移,旧数据不伪造时间。
- [ ] 明确规则即时限制与任务快照,完成 pending 取消和恢复积压确认。
- [ ] 补删除账号后的 unknown 只读查询、同 UID 恢复原记录及删除部分失败处理;不暴露人工核定业务命令。
- [ ] 用假 session、临时 SQLite 验证领取前/结果后写失败,不允许真实写操作参与回归。
### 第一阶段:账号树和详情框架
- [ ] 重排 `src/accounts_app.py` 主窗口布局。
- [ ] 左侧树显示大号、小号、未分配小号和三类状态。
- [ ] 移除账号专属底部按钮,增加角色感知右键菜单。
- [ ] 保留顶部全局按钮和大号批量启动复选框。
- [ ] 选中账号后刷新右侧摘要;按 account ID/request ID 隔离回包,选择、启动勾选与 dirty 草稿互不覆盖。
### 第二阶段:大号详情
- [ ] 右侧加入“历史事件 / 作品列表”两个 TAB。
- [ ] 将完整基线、同步范围、过滤、勾选及带配置基线的二次确认接入历史 TAB。
- [ ] 将作品 CARD、封面缓存、刷新间隔和作品范围保存接入作品 TAB。
- [ ] 保持历史任务低优先级、实时任务高优先级。
### 第三阶段:小号详情和全局日志
- [ ] 小号详情显示当前任务、历史任务、pending 取消及只读不确定结果;复用任务表提供含已删除小号的全局/原组查询入口。
- [ ] 底部日志固定显示最近 2000 条并支持自动滚动。
- [ ] 显示日志目录错误和打开日志目录入口。
- [ ] 账号树状态、详情计数和日志增量更新不得阻塞监听线程。
### 第四阶段:回归和交付
- [ ] 验证菜单按角色裁剪,历史事件、作品监控、执行记录和小号组启停不在小号右键重复出现,非法操作在后端仍会拒绝。
- [ ] 验证大号、小号、未分配小号和多组账号互不串组。
- [ ] 验证历史事件默认不勾选,未二次确认不创建任务。
- [ ] 验证作品 CARD 选择、封面缓存和重启后的 SQLite 数据。
- [ ] 验证实时/历史优先级、冷却、unknown 和停止等待语义。
- [ ] 完成 §12 交错操作、迁移、分页及故障注入矩阵,再在 Windows x64 原生构建后进行 GUI 离线冒烟和人工安装验收。
## 12. 验收清单
- [ ] 添加大号和小号后,账号树层级、归属和状态清晰可见。
- [ ] 大号复选框可批量启动;大号登录核验成功后自动启动已绑定且未手动停止的小号。
- [ ] 右键菜单只显示当前账号角色支持的生命周期、归属和配置操作;小号可启动/停止自身任务但不能启动或停止所属组。
- [ ] 小号手动停止标记在 SQLite、应用重启和大号再次登录后保持,菜单与详情显示明确状态。
- [ ] 大号右侧只有历史事件和作品列表两个主要 TAB,相关入口不再在右键重复提供。
- [ ] 小号右侧能区分当前任务与历史任务;unknown 只读展示,无人工核定按钮、结论提交或改状态操作。
- [ ] 历史事件同步是只读的,默认不勾选,必须二次确认后才创建任务。
- [ ] 作品列表以 CARD 显示,封面优先使用本地缓存,作品监控范围可保存。
- [ ] 底部日志持续显示推送、分配、执行、结果和异常,界面最多保留 2000 条。
- [ ] 同一通知不会重复派发;同一小号一次只处理一个通知批次。
- [ ] 关注和私信同时开启时并行执行、结果独立保存。
- [ ] 登录失效、身份不匹配、超时和 unknown 均不会触发盲目重试或自动登录。
- [ ] 停止保留浏览器和登录目录;删除登录数据、删除小号是独立且有确认的操作。
- [ ] 真实浏览器操作前完成 Windows 离线测试;真实关注、私信和标记已读不由自动化验收代替用户确认。
### 12.1 评审补充验收矩阵
| 场景 | 必须验证的结果 | 最小验证方式 |
| --- | --- | --- |
| 预置 running 后重启、恢复上次选择 | worker 出现前已转 unknown;只恢复勾选,无网络写动作 | 临时 SQLite + 假 session |
| 大号核验失败、部分小号失败 | 大号失败整组不领取;小号失败不改派且显示部分异常 | 可控身份响应 |
| 启动中停止、迟到连接成功 | 旧运行代次不能重新启动 worker | 可控 await |
| 慢历史/作品同步及登录等待时停止 | 接受停止后 1 秒内关闭领取入口,快照持续更新,不等同步结束 | 假分页/登录等待 + UI 冒烟 |
| 在途请求超过 60 秒预算 | 有限收尾;不确定结果为 unknown 或明确账本错误,不重发 | 假执行器/时钟 |
| 同一小号收到多条通知 | 只执行一个通知批次;批内两个动作并行且结果独立 | 假执行器 |
| 删除/移动 unknown 小号并重启 | 原组仍可只读查看,来源不改写,不要求旧账号活动;查看不改状态 | SQLite + UI |
| 查看 unknown 及尝试人工改结果 | 无人工核定按钮/快捷键/业务命令;unknown 不自动改成功/失败、重置或重发 | UI + 命令接口检查 |
| 删除后再次绑定同 UID | 显式恢复原 ID 或取消,不产生第二个身份、不恢复旧任务 | 临时 SQLite |
| 旧 pending、规则编辑、配额收紧 | 快照不变,当前安全限制生效,取消仅影响确认的 pending | 引擎/存储回归 |
| 历史预览后修改规则/作品范围、重复提交 | 配置变化需重新确认;重复提交不重复入队 | 假缓存 + SQLite |
| 一条实时缓存后首次历史同步、分页失败/上限 | 更早页不遗漏;失败/截断不显示完整成功 | 假分页接口 |
| 置顶作品、重复页、游标不推进 | 不误用单个已知 ID 停止;可完整补齐 | 假作品接口 |
| A 同步后切 B、编辑草稿时收快照 | 不串账号、不丢草稿;筛选在分页限制前完成 | UI 冒烟 |
| 旧库迁移、异常任务查询、冷却重启/时钟回拨 | 缺失时间显示未知;查询不改阶段时间/状态;检测异常保守暂停 | 临时旧库 + 假时钟 |
| 领取前/动作后 SQLite 写失败 | 前者无动作;后者停领且不盲目重试 | 故障注入 |
| profile 清理成功但数据库提交失败、进程中断 | 删除意图保留、禁止启动;显式重试不伤其它目录、不自动登录 | 临时目录 + 故障注入 |
以上均为待验证项,不因文档合并打勾。优先复用现有测试、临时库和假执行器,不增加测试框架;本地通过后再进行 Windows GUI/安装验收,不用真实关注、私信或标记已读验证安全分支。
## 13. 明确不做
- 不在界面中承诺单机支持的固定账号数量或自动容量评估。
- 不做分布式队列、远程日志服务、Windows Service 或多机调度。
- 不做自动登录、验证码处理、风控绕过或 Cookie 跨机器迁移。
- 不把浏览器页面点击作为最终业务执行方案;业务继续通过显式账号连接和页面内接口/SDK 完成。
- 不将“缓存有数据”“详情已入库”“任务已分配”表述为关注或私信已经成功。
- 不为上述约束新增通用状态机、调度框架、独立规则版本服务或自动 TTL;优先使用已有 asyncio、SQLite、账号标志和配置摘要。