feat(popup): 重做扩展云同步中心与项目文档

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Developer
2026-03-18 00:28:14 +08:00
parent 5d0611de60
commit a7ff557942
4 changed files with 1080 additions and 125 deletions

700
PROJECT_ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,700 @@
# 涩花塘磁力助手 - 项目架构与部署说明
> 更新时间2026-03-14
> 说明:本文档描述当前项目的整体架构、核心数据流、缓存策略、云同步设计、线上部署信息(**不包含任何敏感凭据**),以及当前已知问题与优化方向。
---
## 1. 项目概览
本项目由两部分组成:
1. **Chrome 扩展端**
负责在涩花塘论坛页面中:
- 识别列表页 / 帖子页
- 批量抓取帖子与磁力链接
- 本地缓存帖子、范围快照、页快照、磁力结果
- 展示搜索结果、缓存总览、收藏夹、云同步入口
2. **云端共享缓存服务**
负责:
- 共享线程缓存shared thread cache
- 共享范围缓存shared coverage cache
- 共享页缓存shared page cache
- 覆盖规划coverage planning
- 私有保险柜vault
- 账号注册 / 登录 / 鉴权
---
## 2. 目录结构
### 扩展端根目录
- `manifest.json`Chrome 扩展清单MV3
- `content.js`:内容脚本,挂载 UI、执行抓取、合并缓存、结果展示
- `background.js`Service Worker负责 IndexedDB、本地状态、云接口、跨页请求
- `popup.html` / `popup.js`:扩展独立云同步中心 + 快捷复制入口
### 服务端目录
- `server/package.json`:服务端依赖与脚本
- `server/src/index.js`Fastify 入口
- `server/src/config.js`:环境变量配置
- `server/src/db.js`MySQL 连接池
- `server/src/redis.js`Redis 连接与 JSON 缓存
- `server/src/crypto.js`AES-GCM 加密与哈希
- `server/src/auth.js`:认证辅助逻辑
- `server/src/routes/auth.js`:注册 / 登录 / me / logout
- `server/src/routes/vault.js`:私有保险柜 push / pull
- `server/src/routes/shared-cache.js`:共享缓存查找 / 写入 / coverage planning
- `server/sql/001_init.sql`:数据库初始化表结构
---
## 3. 扩展端架构
### 3.1 页面层content.js
`content.js` 负责:
- 判断当前页面是:
- 列表页forumdisplay / forum-x-y.html / normalthread tbody
- 帖子页thread-xxx / tid=xxx
- 创建浮动面板 UI
- 管理:
- 关键词搜索
- 页码范围
- 速度模式
- 结果列表
- 收藏页
- 缓存页
- 云同步页入口
- 调用后台:
- 读取 / 保存本地缓存
- 读取 / 保存进度状态
- 触发云同步相关动作
### 3.2 后台层background.js
`background.js` 是当前项目的核心调度层,负责:
- IndexedDB 缓存存取
- 云缓存接口调用
- 共享缓存 planning 调用
- 上传抑制hash 去重 + TTL 节流)
- 本地历史缓存回填到云端
- 私有保险柜加解密
- 云账号登录状态维护
### 3.3 本地存储层
当前本地存储分三类:
1. **IndexedDB结构化缓存**
- `threads`
- `coverages`
- `pageCoverages`
2. **chrome.storage.local扩展私有存储**
- 收藏夹
- 搜索历史
- 云同步状态
- 上传元数据去重表
- 进度状态
3. **运行时内存态**
- 当前抓取状态
- session backup 临时状态
---
## 4. 服务端架构
### 4.1 服务端职责
云服务现在不仅是“存数据”,还承担:
- 共享缓存存储
- 去重写入
- coverage planning
- Redis 缓存 planning 结果
- 账号认证
- 私有保险柜同步
### 4.2 路由职责
#### 认证
- `POST /api/auth/register`
- `POST /api/auth/login`
- `GET /api/auth/me`
- `POST /api/auth/logout`
#### 私有保险柜
- `POST /api/vault/push`
- `POST /api/vault/pull`
#### 共享缓存
- `POST /api/shared-cache/threads/lookup`
- `POST /api/shared-cache/threads/upsert`
- `POST /api/shared-cache/coverages/lookup`
- `POST /api/shared-cache/coverages/upsert`
- `POST /api/shared-cache/pages/lookup`
- `POST /api/shared-cache/pages/upsert`
- `POST /api/shared-cache/coverages/plan`
#### 健康检查
- `GET /health`
- `GET /ready`
---
## 5. 本地缓存模型
### 5.1 `threads`
存储唯一帖子级信息:
- `forumKey`
- `threadKey`
- `url`
- `title`
- `lastSeenAt`
- `magnets`
- `lastMagnetSyncAt`
特点:
- 同一板块 + 同一帖子只保留一份
- 线程磁链缓存优先从这里命中
### 5.2 `coverages`
存储范围级快照:
- `forumKey`
- `startPage`
- `endPage`
- `strategy`
- `frontRefreshPages`
- `threadKeys`
特点:
- 表示某个页范围对应的帖子集合
- 用于 exact coverage / shifted coverage / 历史 coverage 碎片复用
### 5.3 `pageCoverages`
存储页级快照:
- `forumKey`
- `page`
- `threadKeys`
特点:
- 用来组装连续页块
- 当前大范围命中优化的重要基础
---
## 6. 云端缓存模型
### 6.1 共享线程缓存 `shared_thread_cache`
- 唯一键:`(forum_key, thread_key)`
- 数据库存储加密AES-GCM
- 用于跨用户复用帖子级磁链结果
### 6.2 共享范围缓存 `shared_coverage_cache`
- 唯一键:`(forum_key, start_page, end_page, strategy)`
- 用于整段范围的覆盖规划
### 6.3 共享页缓存 `shared_page_cache`
- 唯一键:`(forum_key, page)`
- 用于连续页块拼装
### 6.4 私有保险柜 `vault_items`
- 用户级密文存储
- 当前用于:
- 收藏夹
- 搜索历史
- UI 设置
- 进度状态
---
## 7. 抓取流程(当前实际运行路径)
### 7.1 点击“开始获取”后的流程
1. 读取页码范围 / 关键词 / 速度配置
2. 构建 `searchContext`
3. 显示:
- `正在规划缓存:检查本地缓存 / 云端规划 / 复用块...`
4. 调用 `getCachedCoveragePlan(...)`
5. 依次判断:
- exact coverage
- assembled page coverage
- 服务端 planning
- cachedBlocks
- shiftedCoverage
6. 对缺口区间执行 live 抓取
7. 结果与缓存合并后,再写回本地与云端
### 7.2 实际搜索执行路径
主要函数:
- `fetchFromPage(...)`
- `fetchLivePageRange(...)`
- `processCachedThreadBatch(...)`
- `applyCachedMagnetHits(...)`
---
## 8. 去重与上传抑制策略
### 8.1 本地去重
- 线程去重:`normalizeCachedThreads()`
- 磁链去重:`normalizeMagnetList()`
- coverage 合并去重:`mergeCoverageThreads()`
- coverage 保存前合并:`mergeCoverageThreadLists()`
### 8.2 云端去重
数据库唯一索引 + `ON DUPLICATE KEY UPDATE`
### 8.3 上传抑制
本地维护 upload meta
- `threads`
- `coverages`
- `pages`
每类记录:
- `payloadHash`
- `lastUploadedAt`
TTL
- 线程10 分钟
-30 分钟
- 范围60 分钟
作用:
- 降低重复上传
- 降低重复加密
- 降低数据库写入压力
---
## 9. 当前“智能更新”逻辑
### 已实现
1. front refresh从第一页开始时可刷新前段
2. shiftedCoverage 复用
3. page cache block 复用
4. intersecting coverage fragments 复用
5. 服务端 coverage planning
6. Redis 缓存 planning 结果
### 当前仍不够理想的点
1. **thread cache 很多,但未完全反向沉淀成 page/coverage 索引**
这会导致“明明有很多历史线程缓存,但大范围规划不够聪明”。
2. **coverage 合并仍然偏保守**
少量前页更新后,虽然已经补了历史 coverage 合并,但仍建议继续增强“旧帖保留连续性”。
3. **前段刷新策略仍是经验型策略**
当前已从“固定刷新前 20 页”改为“前面没有缓存覆盖才刷新”,但仍属于启发式策略。
4. **启动前规划仍然是同步等待**
现在已经加了状态提示,但未来可以做:
- 本地快速规划优先
- 云端规划异步补充
---
## 10. 线上部署信息(不含敏感凭据)
### 服务器基础信息
- 公网 IP`47.238.173.98`
- 域名:`s.52oai.com`
- 系统CentOS 7当前会话已确认
- 部署方式Nginx + PM2 + Node.js + MySQL + Redis
- 面板宝塔面板BT Panel
### 当前服务端组成
- Nginx反向代理入口
- Node 服务:`magnet-cloud-cache`
- PM2进程守护
- MySQL主数据存储
- Rediscoverage planning 结果缓存
### 线上访问入口
- `https://s.52oai.com/health`
- `https://s.52oai.com/ready`
### Redis 状态
当前已验证:
- Redis 可连接
- 可写入/读取 JSON
- coverage planning key 已落库
---
## 11. 当前安全边界
### 已完成的安全改造
1. 云同步登录/注册 UI 已迁移到扩展独立页面
2. 收藏/搜索历史已迁移到扩展私有存储
3. session 进度备份已不再依赖页面 `sessionStorage`
4. shared-cache 写接口已加写入令牌鉴权
5. shared-cache 已避免旧写覆盖新写
### 仍建议后续加强
1. `vaultKeyBase64` 改为 session-only
2. auth/vault/shared-cache 更细粒度限流
3. 服务端请求体大小再收紧
4. 共享缓存写审计日志
---
## 12. 当前最值得继续优化的方向
### P1 - 正确性优先
1. **thread cache 反向沉淀成 page/coverage 索引**
这是目前提升“大范围缓存命中率”的最高价值项。
2. **coverage 合并策略继续增强**
尤其是前段少量更新后,历史旧帖不应被挤出当前范围搜索。
3. **规划器结果可观测化**
建议增加 debug summary
- 命中 exact coverage
- 命中 page blocks 数
- 命中 intersecting coverage 数
- 实际缺口页数
### P2 - 性能优先
1. 本地快速规划优先,云端 planning 异步补充
2. planning 结果本地短时缓存
3. 回填队列分批化
---
## 12.1 当前抓取合并 / 去重 / 智能更新逻辑复盘
### 一、当前逻辑里已经做对的部分
1. **线程级去重已经明确**
- 本地通过 `threadKey` 去重
- 云端通过 `(forum_key, thread_key)` 唯一约束去重
2. **磁链级去重已经明确**
- 本地通过 `normalizeMagnetList()` 去重
- 云端共享缓存目前按线程保存,磁链集合在单线程内部去重
3. **coverage 规划已经从“只看精确范围”进化为多层来源**
当前 `getCachedCoveragePlan()` 已经综合:
- exact coverage
- assembled page coverage
- 服务端 planning
- cachedBlocks页块
- intersecting coverages相交范围碎片
- shiftedCoverage
4. **上传抑制已经开始发挥作用**
- thread/page/coverage 都有 upload meta
- hash + TTL 可以减少重复上云
### 二、当前逻辑不够理想的核心点
#### 1. 线程缓存与页/范围索引仍然是“半脱节”
这是目前最关键的问题:
- `threads` 里可能已经积累了大量帖子与磁链
- 但这些历史数据没有系统性地回灌成:
- `pageCoverages`
- `coverages`
结果就是:
> 看起来缓存很多,但真正能参与“大范围规划”的缓存块不够多。
#### 2. 智能更新仍然偏启发式,而不是差异驱动
当前 front refresh / shiftedCoverage 还是基于:
- 从第 1 页开始时,倾向刷新前段
- 历史范围快照的最近性
但它缺少真正的:
- 基于“帖子是否变化”的差异判断
- 基于线程游标 / 内容指纹 / 页指纹 的更新模型
#### 3. coverage 合并虽然已经补强,但仍然不够结构化
当前已经补了:
- 保存新 coverage 前,合并历史相交 coverage 的线程
但这个策略仍是:
- 按线程集合合并
- 不是按“真实页结构”或“线程页位置偏移”合并
所以在论坛前段轻微更新时,仍可能出现:
- 范围快照连续性不足
- 旧帖可见性波动
#### 4. 服务端 planning 已加入,但仍然是“辅助规划器”
现在服务端已经能返回:
- `exactCoverage`
- `cachedBlocks`
- `shiftedCoverage`
但扩展端仍保留了大量本地规划逻辑,导致:
- 本地规划与服务端规划并存
- 逻辑复杂度上升
- 调试成本高
### 三、当前最值得优先继续优化的技术方向
#### A. `threads -> pageCoverages / coverages` 反向沉淀
这是正确性和命中率的第一优先级优化。
目标:
- 当系统手里已经有大量 thread cache 时
- 能定期 / 按需将其重建为:
- page coverage block
- coverage fragment
收益:
- “缓存明明很多却命中不上”的问题会明显缓解
#### B. 引入“线程或页面指纹”作为智能更新依据
例如:
- 页面线程列表 hash
- 范围线程集合 hash
- 线程集合版本号
这样 front refresh 就能从“经验刷新”变成:
- 先比对指纹
- 只有前段真的变化才刷新
#### C. 最终把 planning 统一到服务端主导
建议目标不是“双规划器”,而是:
- 服务端负责 coverage planning
- 扩展端只负责执行计划
- 本地逻辑只保留兜底回退
这样架构会明显更稳。
### P3 - 运维优先
1. 共享缓存保留策略 / 归档策略
2. 写入审计与异常监控
3. 密钥轮换机制
---
## 13. 当前版本的整体评价
### 已经具备的能力
- 本地线程 / 范围 / 页缓存
- 云端共享缓存
- 私有保险柜
- 上传抑制与 TTL 节流
- coverage planning + Redis planning cache
- 扩展端 UI / 云同步中心 / 收藏 / 搜索历史
### 当前最核心的短板
> 缓存数据已经很多,但“如何把这些缓存组织成最优复用计划”仍然不够强。
也就是说,当前系统最难的不是“存缓存”,而是:
> **把已有缓存规划成正确、完整、连续的搜索路径**
---
## 14. 文档使用建议
如果后续你继续迭代项目,建议把本文档当成:
1. **新人接手说明**
2. **线上部署说明**
3. **缓存/同步逻辑总览**
4. **后续重构路线图**
---
## 15. 敏感信息说明
本文档**不记录**以下信息:
- SSH 密码
- MySQL 密码
- write token
- 加密密钥
- `.env` 明文内容
这些信息应只保留在安全的部署环境与秘密管理系统中。
---
## 16. Chrome 分发与更新能力边界
结合当前平台限制和架构评估,下面是**真实可行**与**不可行**的边界。
### 16.1 对普通 Chrome 用户,不可直接做到的事
以下能力在普通非企业托管 Chrome 中,**不现实或不受支持**
1. **从网站自动把扩展装进 Chrome**
2. **通过主页密码后,静默安装 CRX**
3. **普通用户使用自托管 CRX 自动更新**
也就是说:
> `s.52oai.com` 可以做“分发引导页”,但不能真正实现“输密码后自动装到 Chrome 里”。
### 16.2 最现实的分发方式
对于普通用户,最推荐:
1. **发布到 Chrome Web Store建议 unlisted**
2. `s.52oai.com` 做密码门禁页
3. 门禁通过后展示:
- CWS 安装链接
- 安装说明
- 使用说明
这样可以获得:
- 官方安装路径
- Chrome 自动更新
- 最低用户支持成本
### 16.3 自托管更新什么时候才成立
只有在以下场景,自托管更新才是现实方案:
- **企业托管 Chrome**
- 管理员通过策略安装
- 使用企业设备 / 组织统一管理浏览器
这不是普通公网用户场景。
### 16.4 当前项目建议的分发策略
如果未来要正式分发,推荐顺序:
1. **Chrome Web Store最好 Unlisted**
2. `s.52oai.com` 做密码门禁与引导页
3. 扩展内做“最低支持版本”检查
4. 如果版本太低,则提示用户去商店更新
### 16.5 站点密码的真实作用
主页密码(例如 `123456`)只能充当:
- 引导门槛
- 简单访问控制
- 降低无关访问
但它**不能视为真正安全边界**。真正的权限控制仍然必须放在:
- 后端账号系统
- API 鉴权
- 服务端授权逻辑
---
## 16. Chrome 分发与更新能力边界(部署到主页的现实约束)
### 16.1 对普通 Chrome 用户,不能直接做到的事
对于**普通、非企业托管**的 Chrome 用户,当前不支持:
1.`s.52oai.com` 网页直接自动安装扩展
2. 从自有网站静默安装 CRX
3. 对普通用户使用自托管 CRX 做自动更新
也就是说:
> 网站可以做“入口页 / 密码门禁页 / 引导页”,但不能真正代替 Chrome 官方安装渠道完成自动安装。
### 16.2 对普通用户最现实的方案
最可行方案是:
1. 发布到 **Chrome Web Store建议 Unlisted**
2. `s.52oai.com` 作为密码门禁页
3. 输入密码后展示:
- Chrome Web Store 安装链接
- 使用说明
- 更新说明
这样可以获得:
- 标准安装体验
- Chrome 自动更新
- 最低的用户支持成本
### 16.3 自托管自动更新什么时候可行
只有在:
- 企业托管 Chrome
- 管理员策略安装
- 受管设备/受管浏览器环境
这种情况下,自托管 CRX + update manifest 才是现实路径。
### 16.4 当前项目推荐的分发模式
推荐顺序:
1. **Chrome Web StoreUnlisted** 作为主分发渠道
2. `s.52oai.com` 做密码门禁 + 安装引导页
3. 扩展内调用服务端 `/ext/config`(后续可实现)检查最低支持版本
4. 如果版本过低,提示用户跳转到商店升级
### 16.5 密码门禁的真实作用
密码门禁只能起到:
- 隐藏安装入口
- 控制谁能看到链接
但它**不能视为真正的安全边界**。真正的权限控制必须放在:
- 后端账号体系
- API token / 登录态
- 服务器侧权限判断