Skip to content

Latest commit

 

History

History
461 lines (316 loc) · 17.7 KB

File metadata and controls

461 lines (316 loc) · 17.7 KB

LearnFlow详细设计Spec

文档版本:v1.0 创建日期:2026-04-18 文档状态:Draft 适用范围:LearnFlow本地MVP

1. 文档目标与Spec原则

本文件用于把原始需求文档转成可执行、可验收、可追踪的工程规范。本文采用四条Spec原则。第一条是边界清晰,每个能力都声明范围和排除项。第二条是行为可测试,每条关键需求都能落到输入、处理、输出。第三条是约束可量化,性能、稳定性、可用性都有明确指标。第四条是变更可追踪,需求编号、接口、数据结构、验收标准互相可映射。

2. 产品定义

LearnFlow是Mac优先的本地学习任务管理应用。核心问题是用户保存了很多文章,但很少完成阅读。产品通过任务化、截止时间、优先级和提醒机制,把保存动作转成可执行学习流程。

MVP只服务单机单用户,不做云同步,不做账号系统,不做团队协作。MVP目标是让用户从添加链接到标记完成形成闭环,并且闭环可重复。

3. 目标与成功指标

3.1 业务目标

目标1:把收藏内容转成学习任务,且创建成本低。

目标2:提升已保存内容的再打开率和完成率。

目标3:确保用户数据可导出、可迁移、可备份。

3.2 量化指标

M1任务创建成功率不低于99.0%。

M2提醒触达成功率不低于98.0%。

M3用户在7天内至少完成1篇文章的比例不低于35%。

M4从添加URL到任务落库的P95耗时不超过1200ms。网页抓取失败时走兜底流程,兜底落库P95不超过500ms。

M5应用异常退出后重启,任务数据不丢失,最近一次成功事务可恢复。

4. 范围定义

4.1 In Scope

MVP包含以下能力。

  1. 菜单栏常驻入口。
  2. 主窗口任务列表与详情阅读。
  3. 手动添加URL。
  4. 自动提取标题与网页正文,失败可兜底。
  5. 本地SQLite存储。
  6. 任务状态、优先级、截止时间管理。
  7. 本地通知提醒。
  8. 搜索与筛选。
  9. 数据导出为Markdown、JSON、CSV。

4.2 Out of Scope

MVP不包含以下能力。

  1. 微信、邮件、浏览器扩展接入。
  2. 移动端与多端同步。
  3. 云端账号与权限体系。
  4. AI摘要、AI问答、复杂知识库。
  5. 复杂统计报表与团队协作。

5. 角色与场景

系统当前只有一种角色,单用户本机使用者。用户主要场景有五类。第一类是快速捕获,用户看到有价值链接后几秒内完成保存。第二类是任务排程,用户为待学内容设置优先级和截止时间。第三类是被动提醒,系统在关键时点拉回用户。第四类是沉浸阅读,用户在应用内完成阅读并标记状态。第五类是数据迁移,用户随时导出全部学习记录。

6. 领域模型

核心实体包括Item、Tag、ReminderEvent、ActivityEvent、Settings。

Item代表一篇文章及其学习任务。Tag用于轻量分类。ReminderEvent用于提醒调度与去重。ActivityEvent用于行为审计和后续统计。Settings用于本地偏好设置。

Item是主实体。Tag和ReminderEvent都从属于Item。ActivityEvent可关联Item,也可记录系统级事件。

7. 用例定义

用例ID 名称 前置条件 主成功路径 失败路径
UC-01 添加链接并创建任务 应用已启动 输入URL并保存,系统写入Item并返回详情 URL不合法,返回校验错误
UC-02 自动抓取正文 UC-01提交后 系统抓取页面并提取标题与正文 抓取失败,保留URL与标题并标记content_status=failed
UC-03 设置截止和优先级 Item已存在 更新due_atpriority并持久化 时间非法或状态冲突,更新失败
UC-04 到时提醒 Item存在有效提醒时间 触发本地通知并记录reminded_at 通知插件失败,记录重试事件
UC-05 阅读并标记完成 Item状态非done 打开阅读页并点击完成,状态切换为done 写库失败,提示重试
UC-06 搜索和筛选 至少有1条Item 按标题、URL、状态、优先级、日期过滤 条件无结果,返回空列表
UC-07 导出数据 本地数据库可读 选择格式并导出文件 磁盘写入失败,返回导出错误

8. 功能需求

8.1 需求列表

