docs: 添加笔临 P0/P1 设计规格
定义 Electron+React 地基与写作核心的架构、IPC、数据模型与验收标准,作为全量实现的第一阶段依据。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,550 @@
|
||||
# 笔临 P0/P1 设计规格
|
||||
|
||||
**版本**:1.0
|
||||
**日期**:2026-07-05
|
||||
**范围**:Electron + React 全量实现的第一阶段(地基 + 写作核心)
|
||||
**参考**:`design/readme.md` v1.1、`design/ui_pc.html`
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 产品定位
|
||||
|
||||
笔临是面向长篇连载作者的桌面写作平台,以「人本创作」为核心:AI 辅助可选,作者保留绝对控制权。本项目从设计文档与 UI 原型出发,实现完整桌面应用;交付采用分阶段策略,最终覆盖设计文档全部 20 章功能。
|
||||
|
||||
### 1.2 本规格范围(P0 + P1)
|
||||
|
||||
| 阶段 | 目标 | 预估周期 |
|
||||
|------|------|----------|
|
||||
| **P0 地基** | 可启动、可持久化设置、主题/i18n/Onboarding/快捷键 | ~1 周 |
|
||||
| **P1 写作核心** | 多书管理、分卷章节、TipTap 编辑、自动保存、字数统计 | ~2 周 |
|
||||
|
||||
**P1 验收标准**:用户能完成「首次引导 → 创建书籍 → 分卷分章 → 富文本写作 → 自动保存 → 重启后内容恢复」。AI 与高级面板为 UI 占位,不实现业务逻辑。
|
||||
|
||||
### 1.3 已确认决策
|
||||
|
||||
| 维度 | 决策 |
|
||||
|------|------|
|
||||
| 总体目标 | 全量实现,分 P0–P7 阶段交付 |
|
||||
| P1 演示重点 | 纯写作体验,AI/高级功能占位 |
|
||||
| UI 策略 | **混合方案 C**:布局/主题/编辑器区沿用 `ui_pc.html` CSS;模态/表单等用 Radix UI |
|
||||
| 目标平台 | **Windows 优先**(Win 10/11),macOS/Linux 在 P7 适配 |
|
||||
| 状态管理 | **Zustand**(全局域)+ **Jotai**(编辑器高频局部状态) |
|
||||
| 外围体验 | 与设计文档对齐:7 主题 + 双语 i18n + Onboarding + 可自定义快捷键 |
|
||||
| 工程结构 | **electron-vite 单体仓库**(方案 A) |
|
||||
|
||||
### 1.4 后续阶段预览(本规格不实现)
|
||||
|
||||
| 阶段 | 范围 |
|
||||
|------|------|
|
||||
| P2 | 大纲/设定/灵感持久化、引用面板、全局搜索、版本历史 |
|
||||
| P3 | AI 会话、对话模式、上下文注入、离线降级 |
|
||||
| P4 | 交互/自动/向导写作、知识抽取、文风学习 |
|
||||
| P5 | 驾驶舱、地标、章间衔接、更新计划、章节模板 |
|
||||
| P6 | 关系图谱、时间线、用词分析、连续阅读 |
|
||||
| P7 | 导入导出、云同步、自动更新、崩溃报告、跨平台打包 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构
|
||||
|
||||
### 2.1 进程模型
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 主进程 (Node.js) │
|
||||
│ · better-sqlite3(每书一个 .sqlite) │
|
||||
│ · global_settings.json / books_registry.json │
|
||||
│ · IPC Handlers(IpcResult 信封) │
|
||||
│ · globalShortcut 快捷键 │
|
||||
└───────────────────────────┬─────────────────────────────┘
|
||||
│ contextBridge
|
||||
┌───────────────────────────▼─────────────────────────────┐
|
||||
│ 渲染进程 (React 18 + TypeScript) │
|
||||
│ · Zustand Stores(书籍/Tab/设置) │
|
||||
│ · Jotai Atoms(编辑器 dirty/字数/光标) │
|
||||
│ · TipTap 编辑器 │
|
||||
│ · i18next + 7 主题 CSS 变量 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**约束**:
|
||||
- 禁止 `nodeIntegration`;所有 DB/FS 操作经 IPC
|
||||
- 所有 IPC 返回值使用 `IpcResult<T>`(见 §6)
|
||||
- `better-sqlite3` 仅在主进程使用同步 API
|
||||
|
||||
### 2.2 技术栈
|
||||
|
||||
| 层次 | 技术 |
|
||||
|------|------|
|
||||
| 桌面框架 | Electron(electron-vite 脚手架) |
|
||||
| 前端 | React 18、TypeScript strict |
|
||||
| 编辑器 | TipTap (ProseMirror) |
|
||||
| 数据库 | better-sqlite3 |
|
||||
| 全局状态 | Zustand |
|
||||
| 编辑器状态 | Jotai |
|
||||
| 交互组件 | Radix UI(Dialog、Select、Tabs、Checkbox、Toast) |
|
||||
| 国际化 | i18next + react-i18next |
|
||||
| 单元/集成测试 | Vitest |
|
||||
| E2E | Playwright + Electron |
|
||||
| 图标 | Font Awesome 6(与原型一致) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 项目目录结构
|
||||
|
||||
```
|
||||
bilin2/
|
||||
├── design/ # 设计文档(只读参考)
|
||||
├── docs/superpowers/
|
||||
│ ├── specs/ # 本文件
|
||||
│ └── plans/ # 实现计划(writing-plans 产出)
|
||||
├── public/locales/
|
||||
│ ├── zh-CN/translation.json
|
||||
│ └── en/translation.json
|
||||
├── src/
|
||||
│ ├── main/
|
||||
│ │ ├── index.ts
|
||||
│ │ ├── db/
|
||||
│ │ │ ├── connection.ts
|
||||
│ │ │ ├── migrations/
|
||||
│ │ │ ├── schema-v1.sql
|
||||
│ │ │ └── repositories/
|
||||
│ │ │ ├── volume.repo.ts
|
||||
│ │ │ └── chapter.repo.ts
|
||||
│ │ ├── ipc/
|
||||
│ │ │ ├── register.ts
|
||||
│ │ │ ├── result.ts
|
||||
│ │ │ └── handlers/
|
||||
│ │ ├── services/
|
||||
│ │ │ ├── book-registry.ts
|
||||
│ │ │ ├── global-settings.ts
|
||||
│ │ │ └── word-count.ts
|
||||
│ │ └── shortcuts/
|
||||
│ │ └── manager.ts
|
||||
│ ├── preload/
|
||||
│ │ ├── index.ts
|
||||
│ │ └── api.d.ts
|
||||
│ └── renderer/
|
||||
│ ├── styles/ # themes.css, layout.css(从 ui_pc.html 提取)
|
||||
│ ├── components/
|
||||
│ │ ├── layout/
|
||||
│ │ ├── home/
|
||||
│ │ ├── editor/
|
||||
│ │ ├── settings/
|
||||
│ │ ├── onboarding/
|
||||
│ │ └── ui/ # Radix 封装
|
||||
│ ├── stores/ # Zustand
|
||||
│ ├── atoms/ # Jotai
|
||||
│ ├── hooks/
|
||||
│ ├── i18n/
|
||||
│ └── lib/
|
||||
├── electron.vite.config.ts
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
**分层约定**:Repository 负责 SQL;IPC Handler 负责校验 + 调用 Repository + 返回 `IpcResult`;渲染进程禁止直接访问数据库。
|
||||
|
||||
---
|
||||
|
||||
## 4. P0 交付清单
|
||||
|
||||
| 模块 | 内容 | 设计文档对应 |
|
||||
|------|------|--------------|
|
||||
| 工程脚手架 | electron-vite + React + TS strict + ESLint | §1.4 |
|
||||
| 自定义标题栏 | drag 区域、最小化/最大化/关闭 | ui_pc.html #topbar |
|
||||
| 主题系统 | 7 套主题 CSS 变量,`data-theme` 切换,持久化 | §3.1 |
|
||||
| i18n | zh-CN / en,所有 UI 文本走 `t()` | §3.2 |
|
||||
| 全局设置 | `global_settings.json` 读写 | §19 |
|
||||
| IPC 基础 | `IpcResult` 信封 + 通道注册 | §16 |
|
||||
| 数据库 | Schema v1 迁移框架 | §12.1 |
|
||||
| Onboarding | 5 步向导,笔名必填,可选示例书 | §3.3 |
|
||||
| 快捷键 | 默认绑定 + 设置页录制 + 冲突提示 | §3.4 |
|
||||
| 三视图骨架 | 主页 / 编辑器 / 设置页 + Tab 管理 | ui_pc.html |
|
||||
|
||||
---
|
||||
|
||||
## 5. P1 交付清单
|
||||
|
||||
### 5.1 完整实现
|
||||
|
||||
| 模块 | 内容 |
|
||||
|------|------|
|
||||
| 主页 | 书籍网格、新建书籍(Radix Dialog)、最近编辑、连更徽章占位 |
|
||||
| 多书 Tab | 打开/切换/关闭,Tab 标题为书名 |
|
||||
| 分卷 | 创建、重命名、折叠/展开、删除(章节移入未分类或跟随删除) |
|
||||
| 章节树 | 树状展示、选中、双击改标题、按当前卷新建章、状态徽章(草稿/定稿等) |
|
||||
| TipTap 编辑器 | 加粗/斜体/下划线/分割线/缩进;默认 Ctrl+V 纯文本 |
|
||||
| 自动保存 | 输入停顿 2 秒 debounce 写入 SQLite |
|
||||
| 字数统计 | 本章/本卷/全书增量更新,状态栏展示 |
|
||||
| 章节切换 | 切换前强制保存;加载 content + cursor_offset |
|
||||
| Undo | 每章独立内存 undo 堆栈(TipTap 内置);**磁盘持久化放 P2** |
|
||||
|
||||
### 5.2 UI 占位(可见、不可用时 Toast)
|
||||
|
||||
| 功能 | 占位行为 |
|
||||
|------|----------|
|
||||
| 右栏 AI 助手 | 布局完整,输入框 disabled,文案 `t('feature.comingSoon')` |
|
||||
| 右栏知识库/用词/书籍设置 | Tab 可见,点击内容区显示占位 |
|
||||
| 引用面板 | 工具栏按钮可见,点击 Toast |
|
||||
| 顶栏驾驶舱/图谱/时间线/专注/音效 | 按钮可见,点击 Toast 或空 modal 壳 |
|
||||
| 侧栏大纲/设定/灵感 | Tab 可见,**mock 静态列表**,切换编辑器标签但不持久化 |
|
||||
| 批量章节操作 | P2 |
|
||||
| 导入导出 | P7 |
|
||||
|
||||
---
|
||||
|
||||
## 6. IPC 协议
|
||||
|
||||
### 6.1 IpcResult 信封
|
||||
|
||||
```typescript
|
||||
type IpcResult<T> =
|
||||
| { ok: true; data: T }
|
||||
| { ok: false; error: IpcError };
|
||||
|
||||
interface IpcError {
|
||||
code: ErrorCode;
|
||||
message: string;
|
||||
recoverable: boolean;
|
||||
}
|
||||
|
||||
enum ErrorCode {
|
||||
DB_READ_FAILED = 'DB_READ_FAILED',
|
||||
DB_WRITE_FAILED = 'DB_WRITE_FAILED',
|
||||
FILE_NOT_FOUND = 'FILE_NOT_FOUND',
|
||||
IMPORT_INVALID = 'IMPORT_INVALID',
|
||||
UNKNOWN = 'UNKNOWN',
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 通道列表(P0/P1)
|
||||
|
||||
**设置**
|
||||
|
||||
| 通道 | 参数 | 返回 |
|
||||
|------|------|------|
|
||||
| `settings:get` | — | `GlobalSettings` |
|
||||
| `settings:update` | `Partial<GlobalSettings>` | `GlobalSettings` |
|
||||
|
||||
**书籍**
|
||||
|
||||
| 通道 | 参数 | 返回 |
|
||||
|------|------|------|
|
||||
| `book:list` | — | `BookMeta[]` |
|
||||
| `book:create` | `CreateBookParams` | `BookMeta` |
|
||||
| `book:delete` | `{ bookId }` | `void` |
|
||||
| `book:open` | `{ bookId }` | `{ meta, volumes, chapters }` |
|
||||
|
||||
**分卷**
|
||||
|
||||
| 通道 | 参数 | 返回 |
|
||||
|------|------|------|
|
||||
| `volume:create` | `{ bookId, name }` | `Volume` |
|
||||
| `volume:update` | `{ bookId, volumeId, ... }` | `Volume` |
|
||||
| `volume:delete` | `{ bookId, volumeId, moveChaptersTo? }` | `void` |
|
||||
| `volume:reorder` | `{ bookId, orderedIds }` | `void` |
|
||||
|
||||
**章节**
|
||||
|
||||
| 通道 | 参数 | 返回 |
|
||||
|------|------|------|
|
||||
| `chapter:create` | `{ bookId, volumeId, title }` | `Chapter` |
|
||||
| `chapter:get` | `{ bookId, chapterId }` | `Chapter` |
|
||||
| `chapter:update` | `{ bookId, chapterId, title?, content?, status?, cursorOffset?, wordCount? }` | `Chapter` |
|
||||
| `chapter:delete` | `{ bookId, chapterId }` | `void` |
|
||||
| `chapter:reorder` | `{ bookId, volumeId, orderedIds }` | `void` |
|
||||
|
||||
**快捷键**
|
||||
|
||||
| 通道 | 参数 | 返回 |
|
||||
|------|------|------|
|
||||
| `shortcut:getAll` | — | `Record<ActionId, string>` |
|
||||
| `shortcut:register` | `{ action, accelerator }` | `void` |
|
||||
|
||||
**主→渲染事件**
|
||||
|
||||
| 事件 | 用途 |
|
||||
|------|------|
|
||||
| `shortcut:triggered` | `{ action: ActionId }` |
|
||||
|
||||
### 6.3 Preload API 形状
|
||||
|
||||
```typescript
|
||||
interface ElectronAPI {
|
||||
settings: {
|
||||
get(): Promise<IpcResult<GlobalSettings>>;
|
||||
update(p: Partial<GlobalSettings>): Promise<IpcResult<GlobalSettings>>;
|
||||
};
|
||||
book: {
|
||||
list(): Promise<IpcResult<BookMeta[]>>;
|
||||
create(p: CreateBookParams): Promise<IpcResult<BookMeta>>;
|
||||
delete(p: { bookId: string }): Promise<IpcResult<void>>;
|
||||
open(p: { bookId: string }): Promise<IpcResult<BookOpenResult>>;
|
||||
};
|
||||
volume: { /* create, update, delete, reorder */ };
|
||||
chapter: { /* create, get, update, delete, reorder */ };
|
||||
shortcut: {
|
||||
getAll(): Promise<IpcResult<Record<ActionId, string>>>;
|
||||
register(p: { action: ActionId; accelerator: string }): Promise<IpcResult<void>>;
|
||||
};
|
||||
onShortcutTriggered(callback: (action: ActionId) => void): () => void;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 数据模型
|
||||
|
||||
### 7.1 文件布局
|
||||
|
||||
```
|
||||
{userData}/
|
||||
├── global_settings.json
|
||||
├── books_registry.json
|
||||
├── books/
|
||||
│ └── {bookId}.sqlite
|
||||
└── logs/bilin.log
|
||||
```
|
||||
|
||||
### 7.2 global_settings.json
|
||||
|
||||
```typescript
|
||||
interface GlobalSettings {
|
||||
penName: string;
|
||||
onboardingCompleted: boolean;
|
||||
theme: 'default' | 'bamboo' | 'moonlit' | 'ricepaper' | 'mist' | 'teagarden' | 'twilight';
|
||||
language: 'zh-CN' | 'en';
|
||||
dailyWordGoal: number;
|
||||
shortcuts: Record<ActionId, string>;
|
||||
}
|
||||
```
|
||||
|
||||
P0/P1 不实现:`aiBackend`、`syncConfig`、`chapterTemplates`(留字段或 P2+ 扩展)。
|
||||
|
||||
### 7.3 books_registry.json
|
||||
|
||||
```typescript
|
||||
interface BookMeta {
|
||||
id: string;
|
||||
name: string;
|
||||
category: string;
|
||||
targetWordCount: number | null;
|
||||
dbPath: string;
|
||||
status: 'draft' | 'ongoing' | 'done';
|
||||
lastOpenedAt: string;
|
||||
lastChapterId: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
```
|
||||
|
||||
### 7.4 SQLite Schema v1(每书)
|
||||
|
||||
```sql
|
||||
CREATE TABLE schema_version (
|
||||
version INTEGER PRIMARY KEY,
|
||||
applied_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
description TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE volumes (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT DEFAULT '',
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE chapters (
|
||||
id TEXT PRIMARY KEY,
|
||||
volume_id TEXT,
|
||||
title TEXT NOT NULL DEFAULT '',
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'draft',
|
||||
word_count INTEGER NOT NULL DEFAULT 0,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
cursor_offset INTEGER DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (volume_id) REFERENCES volumes(id) ON DELETE SET NULL
|
||||
);
|
||||
```
|
||||
|
||||
**P1 不含**:`outline_items`、`settings`、`inspiration`、`snapshots`、`undo_stack`、`bookmarks` 等(P2+ 通过迁移追加)。
|
||||
|
||||
### 7.5 创建书籍流程
|
||||
|
||||
1. 生成 UUID
|
||||
2. 在 `books/` 下创建 `{id}.sqlite`,执行 schema v1 迁移
|
||||
3. 写入 `books_registry.json`
|
||||
4. 默认创建分卷「第一卷」
|
||||
5. 若 Onboarding 勾选示例书,额外创建 1 章示例正文
|
||||
|
||||
---
|
||||
|
||||
## 8. 状态管理
|
||||
|
||||
### 8.1 Zustand Stores
|
||||
|
||||
| Store | 职责 |
|
||||
|-------|------|
|
||||
| `useAppStore` | 当前视图(home/editor/settings)、侧栏激活 panel |
|
||||
| `useTabStore` | openTabs、activeTabId |
|
||||
| `useBookStore` | 书籍列表、当前书、分卷章节树、选中章节 ID |
|
||||
| `useSettingsStore` | theme、language、penName、shortcuts |
|
||||
| `useOnboardingStore` | 向导步骤、完成状态 |
|
||||
|
||||
写操作:调用 IPC → 成功后更新 Store。
|
||||
|
||||
### 8.2 Jotai Atoms(编辑器域)
|
||||
|
||||
| Atom | 用途 |
|
||||
|------|------|
|
||||
| `currentChapterIdAtom` | 当前编辑章节 |
|
||||
| `editorContentAtom` | TipTap 文档内容 |
|
||||
| `editorDirtyAtom` | 未保存标记 |
|
||||
| `editorSavingAtom` | 保存中状态 |
|
||||
| `wordCountAtom` | `{ chapter, volume, book }` |
|
||||
| `cursorOffsetAtom` | 光标字符偏移 |
|
||||
| `lastSavedAtAtom` | 上次保存时间 |
|
||||
|
||||
### 8.3 章节切换序列
|
||||
|
||||
1. 若 `editorDirtyAtom` → 立即 `chapter:update`
|
||||
2. `chapter:get` 加载新章节
|
||||
3. TipTap 设置 content,恢复 cursor_offset
|
||||
4. 重置 dirty
|
||||
|
||||
### 8.4 自动保存
|
||||
|
||||
- 监听 TipTap `onUpdate`
|
||||
- debounce **2000ms**
|
||||
- 调用 `chapter:update`(content、cursorOffset、wordCount)
|
||||
- 主进程 `word-count.ts` 增量更新章节字数;卷/全书字数由 chapters 聚合或缓存
|
||||
|
||||
---
|
||||
|
||||
## 9. UI 规范
|
||||
|
||||
### 9.1 混合方案落地
|
||||
|
||||
| 区域 | 实现 |
|
||||
|------|------|
|
||||
| 顶栏、侧栏、编辑器区、状态栏 | 从 `ui_pc.html` 提取 CSS(变量 + 布局类) |
|
||||
| 模态框、Select、Checkbox、Toast | Radix UI 封装于 `components/ui/` |
|
||||
| 主题 | `[data-theme="xxx"]` 覆盖 CSS 变量,与原型 7 主题 ID 一致 |
|
||||
|
||||
### 9.2 三视图
|
||||
|
||||
- **主页** `#home-page`:Logo、操作按钮、书籍网格、最近编辑
|
||||
- **编辑器** `#editor-layout`:左栏四 Tab + 中央编辑器 + 右栏占位
|
||||
- **设置** `#settings-page`:侧栏导航 + 通用/编辑器/AI(占位)/快捷键/备份(占位)/关于
|
||||
|
||||
### 9.3 默认快捷键(P0/P1 实现子集)
|
||||
|
||||
| 功能 | 默认 | P0/P1 |
|
||||
|------|------|-------|
|
||||
| 保存章节 | Ctrl+S | ✅ |
|
||||
| 新建章节 | Ctrl+Shift+N | ✅ |
|
||||
| 切换专注模式 | Ctrl+Alt+F | 占位 Toast |
|
||||
| 全局搜索 | Ctrl+Shift+F | 占位 Toast |
|
||||
| 关闭 Tab | Ctrl+W | ✅ |
|
||||
| 打开设置 | — | 顶栏齿轮 |
|
||||
|
||||
其余快捷键在设置页展示,P2+ 绑定实际功能。
|
||||
|
||||
### 9.4 i18n 要求
|
||||
|
||||
- 所有用户可见字符串使用 `t()`
|
||||
- zh-CN 与 en 同步维护,不得混用语言
|
||||
- 数字/日期格式随 locale 变化
|
||||
|
||||
---
|
||||
|
||||
## 10. 核心流程
|
||||
|
||||
### 10.1 启动
|
||||
|
||||
1. 主进程读取 `global_settings.json`,注册快捷键
|
||||
2. 渲染进程 `settings:get` → 应用 theme + language
|
||||
3. 若 `onboardingCompleted === false` → 显示 Onboarding
|
||||
4. 否则 → 主页 + `book:list`
|
||||
|
||||
### 10.2 打开书籍
|
||||
|
||||
1. `book:open` → 填充 useBookStore
|
||||
2. 新建 Tab,`lastChapterId` 或第一卷第一章
|
||||
3. `chapter:get` → TipTap 加载
|
||||
|
||||
### 10.3 错误处理
|
||||
|
||||
| 场景 | code | recoverable | UI |
|
||||
|------|------|-------------|-----|
|
||||
| SQLite 写失败 | DB_WRITE_FAILED | true | Toast + 重试 |
|
||||
| DB 文件丢失 | FILE_NOT_FOUND | false | 错误对话框 |
|
||||
| IPC 异常 | UNKNOWN | true | Toast |
|
||||
|
||||
渲染进程统一 `ipcCall()` 封装处理。
|
||||
|
||||
---
|
||||
|
||||
## 11. 测试
|
||||
|
||||
### 11.1 工具
|
||||
|
||||
- **Vitest**:主进程 Repository、word-count、IPC handler(内存 SQLite)
|
||||
- **Playwright + Electron**:E2E
|
||||
|
||||
### 11.2 P0/P1 必过用例
|
||||
|
||||
| ID | 场景 |
|
||||
|----|------|
|
||||
| E2E-THEME-01 | 依次切换 7 主题,UI 颜色正确 |
|
||||
| E2E-I18N-03 | 中英文切换,无语言混杂 |
|
||||
| E2E-ONBOARD-02 | 完成引导,笔名持久化 |
|
||||
| E2E-KEY-02 | Ctrl+Shift+N 新建章节 |
|
||||
| E2E-P1-SAVE | 写作 → 等 2s 自动保存 → 重启 → 内容完整 |
|
||||
| E2E-P1-CURSOR | 切换章节再回来,光标偏移恢复 |
|
||||
|
||||
---
|
||||
|
||||
## 12. 非目标(P0/P1 明确排除)
|
||||
|
||||
- AI 任何后端集成
|
||||
- 版本历史、undo 磁盘持久化
|
||||
- 大纲/设定/灵感数据持久化
|
||||
- 导入导出、云同步、PDF
|
||||
- 驾驶舱、图谱、时间线业务逻辑
|
||||
- macOS/Linux 打包与签名
|
||||
- 无障碍完整 E2E(P7 补全)
|
||||
|
||||
---
|
||||
|
||||
## 13. 风险与缓解
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|------|------|
|
||||
| better-sqlite3 原生模块 Electron 编译 | electron-vite 官方模板 + rebuild 脚本 |
|
||||
| TipTap 大文档性能 | P1 单章编辑;全书虚拟滚动在 P2 |
|
||||
| ui_pc.html CSS 迁移工作量大 | 先迁移 layout + themes,组件级样式按需提取 |
|
||||
| P1 范围含完整 i18n/主题/Onboarding 导致工期膨胀 | 严格区分 P1 完整 vs 占位清单(§5.2) |
|
||||
|
||||
---
|
||||
|
||||
## 14. 完成定义(Definition of Done)
|
||||
|
||||
P0/P1 合并发布为 **v0.1.0** 时:
|
||||
|
||||
- [ ] Windows 下 `npm run dev` 可启动,无控制台 error
|
||||
- [ ] 新用户走完 Onboarding,可创建书籍并写作
|
||||
- [ ] 7 主题、双语、快捷键自定义可用
|
||||
- [ ] 自动保存与重启恢复通过 E2E
|
||||
- [ ] §5.2 占位功能行为符合规范(可见 + Toast,无崩溃)
|
||||
- [ ] Vitest 集成测试覆盖 chapter CRUD + settings 读写
|
||||
|
||||
---
|
||||
|
||||
*本规格为笔临全量实现的 Phase 0/1 子项目。后续阶段各自独立 spec 或在本文档增量修订。*
|
||||
Reference in New Issue
Block a user