# 笔临 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 验收标准 用户能完成: 1. 在状态栏启动 **15/25/45 分钟**番茄钟,暂停/取消/完成后看到剩余时间变化;完成时 Toast 显示本次新增字数 2. `enableSystemNotifications` 开启时,番茄完成与里程碑解锁可收到 **系统通知**(权限被拒则降级 Toast) 3. `dailyWordGoal > 0` 且当日首次达标时收到 Toast(及可选系统通知);同一自然日不重复提醒 4. 连更达到 **7 / 30 / 100 天**(基于 P5.2 `streakDays`)时:庆祝通知 + 驾驶舱成就区永久展示对应徽章;每档仅庆祝一次 5. 交互/自动/向导 **确认知识上下文**后,被注入的 `approved` 知识条目在 **KnowledgePanel** 卡片显示最近 3 条注入记录 6. 打开 **KnowledgeEditorDialog** 可查看该条目完整注入历史(时间、模式、关联章节) 7. 注入记录失败 **不阻断** 写作流确认步骤 ### 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()` 扩展): ```sql 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`: ```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`) ```typescript 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`: ```typescript 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_CONTEXT` - `auto.handler` → `AUTO_CONFIRM_CONTEXT` - `wizard.handler` → `WIZARD_CONFIRM_CONTEXT` ```typescript 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 通道 ```typescript 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 键(节选) ```json "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|wizard.handler.ts` | confirmContext 挂钩 | | `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 增量修订。*