需求ID 描述 优先级 验收方式
FR-01 系统必须支持手动输入URL创建任务 P0 接口测试+UI测试
FR-02 系统必须校验URL格式并阻断非法输入 P0 单元测试
FR-03 系统必须保存任务基础字段与时间字段 P0 数据库集成测试
FR-04 系统应尝试抓取标题与正文文本 P1 集成测试
FR-05 抓取失败时系统必须保留可用任务 P0 异常流程测试
FR-06 系统必须支持四种状态unread/reading/done/archived P0 状态机测试
FR-07 系统必须支持三档优先级high/medium/low P0 单元测试
FR-08 系统必须支持截止时间与提醒时间设置 P0 集成测试
FR-09 系统必须在提醒触发后记录触达时间 P0 调度测试
FR-10 系统必须支持任务列表排序与筛选 P0 UI自动化测试
FR-11 系统必须支持阅读页并记录阅读进度 P1 UI测试
FR-12 系统必须支持标记完成并停止后续提醒 P0 状态+调度联测
FR-13 系统必须支持标签增删与筛选 P1 集成测试
FR-14 系统必须支持数据导出为Markdown、JSON、CSV P1 文件对比测试
FR-15 系统必须支持关键词搜索标题与URL P1 查询测试

8.2 状态机约束

允许迁移如下。

unread -> reading

unread -> done

unread -> archived

reading -> done

reading -> archived

done -> archived

archived -> unread

以下迁移禁止。

done -> reading

archived -> done

禁止迁移收到请求时,接口返回409_CONFLICT_STATUS_TRANSITION

9. 交互流程规范

9.1 添加链接流程

用户在菜单栏或主窗口输入URL并点击保存。前端先做同步校验,校验通过后调用add_item。后端在一个事务内写入基础Item,随后异步触发抓取任务。抓取成功则更新内容字段,抓取失败则把content_status置为failed,并写入活动事件。

9.2 提醒流程

提醒分成单任务提醒和默认提醒两种。若用户显式设置remind_at,系统按该时间触发。若只设置due_at,系统自动生成同一天09:00提醒。若两者都缺失,不自动提醒。调度器每60秒扫描一次待触发事件,并且在应用启动时执行一次补偿扫描。

9.3 阅读完成流程

用户打开阅读页后,滚动行为按区间更新reading_progress。点击完成时系统把状态改为done并写入completed_at。一旦状态变为donearchived,未触发提醒事件全部置为canceled

10. 数据设计

10.1 数据库约束原则

所有时间字段采用ISO8601字符串并保存本地时区偏移。所有主键使用UUIDv7字符串。关键查询字段必须建索引。状态与优先级字段使用CHECK约束保证取值合法。

10.2 DDL设计

CREATE TABLE items (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  url TEXT NOT NULL,
  url_hash TEXT NOT NULL,
  source TEXT,
  author TEXT,
  published_at TEXT,
  content_text TEXT,
  content_html TEXT,
  cover_image TEXT,
  status TEXT NOT NULL DEFAULT 'unread' CHECK (status IN ('unread','reading','done','archived')),
  priority TEXT NOT NULL DEFAULT 'medium' CHECK (priority IN ('high','medium','low')),
  due_at TEXT,
  remind_at TEXT,
  reminded_at TEXT,
  reading_progress REAL NOT NULL DEFAULT 0 CHECK (reading_progress >= 0 AND reading_progress <= 1),
  content_status TEXT NOT NULL DEFAULT 'pending' CHECK (content_status IN ('pending','ready','failed')),
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL,
  completed_at TEXT,
  archived_at TEXT
);

CREATE UNIQUE INDEX idx_items_url_hash_active
ON items(url_hash)
WHERE status != 'archived';

CREATE INDEX idx_items_status_due_priority
ON items(status, due_at, priority, created_at DESC);

CREATE INDEX idx_items_remind_at
ON items(remind_at)
WHERE reminded_at IS NULL;

CREATE TABLE tags (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL UNIQUE,
  created_at TEXT NOT NULL
);

CREATE TABLE item_tags (
  item_id TEXT NOT NULL,
  tag_id TEXT NOT NULL,
  created_at TEXT NOT NULL,
  PRIMARY KEY (item_id, tag_id),
  FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE,
  FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);

CREATE TABLE reminder_events (
  id TEXT PRIMARY KEY,
  item_id TEXT NOT NULL,
  remind_at TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','triggered','canceled','failed')),
  triggered_at TEXT,
  retry_count INTEGER NOT NULL DEFAULT 0,
  error_message TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL,
  FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE
);

CREATE INDEX idx_reminder_events_due
ON reminder_events(status, remind_at);

