Qbao 项目全貌与专业点评(2026-09-06 · v3.37.0 快照)
快照基线:HEAD `91ff279` / tag `v3.37.0` / 工作树干净。
数据来源:仓库实测(git log、CI 配置、路由清单、测试统计、代码规模扫描)+ REVIEW-2026-08 审计(v3.29 全量审计及其 T1–T23 整改记录;该文档含早期部署痕迹,已归档 local/archive/ 并移出公开树)+ `local/log.md` 运行日志。
隐私纪律:本文不含任何真实主机地址/密钥,一律占位符。
⚠️ 基础设施部分已过时(2026-09-12 注):本文是 2026-09-06 的时点快照,其中「生产形态」等描述
(nginx + VPN 内网模式 + 大陆源站)反映的是迁港之前的架构。2026-09-10 服务已全量迁至香港单机
(Caddy 同机 TLS + 静态直出 + 反代)。当前架构事实源为 ARCHITECTURE.md,
本文其余部分(项目定位、代码规模、工程实践点评)作为历史快照保留,未随迁港改写。
📌 本文 §5 的 P0/P1 清单已有部分被后续整改关闭,见文末 §9「对本文清单的处置回执」;
新发现与新整改统一登记在 ARCHITECTURE.md §9(R1–R12),本文不再逐条维护。
1. 项目定位
一句话:面向医学生个人与好友小组的「AI 出题 → 间隔复习 → 考试模拟 → 数据复盘」一体化学习引擎;网页(SPA)与 Windows 桌面(Electron)双形态;代码托管 GitHub,但运行与分发完全自托管。
- 核心闭环:上传资料(PDF/文本/图片)→ AI 多 Provider 生成题目 → 章节轮次刷题(SRS 间隔复习)→ 看板/答题历史/错题本/大考卷 → AI 错题讲解 → 导入导出与批量编辑复盘资料。
- 协作层:好友 / 群聊 / 文件图片消息 / 题目与题库分享 / 聊天内直接答题 / 消息撤回。
- 平台层:注册制账号、JWT+bcrypt、积分经济(台账/学期清零/防滥用)、成就系统、反馈工单闭环、公告、下载分发站(/dl + 自托管更新源)。
2. 全景速览(数据化)
| 维度 |
数值 |
| 生命周期 |
2026-04-29(单文件 v1.0)→ 2026-09-06(v3.37.0),约 130 天 |
| 版本演进 |
v1.0 → v3.37.0;26 个 git tag(自 v3.25.1 起),平均约 5 天/版 |
| 提交 |
138 个(含 2026-07 历史重写后的基线),工作树干净 |
| 代码规模 |
约 3.6 万行业务代码:app/src 21.7K、server/src 6.6K、server/test 2.6K、desktop 4.7K(含 lock)、scripts 0.7K、tools/e2e 1.3K、docs 1.2K、.github 0.25K;跟踪文件约 390 个 |
| 自动化测试 |
433 例:app 239(24 文件)/ server 183(36 文件)/ scripts 6 / desktop 5;CI 全绿 |
| 后端 |
Express 4 + pg;14 个路由模块、约 105 个端点;13 个版本化数据库迁移(001–013,schema_migrations 追踪) |
| 前端 |
Vue 3 + Vite + Pinia;5 视图 / 约 60 组件 / 11 store / 约 30 服务模块;singlefile 构建产物约 550KB,网页与桌面 file:// 共用 |
| 桌面端 |
Electron 36 + electron-builder NSIS,安装包约 85MB;manifest-first 双渠道(stable/beta)自托管更新与下载 |
| AI 层 |
4 类 Provider(ECNU / DeepSeek / OpenAI 兼容 / Gemini),流式 SSE 缓冲、后台任务队列、章节生成锁、错题讲解、成功才计费 |
| 生产形态 |
nginx + systemd(非 root + NoNewPrivileges)+ PostgreSQL;VPN 内网模式为主 + 公网 80;双健康端点 |
3. 系统构成与架构剖析
3.1 拓扑
```
浏览器(app/ SPA,singlefile)
│ /api/v1/*、业务 /uploads 端点(鉴权)
▼
Nginx(静态托管 + 反向代理)
│ /api → 127.0.0.1:3000
▼
server/ Express API(systemd,非 root)
├── PostgreSQL(核心业务整包 JSONB + 关系表)
├── 外部 AI API(ECNU/DeepSeek/Gemini/OpenAI,后端代理,Key 用户自持)
└── downloads/(桌面端安装包储藏室,manifest 驱动)
桌面端 Electron → 加载本地 app/ → fetch RUNTIME.apiBase(config 注入)→ 同一线上 API
└── electron-updater ← 自托管 generic feed(update/stable/latest.yml)
```
设计要点:同源 API + singlefile 前端使网页与桌面共用一套产物(桌面免“部署”);分发与更新链路自托管,GitHub 仅做 CI 与 Release 归档。
3.2 前端(app/)
- v3.27 完成从“手写 DOM 单文件 20 模块”到 Vue 3 + Vite + Pinia 的全量组件化重构,并保持 singlefile 兼容桌面 file://。
- 分层清晰:`stores/`(状态)+ `services/`(纯逻辑/API 封装)+ `components/features/*`(业务组件族)+ `views/` + `charts/`(零依赖 SVG 图表)。
- 数据架构三位一体:`persistence.js`(localStorage 骨架 + IndexedDB 大字段分流 + 配额自愈)、`sync.js`(rev 乐观锁引擎)、`stateDb.js`(IDB 行键按账号分区)。
- 亮点模块:subjectStats 统计引擎(单一权威源)、同步引擎、聊天虚拟滚动、导入导出、startActions 单槽位状态机、secureStore(桌面 DPAPI)。
3.3 后端(server/)
- 路由层 v2 收敛:全部 asyncHandler + zod schemas + 统一 ApiError/errorHandler;14 个路由模块约 105 端点。
- 安全基线:JWT(启动校验强度)+ bcryptjs;登录/全局 express-rate-limit;CORS 白名单;上传四通道白名单 + 魔数嗅探 + 附件头 + 不静态暴露 /uploads;CSP 客户端 meta;AI Key 不落库(请求头透传 + 状态净化双保险)。
- AI 层成熟:openaiCompatible 工厂 + gemini 适配器(SSE 跨 chunk 缓冲 + 超时/取消区分);任务队列 FOR UPDATE SKIP LOCKED + 每用户上限 + 取消竞态防护 + 重启标记失效;章节生成锁防并发重复出题;finalizer 自检补题。
- 积分系统:points_ledger 台账(unique 幂等)+ balance 每日对账(keyset 分页)+ 学期清零(advisory lock)+ 答题结算行锁事务 + 成功才计费。
3.4 数据模型与同步:本项目的“心脏”与“阿喀琉斯之踵”
- 模型:用户业务状态整包存 `user_data.state_json`(JSONB 单行),`rev` 自增做 CAS;答题会话、聊天、工单、分享、文件、积分台账独立关系表。
- 同步:GET/PUT 全量;2s 防抖提交 + v3.31 起空推跳过(指纹);rev 变化才拉取;409 冲突 → 实体级并集合并(同 id 本地优先)→ 重推;beforeunload keepalive 补推。
- 多账号隔离(v3.36/v3.37 两轮根治):登录门禁(弃匿名态)→ 账号键/IDB 分区/云端分离 → 切换整页重建 → 引擎属主守卫 → 会话令牌钉扎 + 写盘属主钉扎 + 跨标签 storage 守卫。E2E 实测双向零串账。
- 代价与风险:整包 JSONB + 并集合并 = 写放大(每答一题全量 PUT,空推跳过缓解但未根治);删除类操作无墓碑,云端残留会随任意端并集“复活”(v3.37 事件已实证:需人工清云端 + 先清本地);数据增长无分页/快照,单行体积存在上限风险(现有多轮次大账号约数百 KB 级,尚安全)。
3.5 桌面端与分发体系(v3.35 起,行业范式级)
- `scripts/publish-installer.js` + `installer-lib.js`(零依赖,6 例 node:test)。
- manifest.json(schemaVersion 1)= 唯一事实源,双渠道、多版本留存、sha256/sha512/日期/说明;支持 `promote –required`(强制门槛,触发器白名单)与 `retract`(熔断撤回:410 + 回退 + 弹窗引导)。
- 端点全家桶:manifest / latest / download(断点续传)/ update feed / stats / /dl 落地页 / /download 短链。
- 每次发布前滚动备份 manifest.json.bak;公网验收“逐字节下载 + digest 交叉核对”;版本 tag 与三端 package.json 断言(release.yml)。
- beta 通道:构建时 extraMetadata 覆盖版本号,不碰跟踪文件、不推 tag。
3.6 工程化体系
- CI(5 jobs):gitleaks 全历史扫描;后端 npm ci + 语法检查 + npm audit + vitest(forks 固定)+ eslint;前端 build(构建即语法门禁)+ 产物 CSP/伪协议冒烟 + vitest + eslint;tooling 零依赖脚本测试;desktop updater 纯函数测试。
- Release(Windows runner):tag 触发(prerelease 后缀不触发稳定版)→ 三端版本-tag 断言 → 前端 build → NSIS 打包 → 三要素存在性检查 → gh release。
- 发布纪律(DEVELOPMENT_FLOW.md):本地提交 → 部署 → 用户「测试通过」→ 才允许 push/tag/Release → 公网逐字节验证 → log.md 留档。版本号 JSON 正规升版(吸取 v3.34.1 文本替换事故教训)。
- 文档体系:README / ARCHITECTURE(删除线追踪技术债)/ DEVELOPMENT / DEPLOY / PUBLISHING / MOBILE_UX / DEVELOPMENT_FLOW(DoD 表)/ REVIEW 审计 / plans(P0–P3 轮次制)/ CHANGELOG / SECURITY / local/log.md 运行日志。
- 数据运营:破坏性操作前全库快照(pg_dump -Fc)+ 行级 JSON dump 双备份;账号级手术脚本(psql 校验 → node 脚本转换 → 复验);恢复路径存档。
4. 专业点评一:亮点(有证据的强项)
- 数据自洽意识(多数个人项目不具备):v3.37 确立“单一权威源 = 轮次 quizSets + 轮次内答案”,科目级=Σ章节由恒等式单测锁定;环形图绿弧与中心准确率数学恒等;跳过/主客观分离杜绝假值。这是数据产品思维:每个数字可验算。
- 同步正确性工程的坚持:v3.25 rev 乐观锁 → v3.31 空推跳过 → v3.36 账号隔离四层 → v3.37 身份钉扎三层。串号这种“环境依赖、难复现”的 bug 被用户实测→根因定位(内存属主 vs 活读 localStorage)→ 三层修复 + 12 例回归 + E2E 锁定,方法论完整。
- 测试文化:433 例覆盖统计/同步/持久化/积分并发/上传安全/updater;fake pool 不依赖真实 DB;CI 强制执行;规模只增不减(基线纪律)。
- 发布与分发工程达到商业软件水准:tag-版本断言、三要素检查、三重 digest 交叉验证、manifest 双渠道/强制/撤回/回滚、公网逐字节验收;自托管镜像解决国内分发,规避 GitHub 依赖。
- 安全整改执行力:CORS 全开→白名单、上传三漏洞→统一加固、admin 引导→env、CSP 收紧、systemd root→非 root、历史重写清敏感信息、gitleaks 入口。从 v3.29 审计到 T1–T23 全部落地有验收记录。
- 取舍清晰:匿名离线态 → 权衡后主动废弃(登录门禁),而不是留一个隐患的后门;迁移与兼容(旧键兼容读写/升级回退)考虑周到。
- 知识管理:版本快照归档(local/Version/)、运行日志、审计报告、轮次方案表——单人项目罕见的“组织记忆”。
5. 专业点评二:短板与风险(真实清单)
P0(建议尽快处理)
| # |
问题 |
现状与影响 |
| 1 |
公网形态无 TLS(http:80) |
JWT/密码在不可信网络上明文传输;主推 VPN 内网模式可缓解,但只要公网形态存在即为真实风险。建议 certbot 一键 + 强制跳转 HTTPS(DEPLOY §6 已有步骤,缺落地)。 |
| 2 |
备份自动化未实证 |
DEPLOY 写明每日 pg_dump + rsync,但服务器侧未见定时任务实证;最近为手动快照。应 cron + 保留策略 + 月度恢复彩排。 |
| 3 |
桌面 NSIS 未代码签名 |
SmartScreen 红屏、供应链信任缺失;按投放范围定级,至少文档明示。 |
P1(重要改进项)
| # |
问题 |
说明 |
| 4 |
可观测性缺失 |
仅 /health;无结构化日志、无指标、无告警。AI 任务/同步/下载统计已有数据雏形,上 pino + 指标端点 ROI 高。 |
| 5 |
E2E 未进 CI |
tools/e2e CDP 探针人工/会话内跑,未纳入 CI;核心链路(登录/隔离/看板)应至少一个 headless 冒烟 job。 |
| 6 |
JSONB 整包 + 并集合并 |
写放大仍存;删除“复活”需人工云端清理——建议服务端删除墓碑/收敛合并(已在 backlog)。单行体积应有警戒线监控。 |
| 7 |
Web 端 token/AI Key |
网页端仍 localStorage 明文(混淆级);桌面已 DPAPI。网页形态建议凭据内存态 + 会话短命化评估。 |
| 8 |
单机单实例 |
无 HA、无灾备演练;个人规模可接受,但要书面承认风险边界。 |
P2(中长期/体验面)
- ARCHITECTURE.md 前端章节仍描述“无框架手工 DOM”(v3.27 已重构),文档一致性需刷。
- AI worker 竞态/取消/重启清理的单测仍偏薄(部分已覆盖,可扩充并发模拟)。
- 无 TypeScript / Docker / pino(均已立项未实施);Express 4→5、multer 2、Electron 升级节奏需跟踪。
- 部署为手工 scp + 脚本,无 IaC;单点运维知识集中在一个人。
- 产品面:题库内容依赖个人导入体积(2000 题 CSV 待真机手检)、无 a11y/i18n、无多用户压测、桌面仅 Windows。
6. 评分卡(5 分制,主观但给依据)
| 维度 |
分 |
依据 |
| 发布/分发纪律 |
4.8 |
tag 断言、测试通过门禁、三重 digest、双渠道/撤回/回滚 |
| 数据一致性 |
4.5 |
单一权威源、恒等式锁定、rev CAS、身份钉扎 |
| 测试文化 |
4.2 |
433 例 + CI 强制 + 只增不减 |
| 文档 |
4.5 |
全套文档 + 修订追踪 + 运行日志 |
| 安全 |
3.5 |
多轮整改到位;TLS/签名/Web 明文待补 |
| 产品力 |
4.0 |
功能密度高、移动专项、看板专业度 |
| 可观测性 |
2.5 |
仅健康端点 |
| 规模化准备 |
2.0 |
JSONB 整包 + 单实例,明确服务个人/小组规模 |
7. 建议路线图(按 ROI 排序)
- HTTPS 化(certbot + 强制跳转 + HSTS)——半天工作量,最大安全收益。
- 备份自动化 + 恢复彩排(cron pg_dump / uploads rsync + 保留 N 天 + 月度演练,结果记 log.md)。
- E2E 冒烟进 CI(复用 tools/e2e 探针思路,headless 一档:登录→答题→看板数字闭环)。
- 服务端删除墓碑 + 并发收敛合并(根治“删除复活”,终结人工云端清理)。
- 可观测性(pino + /metrics + 告警;下载统计端点已示范)。
- 单行 JSONB 体积警戒线(sync 前体积审计 + 超限强制骨架化/拆表预案)。
- 文档一致性刷新(ARCHITECTURE 前端章节、ecosystem 路径对照)。
- 按投放范围决策:代码签名(用户增速明显时优先)。
8. 总体判断
定位:单人终身学习工具的“准专业软件”,在个人项目中属于头部水准——发布纪律、测试文化、数据自洽、安全整改执行力都明显高于同类;对照商业 SaaS 标准,差距集中在可观测性、数据模型规模化、TLS/签名与团队化治理。
一句话评价:以产品思维做架构、以运维思维做交付、以测试思维做数据的精品单人项目;其剩余风险不在代码质量,而在单点——单点运维、单点知识、单点服务器。每一项都可通过“自动化 + 文档化 + 演练”对冲,路线图见 §7。
9. 对本文清单的处置回执(2026-09-13 补记)
只记录「本文写过、现在结论变了」的条目;未列出的条目仍按原文视为未完成。
详细整改记录见 ARCHITECTURE.md §9(R1–R12)。
§5 P0
| 原条目 |
现状 |
| 1 公网形态无 TLS |
已关闭:2026-09-10 全量迁港,Caddy 同机 TLS 终结 + ACME 自动证书,且 HTTP 由 Caddy 跳转 HTTPS;服务器不再暴露明文入口 |
| 2 备份自动化未实证 |
部分:cron /etc/cron.d/qbao-backup 每日 04:00 双库 dump(保留 30 天)已落地并写入文档;月度恢复彩排仍缺,保留待办 |
| 3 桌面 NSIS 未代码签名 |
仍在(未变),按投放范围决策;文档已明示 |
§5 P1
| 原条目 |
现状 |
| 4 可观测性缺失 |
部分关闭:客户端全局错误已收口并上报(见 ARCHITECTURE §9 R6,落 journald);结构化日志与指标端点仍未做 |
| 7 Web 端 token/AI Key |
仍在:网页端仍 localStorage 明文;但本轮起所有出网请求统一经 effectiveToken()(不再有取到失效 token 的旁路),凭据短命化仍未做 |
§5 P2
| 原条目 |
现状 |
| ARCHITECTURE 前端章节仍写「无框架手工 DOM」 |
已关闭:迁港校准(v2)与本次复查(v3)后,§5.2 已按 Vue3+Vite+Pinia 描述 |
| AI worker 竞态/取消/重启清理单测偏薄 |
部分关闭:新增优雅停机用例(停机顺序/宽限超时/二次信号)与重启清理回归;并发模拟仍可扩充 |
| 无「代码引用的表/列必须在仓库 DDL 中可复现」的守卫 |
已关闭:schema.drift.test.js 双向夹逼(P0-2 的成因即此缺口漏检),并附「同一 method+path 不得重复注册」守卫(R4 的成因) |
| multer 上传错误一律 422 + 回显英文枚举 |
已关闭(R12):体积类改判 413 并给中文文案,业务文案不被覆盖 |
§7 路线图
1(HTTPS 化)已完成;5(可观测性)已启动(客户端错误上报);3/4/6/8 未动,仍按原优先级有效。