Files
bilin/docs/superpowers/specs/2026-07-06-bilin-p2-design.md
T
bing c772b7d703 docs: 添加笔临 P2 设计规格
覆盖大纲/设定/灵感持久化、引用面板、版本历史、全局搜索、地标、用词分析与 P2.0 主题修复;严格对齐 design/readme §5.3.9–§5.6。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 10:49:12 +08:00

20 KiB
Raw Blame History

笔临 P2 设计规格

版本1.0
日期2026-07-06
范围:第二阶段——内容扩展、引用与检索、版本追溯、主题修复
前置P0/P1 已交付(v0.1.0011bd6d
参考design/readme.md v1.1 §5.3.9 / §5.4–§5.6 / §5.5、design/ui_pc.html


1. 背景与目标

1.1 阶段定位

P2 在 P1「纯写作闭环」之上,补齐长篇创作的信息管理能力:大纲/设定/灵感持久化、写作引用、全文检索、版本历史、地标待办、用词分析,并修复浅色主题控件不可见问题。

1.2 已确认决策(Brainstorming 2026-07-06

维度 决策
范围 完整 P2 + 主题修复
对齐深度 严格对齐 design/readme.md §5.3.9 / §5.4–§5.6 / §5.5
编辑器 完全统一中央 TipTap(章节/大纲/设定/灵感)
搜索 §5.6.1 全量;§5.6.3 用词分析实装;§5.6.2 AI 命名检查 占位至 P3
地标 §5.3.9 全量 + 纳入全局搜索
主题 P2.0 先行~3 天),再进入功能开发
实现策略 方案 A:分层基础 + 功能切片
平台 Windows 优先(延续 P0/P1

1.3 P2 验收标准

用户能完成:

  1. 在左栏四 Tab 中 CRUD 大纲/设定/灵感,并在中央编辑器统一编辑、自动保存、重启恢复
  2. 打开引用面板,搜索/钉住/拖拽插入设定或大纲内容到正文
  3. 使用全局搜索(含正则、替换预览)跨章节/大纲/设定/灵感/地标检索并跳转
  4. 创建/浏览/对比/回滚章节版本历史(自动/手动/持久快照)
  5. 插入/管理写作地标,通过清单或搜索跳转
  6. 查看用词分析(高频词、过度用词高亮)并跳转编辑器定位
  7. 切换 3 套浅色主题,所有关键页面文字清晰可读

1.4 本规格不实现(明确排除)

归属
§5.6.2 AI 命名一致性检查 P3UI 占位)
§5.4.1 ai 类型快照业务触发 P3DB 字段预留)
灵感语音输入 P2.1 占位按钮
ai_sessions / knowledge_entries / timeline_events P3/P5/P6
章节拖拽排序(同卷/跨卷) P2.1P2 先用按钮排序)
TipTap @提及 反向跳转 P2.4 实现 Mention 扩展

2. 架构