CREATE TABLE activity_events (
  id TEXT PRIMARY KEY,
  item_id TEXT,
  event_type TEXT NOT NULL,
  payload_json TEXT,
  created_at TEXT NOT NULL,
  FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE SET NULL
);

CREATE INDEX idx_activity_item_created
ON activity_events(item_id, created_at DESC);

CREATE TABLE settings (
  key TEXT PRIMARY KEY,
  value TEXT NOT NULL,
  updated_at TEXT NOT NULL
);

10.3 重复URL策略

系统对标准化URL计算url_hash。若存在未归档任务拥有同一url_hash,默认返回该任务并提示已存在,不重复创建。用户明确选择重复创建时,系统在URL后追加参数lf_dup=<timestamp>参与哈希,保留独立任务。

11. 接口设计

11.1 Tauri命令清单

命令 输入 输出 错误码
add_item url,title?,priority?,due_at?,remind_at? ItemDTO 400_INVALID_URL,409_DUPLICATED_ITEM,500_DB_ERROR
get_items filter?,sort? ItemListDTO 500_DB_ERROR
get_item id ItemDTO 404_ITEM_NOT_FOUND
update_item id,input ItemDTO 400_BAD_INPUT,409_CONFLICT_STATUS_TRANSITION
delete_item id DeleteResultDTO 404_ITEM_NOT_FOUND
archive_item id ItemDTO 404_ITEM_NOT_FOUND
mark_item_done id ItemDTO 409_CONFLICT_STATUS_TRANSITION
fetch_article url ArticleContentDTO 422_PARSE_FAILED,503_FETCH_FAILED
set_reminder id,remind_at ReminderDTO 400_BAD_TIME,404_ITEM_NOT_FOUND
export_items format,path ExportResultDTO 400_BAD_FORMAT,507_EXPORT_WRITE_FAILED

11.2 DTO定义

export type ItemStatus = 'unread' | 'reading' | 'done' | 'archived';
export type ItemPriority = 'high' | 'medium' | 'low';

export interface ItemDTO {
  id: string;
  title: string;
  url: string;
  source?: string;
  author?: string;
  published_at?: string;
  content_text?: string;
  content_html?: string;
  content_status: 'pending' | 'ready' | 'failed';
  status: ItemStatus;
  priority: ItemPriority;
  due_at?: string;
  remind_at?: string;
  reminded_at?: string;
  reading_progress: number;
  created_at: string;
  updated_at: string;
  completed_at?: string;
  archived_at?: string;
  tags: string[];
}

export interface ItemFilterDTO {
  keyword?: string;
  statuses?: ItemStatus[];
  priorities?: ItemPriority[];
  due_from?: string;
  due_to?: string;
  tags?: string[];
  only_overdue?: boolean;
}

11.3 错误返回规范

统一返回结构。

{
  "code": "409_CONFLICT_STATUS_TRANSITION",
  "message": "状态迁移不允许",
  "request_id": "a8f6c5c1-5f31-4c90-84f8-59dbab6d48f1",
  "retryable": false
}

12. 模块设计

12.1 前端模块

TaskList负责展示、筛选、排序和批量操作入口。

ArticleReader负责正文展示、进度更新和完成动作。

AddLinkDialog负责输入校验和提交流程。

FilterBar负责条件组合与快速筛选。

SettingsPage负责提醒、默认优先级和导出配置。

状态管理采用Zustand,分成itemStoresettingsStore两个仓库。网络层通过tauriCommands.ts统一调用。

12.2 Rust后端模块

db.rs负责连接池、迁移、事务边界。

commands.rs负责参数校验和命令路由。

article_fetcher.rs负责下载、正文提取、内容清洗。

reminders.rs负责提醒事件调度和通知触发。

export.rs负责多格式导出。

tray.rs负责菜单栏交互与窗口控制。

13. 网页解析设计

抓取流程分四步。第一步获取原始HTML,超时上限8秒。第二步提取<title>和站点信息。第三步执行正文抽取,优先Readability规则。第四步清洗脚本和样式标签,生成content_textcontent_html

抓取失败分级处理。网络失败记为503_FETCH_FAILED。解析失败记为422_PARSE_FAILED。任意失败都不阻断任务创建。系统至少保留URL和可得标题。

14. 提醒调度设计

调度器采用单进程内循环,每60秒执行一次。每轮读取reminder_eventsstatus=pendingremind_at<=now的记录,按时间升序触发通知。触发成功写triggeredtriggered_at。触发失败写failed并增加retry_count。重试上限3次,指数回退间隔为1分钟、3分钟、9分钟。

