Define pomodoro, milestone badges, goal notifications, and knowledge injection logging for the next release. Co-authored-by: Cursor <cursoragent@cursor.com>
18 KiB
笔临 P5.3 + P6.1 写作目标补全 + 知识注入历史 设计规格
版本:1.0
日期:2026-07-07
范围:P5.3(§8 补全)番茄钟、连更里程碑徽章、达标通知;P6.1 知识库条目注入历史与反向链接
前置:P5.2 写作日志 + AI 知识抽取已交付(v0.8.0,a39e06f);P6 AI 知识上下文(v0.7.0)
参考:design/readme.md v1.1 §8 / §5.5.7、docs/superpowers/specs/2026-07-07-bilin-p52-writing-logs-extraction-design.md、docs/superpowers/specs/2026-07-07-bilin-p6-ai-context-design.md
目标版本:v0.9.0
1. 背景与目标
1.1 阶段定位
v0.8.0 已交付 writing_logs 日更追踪、驾驶舱热力图/连更、状态栏日更进度,以及 AI 章节知识抽取与 P6 注入链路。但 design/readme.md §8 仍缺 番茄钟、7/30/100 天连更里程碑徽章 与 达标/完成通知;P6 spec 延后的 注入历史 / 反向链接 尚未落地,作者无法在知识库条目上查看「这条知识曾在哪些写作流中被 AI 使用」。
本阶段(v0.9.0)双线交付:
- P5.3:补齐 §8 剩余能力,强化日更作者的正反馈与专注工具
- P6.1:在知识库条目上记录并展示写作流(交互/自动/向导)上下文确认时的注入历史
1.2 已确认决策(Brainstorming 2026-07-07)
| 维度 | 决策 |
|---|---|
| 交付版本 | v0.9.0 单版交付 P5.3 + P6.1 |
| 架构方案 | 主进程服务分层:PomodoroService + AchievementService + GoalNotificationService + KnowledgeInjectionService |
| 统计范围 | 当前书籍(与 P5.2 一致:连更、里程碑、番茄字数增量、成就均按 bookId) |
| 通知 | Toast + 可选 Electron 系统通知;设置页可关闭系统通知与目标通知 |
| 番茄钟 UI | 状态栏紧凑控件(▶/⏸ + 剩余时间);驾驶舱展示今日番茄完成次数 |
| 番茄时长 | 设置页 15 / 25 / 45 分钟 三档,默认 25 |
| 里程碑 UI | 庆祝 + 持久展示:达成时 Toast/系统通知;驾驶舱「成就区」展示已解锁 7/30/100 天徽章 |
| P6.1 范围 | 仅知识库条目(不含设定条目 AI 注入历史) |
| P6.1 记录场景 | 交互 / 自动 / 向导 三模式 confirmContext 且 knowledgeIds 非空;不含 AI 对话助手 |
| 注入历史 UI | 列表最近 3 条预览 + 编辑对话框完整时间线 |
| 切换书籍(番茄进行中) | 自动取消番茄并 Toast 提示 |
1.3 验收标准
用户能完成:
- 在状态栏启动 15/25/45 分钟番茄钟,暂停/取消/完成后看到剩余时间变化;完成时 Toast 显示本次新增字数
enableSystemNotifications开启时,番茄完成与里程碑解锁可收到 系统通知(权限被拒则降级 Toast)dailyWordGoal > 0且当日首次达标时收到 Toast(及可选系统通知);同一自然日不重复提醒- 连更达到 7 / 30 / 100 天(基于 P5.2
streakDays)时:庆祝通知 + 驾驶舱成就区永久展示对应徽章;每档仅庆祝一次 - 交互/自动/向导 确认知识上下文后,被注入的
approved知识条目在 KnowledgePanel 卡片显示最近 3 条注入记录 - 打开 KnowledgeEditorDialog 可查看该条目完整注入历史(时间、模式、关联章节)
- 注入记录失败 不阻断 写作流确认步骤
1.4 本规格不实现(明确排除)
| 项 | 归属 |
|---|---|
| 预计完本、写作速度仪表盘、时段热力图 | §9 延后 |
| 设定条目「被 AI 注入的轮次」 | P6.2 |
| AI 对话助手注入历史 | 本阶段排除(用户确认 C) |
| 番茄钟自定义任意分钟数、休息间隔、番茄统计全屏页 | 后续 |
| 里程碑 365 天等扩展档位 | 后续 |
| 语义 embedding、注入内容 diff | 后续 |
| 导入导出、章节模板 | P7 / §10 |
2. 架构
2.1 进程模型
┌────────────────────────────────────────────────────────────────────┐
│ 主进程 │
│ · PomodoroService(倒计时、开始/暂停/取消、完成字数差分) │
│ · AchievementService(7/30/100 里程碑解锁检测与持久化) │
│ · GoalNotificationService(Toast IPC + Notification,受设置控制) │
│ · WritingLogService(已有,番茄快照/差分、streakDays) │
│ · KnowledgeInjectionService(写入/查询 injection logs) │
│ · CockpitService 扩展(成就区、pomodoroTodayCount) │
│ · interactive/auto/wizard confirmContext 挂钩 injection 记录 │
└──────────────────────────────┬─────────────────────────────────────┘
│ IPC
┌──────────────────────────────▼─────────────────────────────────────┐
│ 渲染进程 │
│ · EditorLayout 状态栏:番茄控件 + 日更进度(已有) │
│ · CockpitModal:成就区徽章 + 今日番茄次数 │
│ · SettingsPage:番茄时长、通知开关 │
│ · KnowledgePanel:注入历史最近 3 条预览 │
│ · KnowledgeEditorDialog:完整注入历史列表 │
└────────────────────────────────────────────────────────────────────┘
2.2 模块边界
| 模块 | 职责 | 依赖 |
|---|---|---|
PomodoroService |
单实例番茄状态机;完成时计算 wordDelta |
WritingLogService, GlobalSettings |
AchievementService |
读 streakDays,写 writing_milestones,触发庆祝 |
WritingLogService, GoalNotificationService |
GoalNotificationService |
统一发送 goal-met / milestone / pomodoro 通知 | GlobalSettings, Notification(Electron) |
KnowledgeInjectionService |
batch 写入、按 entry 查询、recent N | 每书 KnowledgeInjectionRepository |
CockpitService |
聚合 achievements[]、pomodoroTodayCount |
上述服务 |
原则:
- 番茄钟状态在主进程,保证最小化/失焦时计时准确、完成时可发系统通知
- 注入记录与 confirmContext 同事务意图:build 成功即写 log;写 log 失败仅
console.error,不抛给 IPC - 成就不回溯:仅在未来
streakDays首次跨档时解锁
3. 数据模型
3.1 全局 userData:扩展 writing_logs.sqlite
在现有 writing_logs 表基础上 同库追加(WritingLogRepository.migrate() 扩展):
CREATE TABLE IF NOT EXISTS writing_milestones (
book_id TEXT NOT NULL,
milestone TEXT NOT NULL, -- 'streak_7' | 'streak_30' | 'streak_100'
unlocked_at TEXT NOT NULL DEFAULT (datetime('now')),
PRIMARY KEY (book_id, milestone)
);
CREATE TABLE IF NOT EXISTS pomodoro_daily (
date TEXT NOT NULL,
book_id TEXT NOT NULL,
completed_count INTEGER NOT NULL DEFAULT 0,
total_words INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (date, book_id)
);
pomodoro_daily 在每次番茄 完成 时 completed_count += 1,total_words += wordDelta。
3.2 每书 schema v8
新文件 schema-v8.sql:
CREATE TABLE IF NOT EXISTS knowledge_injection_logs (
id TEXT PRIMARY KEY,
knowledge_entry_id TEXT NOT NULL,
flow_mode TEXT NOT NULL, -- 'interactive' | 'auto' | 'wizard'
flow_id TEXT NOT NULL,
chapter_id TEXT,
injected_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (knowledge_entry_id) REFERENCES knowledge_entries(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_injection_entry_time
ON knowledge_injection_logs (knowledge_entry_id, injected_at DESC);
migrate.ts:CURRENT_VERSION = 8;v7→v8 仅 exec(schemaV8)。
3.3 TypeScript 类型(src/shared/types.ts)
export type PomodoroDuration = 15 | 25 | 45
export type WritingMilestone = 'streak_7' | 'streak_30' | 'streak_100'
export type InjectionFlowMode = 'interactive' | 'auto' | 'wizard'
export interface PomodoroState {
running: boolean
paused: boolean
remainingSec: number
bookId: string | null
startedAt: string | null
}
export interface WritingAchievement {
milestone: WritingMilestone
unlockedAt: string
}
export interface KnowledgeInjectionLog {
id: string
knowledgeEntryId: string
flowMode: InjectionFlowMode
flowId: string
chapterId?: string
injectedAt: string
}
export interface CockpitSummary {
// 已有字段…
achievements?: WritingAchievement[]
pomodoroTodayCount?: number
}
扩展 GlobalSettings:
pomodoroDurationMinutes?: PomodoroDuration // default 25
enableSystemNotifications?: boolean // default false
enableGoalNotifications?: boolean // default true
4. 服务行为
4.1 PomodoroService
- start(bookId):若已有运行中番茄且
bookId不同,先 cancel 再 start;记录wordSnapshot = WritingLogService.getStats(bookId).todayWords - pause / resume / cancel:标准状态机;cancel 清空快照
- tick:主进程
setInterval(1s)递减;remainingSec === 0触发complete() - complete():
wordDelta = max(0, todayWords_now - wordSnapshot)- 更新
pomodoro_daily GoalNotificationService.notifyPomodoroComplete(bookId, wordDelta)- 重置状态
渲染进程每 1s 通过 IPC pomodoro:getState 同步 UI(或由主进程 push POMODORO_TICK 事件,实现时二选一,计划阶段选定 push 以减少轮询)。
4.2 AchievementService
- 在 WritingLogService 写入后 或 Cockpit getSummary 时调用
checkMilestones(bookId):- 读
streakDays(需dailyWordGoal > 0) - 若
streakDays >= 7且 DB 无streak_7→ insert + notify - 同理 30、100
- 读
listAchievements(bookId)→WritingAchievement[]按 milestone 排序
4.3 GoalNotificationService
| 事件 | Toast | 系统通知(enableSystemNotifications) |
|---|---|---|
| 日更首次达标 | ✓(enableGoalNotifications) |
可选 |
| 里程碑解锁 | ✓ | 可选 |
| 番茄完成 | ✓ | 可选 |
Toast 经现有 useAppStore.showToast 模式:主进程 webContents.send(GOAL_NOTIFICATION, payload) 或复用通用 notification IPC。
系统通知权限被拒:catch 并忽略,不抛错。
4.4 KnowledgeInjectionService
挂钩点(均在 buildFlowContextPayload 成功返回之后):
interactive.handler→INTERACTIVE_CONFIRM_CONTEXTauto.handler→AUTO_CONFIRM_CONTEXTwizard.handler→WIZARD_CONFIRM_CONTEXT
recordInjection(bookId, {
knowledgeIds: binding.knowledgeIds,
flowMode: 'interactive' | 'auto' | 'wizard',
flowId,
chapterId?: string // flow 关联章或 registry meta lastChapterId
})
对每个 knowledgeId:校验 entry 存在且 status === 'approved'(防御性;UI 本不应注入 pending)。
查询:
listRecentForEntry(entryId, limit=3)listForEntry(entryId, limit=50)供编辑对话框
5. UI 规格
5.1 状态栏番茄控件
- 位置:
EditorLayout#editor-statusbar,日更进度右侧 - 控件:
data-testid="pomodoro-control" - idle:▶ 按钮,点击 start
- running:⏸ +
MM:SS+ ✕取消 - paused:▶ 继续 + ✕取消
- 无
currentBookId时禁用
5.2 驾驶舱成就区
- 位置:
CockpitModal写作统计区下方 data-testid="cockpit-achievements"- 展示已解锁徽章(7🔥 / 30🔥 / 100🔥 或 i18n 文案);未解锁灰显或隐藏
data-testid="cockpit-pomodoro-today":今日完成番茄次数
5.3 设置页
| 控件 | testid | 说明 |
|---|---|---|
| 番茄时长 | settings-pomodoro-duration |
select: 15/25/45 |
| 系统通知 | settings-system-notifications |
checkbox,默认 false |
| 目标通知 | settings-goal-notifications |
checkbox,默认 true |
5.4 知识库注入历史
KnowledgePanel 列表项:
data-testid="knowledge-injection-preview-{entryId}"- 最多 3 行:
{date} · {flowMode} · {chapterTitle}
KnowledgeEditorDialog:
- 折叠区「注入历史」
data-testid="knowledge-injection-history" - 完整列表,按时间倒序;章节名可点击跳转(调用现有
switchTarget)
6. IPC 通道
POMODORO_START: 'pomodoro:start',
POMODORO_PAUSE: 'pomodoro:pause',
POMODORO_RESUME: 'pomodoro:resume',
POMODORO_CANCEL: 'pomodoro:cancel',
POMODORO_GET_STATE: 'pomodoro:getState',
ACHIEVEMENT_LIST: 'achievement:list',
KNOWLEDGE_LIST_INJECTIONS: 'knowledge:listInjections',
GOAL_NOTIFICATION: 'goal:notification', // main → renderer push
preload / electron-api.d.ts 同步扩展。
7. i18n 键(节选)
"pomodoro.start": "开始番茄钟",
"pomodoro.pause": "暂停",
"pomodoro.cancel": "取消",
"pomodoro.complete": "番茄钟完成!本次写作 {{words}} 字",
"pomodoro.switchedBook": "已切换书籍,番茄钟已取消",
"goal.dailyMet": "今日目标已达成 {{current}} / {{goal}} 字",
"achievement.streak7": "连更 7 天",
"achievement.streak30": "连更 30 天",
"achievement.streak100": "连更 100 天",
"achievement.unlocked": "解锁成就:{{name}}",
"cockpit.achievements": "写作成就",
"cockpit.pomodoroToday": "今日番茄 {{count}} 次",
"knowledge.injectionHistory": "注入历史",
"knowledge.injectionPreview": "最近注入",
"knowledge.injectionEntry": "{{date}} · {{mode}} · {{chapter}}",
"settings.pomodoroDuration": "番茄钟时长(分钟)",
"settings.systemNotifications": "启用系统通知",
"settings.goalNotifications": "启用目标达成提醒"
8. 测试要求
8.1 单元 / 集成
| 用例ID | 场景 | 预期 |
|---|---|---|
| UT-POM-01 | start → complete,todayWords +50 | wordDelta=50,pomodoro_daily 更新 |
| UT-POM-02 | 切换 bookId start | 旧番茄 cancel,新番茄 running |
| UT-ACH-01 | streakDays=7 首次检测 | writing_milestones 写入 streak_7 |
| UT-ACH-02 | streak_7 已存在 | 不重复 notify |
| UT-INJ-01 | recordInjection 3 ids | 3 rows inserted |
| IT-INJ-01 | interactive confirmContext with knowledgeIds | DB 有对应 logs |
| IT-GOAL-01 | addToday 达标首次 | notification payload 发送一次 |
8.2 E2E(对齐 design/readme §8.2)
| 用例ID | 场景 | 预期 |
|---|---|---|
| E2E-GOAL-01 | 日更 3000 目标写 3500 | 进度变绿,达标 Toast |
| E2E-GOAL-02 | 连更 7 天(测试数据 seed) | 成就区显示 7 天徽章 |
| E2E-GOAL-03 | 启动番茄并完成(测试环境可缩短 duration mock 或 settings=15 + 加速 hook 仅限 E2E) | 完成 Toast 含字数 |
| E2E-INJ-01 | 向导 confirm 知识上下文 | Panel 预览可见注入记录 |
E2E 番茄加速:主进程识别 BILIN_E2E=1 时允许 POMODORO_TEST_SEC=3 环境变量覆盖时长(仅 E2E,不暴露给生产 UI)。
8.3 原则
- 注入历史 IT/E2E 不需要 AI 调用,可纯 DB 断言
- 含通知的 E2E 断言 Toast DOM,不断言 OS 通知栏
9. 文件映射
| 文件 | 职责 |
|---|---|
src/main/db/schema-v8.sql |
knowledge_injection_logs |
src/main/db/migrate.ts |
v8 |
src/main/db/repositories/writing-milestone.repo.ts |
全局 milestones |
src/main/db/repositories/pomodoro-daily.repo.ts |
全局 pomodoro 日统计 |
src/main/db/repositories/knowledge-injection.repo.ts |
每书 injection logs |
src/main/services/pomodoro.service.ts |
番茄状态机 |
src/main/services/achievement.service.ts |
里程碑 |
src/main/services/goal-notification.service.ts |
通知 |
src/main/services/knowledge-injection.service.ts |
注入记录 |
src/main/services/cockpit.service.ts |
扩展 summary |
src/main/ipc/handlers/pomodoro.handler.ts |
番茄 IPC |
src/main/ipc/handlers/achievement.handler.ts |
成就 IPC |
src/main/ipc/handlers/knowledge.handler.ts |
扩展 listInjections |
| `src/main/ipc/handlers/interactive | auto |
src/renderer/components/layout/EditorLayout.tsx |
番茄控件 |
src/renderer/components/cockpit/CockpitModal.tsx |
成就区 |
src/renderer/components/knowledge/KnowledgePanel.tsx |
注入预览 |
src/renderer/components/knowledge/KnowledgeEditorDialog.tsx |
完整历史 |
src/renderer/components/settings/SettingsPage.tsx |
新设置 |
tests/main/pomodoro.test.ts |
UT-POM-* |
tests/main/achievement.test.ts |
UT-ACH-* |
tests/main/knowledge-injection.test.ts |
UT/IT-INJ-* |
e2e/writing-goals.spec.ts |
E2E-GOAL-* |
e2e/knowledge-injection-history.spec.ts |
E2E-INJ-* |
10. Definition of Done(v0.9.0)
- §8 番茄钟 + 里程碑 + 通知按 §1.3 验收
- P6.1 注入历史按 §1.3 第 5–6 条验收
- schema v8 + 全局 sqlite 扩展迁移
npm run build通过npm run test全绿(新增 UT/IT)- E2E-GOAL-01~03、E2E-INJ-01 通过
package.json/ README → v0.9.0- i18n zh-CN / en 键齐全
本规格为笔临 P5.3 + P6.1 子项目。§9 个人写作分析、设定条目注入历史等在后续 spec 增量修订。