写在前面
先说结论:我是个前端半吊子,但我用 AI 写了一个功能完整的桌面笔记应用。
FireFire,Electron + React 技术栈,支持三大平台,123 个源文件,2 万多行代码。从 2022 年 8 月第一次 commit 到现在 v0.6.29,该有的功能基本都有了------富文本编辑、知识图谱、WebDAV 同步、AI 对话、版本历史......
如果你问我:这些代码你都看得懂吗?
emmm......大部分吧(心虚)。
真香警告
说实话,一开始我对 AI 写代码这事儿是拒绝的。
改变我想法的是一个 B站视频嵌入功能。我当时的状态是:知道 Tiptap 是个编辑器框架,但它底层的 ProseMirror 是啥玩意儿?Node Extension 怎么写?完全不懂,文档看得我头大。
于是我抱着试试看的心态问了 TRAE,结果它直接给我整了这么一段:
javascript
// src/common/extensions/biliBiliNode.js
const BiliBiliNode = Node.create({
name: 'BiliBili',
draggable: true, // 还贴心地加上了拖拽功能
addPasteRules() {
return [
nodePasteRule({
// 这正则写得比我自己写的都优雅
find: /^(https?:\/\/)?(www\.|player\.)?(bilibili\.com\/video\/)(BV[0-9a-zA-Z]*)[?/](.+)?$/g,
type: this.type,
getAttributes: match => {
return {src: match[4]} // 精准提取 BV 号
},
}),
]
},
renderHTML({HTMLAttributes}) {
const vid = HTMLAttributes.src;
HTMLAttributes.src = `//player.bilibili.com/player.html?bvid=${vid}&page=1`
return [
'div',
{ 'data-bilibili-video': vid },
['iframe', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)],
];
},
});
我当时的表情:😮