应用启动时执行一次补偿任务,处理离线期间错过的提醒。若提醒对应Item状态已经是donearchived,直接把事件改为canceled

15. 搜索排序规则

默认排序使用四级权重。第一层按是否逾期降序。第二层按due_at升序。第三层按优先级high > medium > low。第四层按created_at降序。

关键词搜索首版只覆盖标题和URL,使用不区分大小写匹配。全文搜索不进入MVP。

16. 导出设计

导出支持三种格式。Markdown用于阅读与归档。JSON用于程序化迁移。CSV用于表格分析。

导出文件命名规则为learnflow_export_YYYYMMDD_HHMMSS.<ext>。导出范围支持全部数据和筛选后数据两种。导出内容必须包含任务元数据与标签,正文字段在用户勾选后写入,默认包含正文。

17. 非功能需求

编号 项目 目标
NFR-01 启动时长 冷启动到可操作界面P95不超过2秒
NFR-02 列表性能 5000条任务下滚动FPS不低于50
NFR-03 存储可靠性 关键写操作使用事务,崩溃后数据库完整
NFR-04 可观测性 关键路径写入结构化日志并带request_id
NFR-05 隐私安全 全部数据本地存储,默认不出网同步
NFR-06 可维护性 后端模块单元测试覆盖率不低于70%

18. 安全与隐私

应用不上传用户正文到云端。抓取行为仅在用户主动添加URL后发生。导出文件写入前弹出目标路径确认。删除操作需要二次确认。提供本地数据库路径展示,方便用户备份。

19. 测试策略

测试分四层执行。

第一层是单元测试,覆盖URL校验、状态迁移、排序规则、提醒计算。

第二层是数据库集成测试,覆盖迁移脚本、索引、事务回滚。

第三层是命令接口测试,覆盖主要命令的成功与异常分支。

第四层是端到端测试,覆盖添加、提醒、阅读完成、导出主流程。

关键回归用例如下。

  1. 添加非法URL应直接失败。
  2. 解析失败仍可创建任务。
  3. 已完成任务不会再次提醒。
  4. 状态迁移违规返回409。
  5. 导出三种格式字段一致。

20. 里程碑与交付

M1 项目骨架与数据层

交付项包括Tauri2工程、SQLite迁移、基础命令可调用、任务列表可渲染。完成标准是可本地运行并完成最小增删改查。

M2 任务管理闭环

交付项包括添加链接、状态管理、优先级、截止时间、排序筛选。完成标准是UC-01、UC-03、UC-06通过。

M3 网页解析与阅读

交付项包括正文抓取、失败兜底、阅读页展示、进度记录。完成标准是UC-02、UC-05通过。

M4 提醒系统

交付项包括提醒创建、调度循环、通知点击回跳、补偿扫描。完成标准是UC-04通过。

M5 导出与验收

交付项包括Markdown、JSON、CSV导出和验收测试报告。完成标准是全部P0需求通过,且NFR核心指标达标。

21. 验收矩阵

验收ID 对应需求 用例 通过标准
AC-01 FR-01 FR-02 FR-03 UC-01 输入合法URL后任务成功入库并可查询
AC-02 FR-04 FR-05 UC-02 抓取成功写正文,失败不阻断任务创建
AC-03 FR-08 FR-09 UC-04 到时通知触发并记录triggered_at
AC-04 FR-06 FR-12 UC-05 标记完成后状态正确且提醒取消
AC-05 FR-10 FR-15 UC-06 筛选排序结果与规则一致
AC-06 FR-14 UC-07 三种格式导出成功且字段完整

22. 风险与应对

风险1是网页解析稳定性不足。应对策略是分级失败兜底和可重试抓取。

风险2是需求膨胀拖慢MVP。应对策略是只接受能直接提升读完率的新增需求。

风险3是提醒漏触达。应对策略是启动补偿扫描和失败重试。

风险4是误删数据。应对策略是二次确认、导出入口前置、删除行为审计。

23. 未决策事项

当前仍有四个待确认点。第一,默认是否允许重复任务。第二,阅读进度是否需要手动校正。第三,导出是否默认包含正文HTML。第四,菜单栏窗口是否支持直接编辑任务。

若以上事项在实现前未明确,按本Spec默认值执行并在变更日志记录。

24. 变更控制

任何需求变更都需要补充三项内容。第一项是影响范围。第二项是是否影响P0。第三项是是否影响里程碑时间。变更审批通过后更新文档版本号并记录日期。