2.1 进程模型(延续 P0/P1

┌─────────────────────────────────────────────────────────┐
│ 主进程                                                   │
│  · node:sqlite(每书 .sqliteschema v2                │
│  · FTS5 虚拟表(search_fts                            │
│  · SnapshotService(定时/退出快照)                       │
│  · SearchService / WordFreqService                       │
│  · IPC HandlersIpcResult 信封)                        │
└───────────────────────────┬─────────────────────────────┘
                            │ contextBridge
┌───────────────────────────▼─────────────────────────────┐
│ 渲染进程                                                   │
│  · useEditStoreEditTarget 统一编辑)                    │
│  · Zustand + Jotai(延续 P1                             │
│  · TipTap(章节完整 / 其他简化模式)                      │
│  · 模态:搜索 / 版本 / 灵感捕获 / 地标清单                │
└─────────────────────────────────────────────────────────┘

2.2 统一编辑内核(EditSession

type EditTarget =
  | { kind: 'chapter'; id: string }
  | { kind: 'outline'; id: string }
  | { kind: 'setting'; id: string }
  | { kind: 'inspiration'; id: string }

useEditStoreZustand)职责

  • 持有 currentTarget: EditTarget | null
  • switchTarget(next)flush 当前 → IPC get → 更新 TipTap 内容与 cursor
  • useBookStore.selectedChapterId 协同:选中章节时 kind='chapter'

Jotai atoms(延续并扩展):

  • editorDirtyAtom / editorSavingAtom / lastSavedAtAtom — 所有 target 共用
  • wordCountAtom — 章节时显示卷/章/全书;其他 target 仅条目字数

自动保存debounce 2s(与 P1 一致);切换 target / 关闭 Tab 前 flushEditorSave()

2.3 里程碑

阶段 交付 周期
P2.0 主题 token 补全、消除硬编码色值、对比度 E2E ~3 天
P2.1 schema-v2 迁移、Repository、IPC 扩展 ~4 天
P2.2 EditSession + 左栏四 Tab CRUD + 统一编辑 ~5 天
P2.3 大纲对照视图、覆盖度标记/筛选 ~4 天
P2.4 引用面板(Tab/钉住/拖拽/Mention ~4 天
P2.5 版本历史(快照/diff/回滚) ~5 天
P2.6 全局搜索 FTS5 + 替换 + 地标全量 ~5 天
P2.7 用词分析 + §5.6.2 占位 ~3 天

目标版本v0.2.0


3. 数据模型

3.1 Schema v2 迁移

schema_version 1 → 2。新安装书籍直接应用 v1+v2;已有书籍运行 migrate.ts 增量 ALTER。

chapters 扩展

ALTER TABLE chapters ADD COLUMN publish_status TEXT NOT NULL DEFAULT 'draft';
ALTER TABLE chapters ADD COLUMN pov_character_id TEXT DEFAULT NULL;
ALTER TABLE chapters ADD COLUMN summary TEXT DEFAULT '';
ALTER TABLE chapters ADD COLUMN story_time TEXT DEFAULT NULL;
-- pov_character_id FK → settings(id) 在 v2 表创建后添加

新增表(对齐 design §19):

CREATE TABLE outline_items (
    id                  TEXT PRIMARY KEY,
    parent_id           TEXT,
    title               TEXT NOT NULL,
    description         TEXT DEFAULT '',
    status              TEXT NOT NULL DEFAULT 'pending',
    expected_word_count INTEGER DEFAULT NULL,
    chapter_id          TEXT,
    sort_order          INTEGER NOT NULL DEFAULT 0,
    created_at          TEXT NOT NULL DEFAULT (datetime('now')),
    updated_at          TEXT NOT NULL DEFAULT (datetime('now')),
    FOREIGN KEY (parent_id) REFERENCES outline_items(id) ON DELETE CASCADE,
    FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE SET NULL
);

CREATE TABLE settings (
    id          TEXT PRIMARY KEY,
    type        TEXT NOT NULL,
    name        TEXT NOT NULL,
    description TEXT DEFAULT '',
    properties  TEXT DEFAULT '{}',
    created_at  TEXT NOT NULL DEFAULT (datetime('now')),
    updated_at  TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE setting_chapter_refs (
    setting_id  TEXT NOT NULL,
    chapter_id  TEXT NOT NULL,
    PRIMARY KEY (setting_id, chapter_id),
    FOREIGN KEY (setting_id) REFERENCES settings(id) ON DELETE CASCADE,
    FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE CASCADE
);

CREATE TABLE inspiration (
    id          TEXT PRIMARY KEY,
    title       TEXT NOT NULL DEFAULT '',
    content     TEXT NOT NULL DEFAULT '',
    tags        TEXT DEFAULT '[]',
    created_at  TEXT NOT NULL DEFAULT (datetime('now')),
    updated_at  TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE snapshots (
    id          TEXT PRIMARY KEY,
    chapter_id  TEXT NOT NULL,
    type        TEXT NOT NULL,
    name        TEXT DEFAULT '',
    content     TEXT NOT NULL,
    created_at  TEXT NOT NULL DEFAULT (datetime('now')),
    FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE CASCADE
);

CREATE TABLE bookmarks (
    id            TEXT PRIMARY KEY,
    chapter_id    TEXT NOT NULL,
    position      INTEGER NOT NULL,
    label         TEXT NOT NULL,
    landmark_type TEXT NOT NULL DEFAULT 'todo',
    resolved      INTEGER NOT NULL DEFAULT 0,
    created_at    TEXT NOT NULL DEFAULT (datetime('now')),
    FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE CASCADE
);

FTS5(每书 DB):

CREATE VIRTUAL TABLE search_fts USING fts5(
    source_kind,
    source_id,
    title,
    body,
    tokenize='unicode61'
);

触发器:chapters / outline_items / settings / inspiration / bookmarks 的 INSERT/UPDATE/DELETE 同步 search_fts。迁移完成后执行一次 rebuildFts(bookId)

3.2 枚举值

字段
outline_items.status pending / writing / done / abandoned
settings.type character / location / item / skill / faction / custom
snapshots.type auto / manual / persist / ai
bookmarks.landmark_type todo / foreshadow / research / custom
chapters.publish_status draft / ready / published

3.3 global_settings.json 扩展

interface GlobalSettings {
  // ...P0/P1 字段
  snapshotIntervalMs: number    // 默认 3000005 分钟)
  snapshotMaxAuto: number       // 默认 20
  snapshotMaxPersist: number    // 默认 3
  searchHistory: string[]       // 最近 10 条
}

4. IPC 契约

所有通道返回 IpcResult<T>。参数 camelCaseRepository 映射 snake_case。

4.1 新增通道

通道 说明
outline:list { bookId }OutlineItem[](树形扁平化或嵌套)
outline:create { bookId, parentId?, title, sortOrder }
outline:update { bookId, id, patch }
outline:delete { bookId, id }(级联子节点)
outline:move { bookId, id, parentId?, sortOrder }
setting:list { bookId, type? }
setting:create { bookId, type, name }
setting:update { bookId, id, patch }
setting:delete { bookId, id }
setting:syncRefs { bookId, id, chapterIds[] }
inspiration:list { bookId }
inspiration:create { bookId, title?, content?, tags? }
inspiration:update { bookId, id, patch }
inspiration:delete { bookId, id }
inspiration:convert { bookId, id, targetKind: 'outline' | 'setting' }
snapshot:list { bookId, chapterId }
snapshot:create { bookId, chapterId, type, name? }
snapshot:restore { bookId, chapterId, snapshotId }
snapshot:delete { bookId, snapshotId }
bookmark:list { bookId, chapterId?, resolved? }
bookmark:create { bookId, chapterId, position, label, landmarkType }
bookmark:update { bookId, id, patch }
bookmark:resolve { bookId, id, resolved: boolean }
bookmark:delete { bookId, id }
search:query { bookId, query, scope, options }SearchResult[]
search:replace { bookId, query, replacement, scope, dryRun }
search:getHistory / search:saveHistory 读写 global_settings.searchHistory
wordfreq:analyze { bookId, scope }{ words: { token, count }[] }

4.2 主进程服务

服务 职责
SnapshotService 定时 auto 快照、Ctrl+S/退出 persist 快照、FIFO 淘汰
SearchService FTS5 查询;regex 模式 fallback 到 JS 扫描
WordFreqService HTML→plainTextCJK 单字 + 拉丁词分词,Top N 统计
FtsSyncService CRUD 后增量同步;rebuildFts 全量重建

4.3 book:open 响应扩展

interface BookOpenResult {
  meta: BookMeta
  volumes: Volume[]
  chapters: Chapter[]
  outlines: OutlineItem[]      // 新增
  settings: SettingEntry[]     // 新增
  inspirations: InspirationEntry[]  // 新增
}

5. UI 规格

5.1 左栏四 Tab

Tab 组件 P2 行为
章节 ChapterTree 双击改标题(已有);status badge
大纲 OutlineTree 无限层级;新建/删除;覆盖度橙色边框;筛选下拉
设定 SettingList 按 type 分组折叠;新建
灵感 InspirationList 列表 + 底部新建

各 Tab 底部「+ 新建」;选中条目 → useEditStore.switchTarget

大纲覆盖度(§5.5.2):

  • chapter_id 关联 → 橙色左边框 + ⚠ 图标
  • 筛选:全部 / 未覆盖 / 已覆盖
  • Tooltip:预期字数 vs 关联章节实际字数,偏差 >20% 标红

5.2 中央编辑器

元素 规格
DocumentTitle 双击 inline 编辑;Enter 确认 / Esc 取消
EditorToolbar 加粗/斜体/下划线;引用按钮;版本历史;插入地标
TipTapEditor chapter=StarterKit+Underline;其他=simplifiedParagraph+Bold+Italic+Placeholder
StatusBar 保存状态 + 字数(章节三维 / 其他单维)
粘贴 纯文本插入(Shift 保留格式,延续 P1)

5.3 引用面板(§5.3.8

  • DOM#reference-panel,宽 240px.open 切换
  • 与 AI 右栏互斥
  • Tab:设定 / 大纲 / 灵感;顶部搜索框
  • 列表项:名称 + 摘要前 40 字;点击展开详情
  • 钉住 checkbox:切换章节时保持选中条目
  • 拖拽:插入 plainText 到光标
  • MentionP2.4):@设定名 高亮,点击跳转设定 EditTarget

5.4 模态层

ID 快捷键 功能
#searchModal Ctrl+Shift+F 搜索 + 范围 + 高级选项 + 替换预览
#versionModal 工具栏 版本列表 + diff 双栏 + 回滚
#inspirationModal Ctrl+Shift+I 快速捕获(语音按钮占位)
#landmarksModal Ctrl+Shift+L 地标清单,按类型/章节分组

搜索结果:按类型分组;↑↓ 选择 + Enter 跳转;上下文前后 20 字。

5.5 大纲对照视图(§5.5.6

  • 入口:大纲 Tab「对照模式」
  • 分屏:左 35% 大纲树,右 65% 关联章节正文(只读)
  • 底部对比条:预期 vs 实际 vs 偏差%
  • 无关联:「尚未写作」占位

5.6 版本历史(§5.4

类型 触发 上限
auto 定时(默认 5min)且内容变更 20FIFO
manual 用户「创建快照」 无上限
persist Ctrl+S / app quit 3,轮替
ai 预留 P3
  • Diffdiff-match-patch 行级对比;绿新增/红删除/黄修改
  • 回滚:restore 前自动 manual 备份
  • 列表:版本号、时间、类型、摘要(manual 名称)

5.7 地标(§5.3.9

  • 插入:编辑器右键 / 工具栏 / Ctrl+Shift+M
  • 正文行内标记:[TODO: ...] 样式(TipTap Mark 或 inline Node
  • 不进入导出正文(export 逻辑留 P7,P2 仅存储)
  • 清单模态:按类型/章节分组;点击跳转章节+position
  • 完成:勾选 resolved,可选归档

5.8 用词分析(§5.6.3

  • 入口:右栏「用词」Tab(原占位 → 实装)
  • 高频词 Top 100,频次降序
  • 点击词条 → 编辑器跳转并高亮所有出现
  • 过度用词:每千字 >5 次的非功能词,编辑器淡黄色 Mark
  • §5.6.2 命名一致性:同面板底部「即将推出(需 AI)」

5.9 主题修复(P2.0

问题根因:浅色主题 CSS 变量不完整;多处硬编码 #fff(含 ui_pc.html 移植残留)。

修复项

  1. 补全 ricepaper / mist / teagarden 全部 token--bg-surface--text-dim--accent-glow--border-light 等)
  2. 新增语义 token
    • --text-on-accent:主按钮/激活 Tab 上的文字
    • --input-text / --input-bg:表单控件
  3. 替换 layout.css、组件内联 style 中 color: #fff → 语义 token
  4. select / option / input 统一使用 --input-* token

验收 E2Ee2e/themes-contrast.spec.ts):

  • 主题:ricepapermistteagarden
  • 页面:主页、编辑器、设置、搜索模态、引用面板
  • 断言:关键文字元素 colorbackground 对比度 ≥ 4.5:1WCAG AA

6. 状态管理

6.1 新增 Stores

Store 职责
useEditStore EditTarget 切换、flush、load
useOutlineStore 大纲树、筛选、对照模式
useReferenceStore 引用面板 open/pin/activeTab/selectedItem
useSearchStore 搜索模态、query、results、replacePreview

useBookStore 扩展:缓存 outlines/settings/inspirationsopenBook 一次性加载。

6.2 快捷键绑定(P2 实装)

动作 默认 P2 行为
globalSearch Ctrl+Shift+F 打开搜索模态
openReference Ctrl+Shift+P 切换引用面板
insertLandmark Ctrl+Shift+M 插入地标
openLandmarks Ctrl+Shift+L 地标清单
captureInspiration Ctrl+Shift+I 灵感捕获模态
saveChapter Ctrl+S 保存 + 创建 persist 快照

7. 测试策略

7.1 单元/集成(Vitest

模块 用例
outline.repo CRUD、层级、move、覆盖度查询
setting.repo CRUD、chapterRefs 同步
inspiration.repo CRUD、convert
snapshot.repo 创建、FIFO 淘汰、restore
bookmark.repo CRUD、resolve
search.service FTS 索引、query、replace dryRun
wordfreq.service CJK/拉丁分词、Top N
migrate v1→v2 旧库升级后数据完整

7.2 E2EPlaywright

ID 场景
E2E-P2-OUTLINE-01 创建层级大纲 → 重启 → 树结构保留
E2E-P2-EDIT-01 切换章节→大纲→设定,内容互不覆盖
E2E-P2-REF-01 引用面板拖拽设定到正文
E2E-P2-SEARCH-01 全局搜索跨类型 → Enter 跳转
E2E-P2-SNAP-01 编辑 → 手动快照 → diff → 回滚
E2E-P2-LAND-01 插入地标 → 清单可见 → 跳转
E2E-P2-WORD-01 用词分析 Top 词 → 点击跳转高亮
E2E-THEME-01 3 浅色主题关键页面文字可见

8. 目录结构增量

src/main/
├── db/
│   ├── schema-v2.sql
│   ├── migrations/migrate-v2.ts
│   └── repositories/
│       ├── outline.repo.ts
│       ├── setting.repo.ts
│       ├── inspiration.repo.ts
│       ├── snapshot.repo.ts
│       └── bookmark.repo.ts
├── services/
│   ├── snapshot.service.ts
│   ├── search.service.ts
│   ├── fts-sync.service.ts
│   └── wordfreq.service.ts
└── ipc/handlers/
    ├── outline.handler.ts
    ├── setting.handler.ts
    ├── inspiration.handler.ts
    ├── snapshot.handler.ts
    ├── bookmark.handler.ts
    ├── search.handler.ts
    └── wordfreq.handler.ts

src/renderer/
├── stores/useEditStore.ts
├── stores/useOutlineStore.ts
├── stores/useReferenceStore.ts
├── stores/useSearchStore.ts
├── components/
│   ├── outline/OutlineTree.tsx
│   ├── outline/OutlineCompareView.tsx
│   ├── setting/SettingList.tsx
│   ├── inspiration/InspirationList.tsx
│   ├── reference/ReferencePanel.tsx
│   ├── search/SearchModal.tsx
│   ├── version/VersionModal.tsx
│   ├── landmark/LandmarkModal.tsx
│   ├── landmark/LandmarkMark.ts
│   └── wordfreq/WordFreqPanel.tsx
└── extensions/mention.ts

e2e/
├── themes-contrast.spec.ts
├── outline.spec.ts
├── search.spec.ts
├── snapshot.spec.ts
└── landmarks.spec.ts

9. 风险与缓解

风险 缓解
FTS5 在 node:sqlite 不可用 启动时检测;fallback JS 全表扫描(性能可接受于单书规模)
统一 EditTarget 切换丢数据 flush 强制 awaitE2E 覆盖切换序列
版本 diff 大章节性能 plainText diff>100KB 时警告并限制词级粒度
P2 范围大、工期膨胀 严格按 P2.0–P2.7 里程碑交付;每阶段 E2E 门禁
浅色主题回归 P2.0 建立 token 规范 + contrast E2E 纳入 CI

10. Definition of Donev0.2.0

  • P2.0P2.7 全部里程碑完成
  • §7 测试全部 PASS
  • 3 套浅色主题 contrast E2E PASS
  • §5.6.2 AI 命名检查为占位 Toast,不 crash
  • npm run build 无 error
  • Windows 手动验收:§1.3 七项流程

Spec Self-Review

检查项 结果
Placeholder 扫描 §5.6.2 / 语音 / ai 快照 均明确标注归属,无 TBD
内部一致性 EditTarget 统一编辑贯穿 IPC/UI/测试;FTS 与五类 source 对齐
范围 单规格可支撑一份 implementation plan;章节拖拽明确 P2.1
歧义 snapshot 类型 persist vs design「退出/手动保存版本」已映射;status 枚举与 design §19 对齐

附录:与 P0/P1 规格差异

P0/P1 规格 当前/P2 规格
数据库 better-sqlite3 node:sqlite(已迁移)
P5 地标 原归 P5 P2 全量(用户确认)
P6 用词分析 原归 P6 P2 实装(用户确认)