这代码不仅能跑,而且考虑到了各种 B站链接格式,还自动把链接转成嵌入式播放器。我自己写的话,光那个正则表达式就得调半天。
从那以后,真香。
我是怎么和 AI 搭伙干活的
混了一年之后,我总结出了一套"人机协作"的野路子:
1. 大事找 AI 商量,小事自己瞎搞
架构层面的决策,我会先让 AI 给我分析利弊。比如全文搜索这个功能,我最开始想的是:不就是遍历文件然后 indexOf 嘛,多大点事儿。
AI 说:兄弟,你这样一百个文件还行,一千个文件你等着卡死吧。
然后它给我科普了 SQLite FTS5(全文搜索引擎),还顺手写了这么一套:
javascript
// electron/dbManager.js
createTables() {
// 使用 WAL 模式,AI 说这样性能好(我也不知道为啥,但它说得对)
this.db.pragma('journal_mode = WAL');
// 创建全文搜索虚拟表
this.db.exec(`
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
title,
content_text,
content='notes',
content_rowid='rowid'
)
`);
// 触发器:笔记更新时自动更新索引
// 这个我自己肯定想不到,手动维护索引迟早出 bug
this.db.exec(`
CREATE TRIGGER IF NOT EXISTS notes_ai AFTER INSERT ON notes BEGIN
INSERT INTO notes_fts(rowid, title, content_text)
VALUES (new.rowid, new.title, new.content_text);
END;
`);
}
事实证明这决策太对了。现在几百篇笔记搜索,毫秒级响应,丝滑。
2. 复杂功能拆着来,别想一口吃成胖子
[[双向链接]] 是我做过最复杂的功能之一。一开始我跟 AI 说"我要做个双向链接",它给我生成了一大坨代码,我直接懵了。
后来学聪明了,拆成小任务:
- 第一步:识别
[[]]语法 - 第二步:把它变成可点击的链接
- 第三步:点击后跳转
- 第四步:输入时自动补全
- 第五步:不存在的链接显示红色
一步一步来,每步都能测,出了 bug 也知道是哪儿的问题。
javascript
// src/common/extensions/internalLinkExtension.js
addKeyboardShortcuts() {
return {
// 用户输入第二个 ] 时触发
']': ({ editor }) => {
const textBefore = /* 获取光标前的文本 */;
// 正则匹配 [[链接名
const match = textBefore.match(/\[\[([^\]]+)$/);
if (match) {
// 把文本替换成链接节点
editor.chain()
.deleteRange({ from: start, to: end })
.insertContent({
type: this.name,
attrs: { target: match[1], exists: false },
})
.run();
// 顺便检查一下这个链接指向的笔记存不存在
this.checkLinkExists(editor, match[1]);
return true;
}
return false;
},
};
}
这种"化整为零"的方式,让我这个半吊子也能驾驭复杂功能。
3. 知识图谱:装X利器
说实话,做知识图谱纯粹是因为看 Obsidian 的图谱太酷了,我也想要。
D3.js 力导向图?听都没听过。但 AI 懂啊:
javascript
// src/pages/graph/GraphView.jsx
const GraphView = () => {
// 标签不同颜色,看着就专业
const TAG_COLORS = [
'#0f7b6c', '#2563eb', '#dc2626', '#9333ea',
'#ea580c', '#0891b2', '#65a30d', '#db2777',
];
// 点击标签筛选,还要保留关联节点(这个逻辑我想了半天,AI 秒出)
const filteredData = React.useMemo(() => {
if (selectedTag) {
const filteredNodeIds = new Set(
nodes.filter(n => n.tags?.includes(selectedTag)).map(n => n.id)
);
// 关联节点也要显示,不然图就断了
links.forEach(link => {
if (filteredNodeIds.has(link.source)) {
filteredNodeIds.add(link.target);
}
});
// ...过滤逻辑
}
return { nodes, links };
}, [graphData, selectedTag]);
return <ForceGraph2D graphData={filteredData} /* 各种配置 */ />;
};
3. 对TRAE问自己项目与其它Obsidian的区别,还需要什么功能点

markdown
## 缺失功能判断
- 最亟需补齐的功能是"本地安全与隐私保护":缺少应用级锁定、本地数据/设置加密,以及对敏感凭证(AI API Key、代理密码、WebDAV 账号)的安全存储。
- 当前敏感信息以明文保存在设置文件,且存在 `webSecurity: false` 的使用场景;这对用户数据安全与合规存在风险。
## 功能目标
- 引入"Vault 安全模式":在桌面端提供应用锁定、凭证安全存储、关键设置加密与自动锁定机制。
- 跨平台安全存储:macOS 使用 Keychain、Windows 使用 DPAPI、Linux 使用 libsecret;统一封装为主进程安全服务。
- 保障体验:默认不影响现有工作流;用户可一键启用,支持自动锁定与解锁流程。
## 技术实现
- 依赖与方案:
- 使用 `keytar` 封装系统级安全存储,保存 API Key、代理密码、WebDAV 凭证。
- 使用 `crypto` 的 AES-GCM(或 `libsodium-wrappers`)对本地 `setting.json` 中的敏感字段进行字段级加密;密钥以系统安全存储保护。
- 初期不改动 `better-sqlite3` 数据库文件结构;后续独立评估 SQLCipher 全库加密与 FTS5 兼容性。
- 主进程服务:
- 新增 `secureStore` 模块(getSecret/setSecret/deleteSecret),统一多平台实现与错误处理。
- 新增 `vaultManager`(enable/disable/lock/unlock/isLocked),管理主密码(可选)、自动锁定计时、进程状态。
- IPC:暴露 `vault:*` 与 `secureStore:*` 接口至预加载;所有调用均白名单校验与输入校验。
- 预加载层:
- `contextBridge.exposeInMainWorld` 增加 `vault` 与 `secureStore` API;保持最小授权面。
- 渲染端 UI:
- 设置页新增"安全"分区:启用 Vault、设置主密码(可选)、自动锁定时长、清除凭证。
- 头部新增"锁定应用"入口与状态指示;锁定态显示解锁面板(主密码或系统生物识别)。
- 数据迁移:
- 首次启用 Vault 时,将 `setting.json` 中的敏感字段迁移到 `secureStore`,并以加密占位符写回;生成一次性备份并提示用户校验。
## 流程与状态
- 首次启用:用户选择启用 → 可设置主密码 → 生成并存储加密密钥 → 迁移敏感数据。
- 应用启动:检测 Vault 状态;如启用则进入锁定态,解锁后加载设置与服务。
- 自动锁定:触发条件包括闲置超时、系统睡眠/唤醒、窗口最小化;解锁后恢复会话。
## 测试与验证
- 单元测试:`secureStore` 的多平台行为(通过 mock)、加解密正确性与错误路径覆盖。
- 集成测试:临时工作空间与设置文件迁移流程的回滚与容错验证。
- 安全检查:确保不在日志中输出密钥/敏感数据,渗透测试 checklist(路径校验、IPC 输入校验、预加载最小化)。
## 文档与配置
- README 与设置说明:新增"安全与隐私"章节、启用步骤与注意事项;统一技术版本与许可证声明。
- 开发文档:主进程模块接口、预加载白名单、错误码约定。
## 后续扩展
- 评估数据库全库加密(SQLCipher)与 FTS5 的兼容与替代方案。
- WebDAV 端到端加密通道(本地加密后再同步),以及冲突解决策略。
- 生物识别集成(macOS Touch ID、Windows Hello)与解锁体验增强。
翻车现场
当然也不是一路顺风,翻车的时候也不少。
翻车一:AI 的记性不如鱼
跨几次对话之后,AI 就开始"失忆"了。之前说好的变量命名规范?忘了。文件组织结构?什么结构?
后来我学乖了,专门写了个 README.md 文件,把项目架构、代码规范、重要决策全记下来,每次对话先让 AI 读一遍。相当于给它发了个"员工手册"。
翻车二:在 Mac 上跑得好好的......
Windows 用户:你的路径分隔符有问题。
我:???
AI 写的 path.join() 没问题,但有几个地方手动拼的 / 就出事了。现在我每次都会问一句:"这个在 Windows 上能跑吗?"
一点感悟
折腾了一年,最大的感悟就是:
AI 是外挂,不是代打。
它能让你 10 倍速写代码,但不能替你想清楚"要写什么"。架构设计、用户体验、产品方向------这些还得自己来。AI 只是把"实现"这个环节大大加速了。
另外就是学习方式变了。以前是先花两周看文档,再花两周写 demo,最后才敢动手做项目。现在是反过来------先干,不懂就问,边做边学。我对 Electron、Tiptap、SQLite 的理解,比任何时候都深,因为每个知识点都对应着一个实际问题。
最后说一句:有人觉得 AI 写代码是"作弊",我不这么看。
工具嘛,用就完了,现在自己用,有啥功能让TRAE给我写,也不用担心无人维护,哈哈哈哈。

对 FireFire 感兴趣可以去 GitHub 看看。更新日志:




