Files
bilin/docs/superpowers/specs/2026-07-07-bilin-p53-p61-goals-injection-design.md
T
bing 1099cb2b0e docs: add P5.3 and P6.1 goals and injection history design spec for v0.9.0
Define pomodoro, milestone badges, goal notifications, and knowledge injection logging for the next release.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 18:51:45 +08:00

422 lines
18 KiB
Markdown
Raw 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.
# 笔临 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(倒计时、开始/暂停/取消、完成字数差分) │
│ · AchievementService7/30/100 里程碑解锁检测与持久化) │
│ · GoalNotificationServiceToast 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 → completetodayWords +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 Donev0.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 增量修订。*