Files
WeReadBoard/docs/TECHNICAL_DOC.md
T

355 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 微信读书数据展示网站 - 技术文档
> 更新时间:2026-07-17 | 作者:WorkBuddy | 数据模型:完整阅读数据表
---
## 1. 项目概述
### 1.1 项目简介
本项目是一个个人读书数据展示网站,数据来源于微信读书。通过微信读书 API 拉取用户的阅读数据(书架、阅读统计、笔记等),存入本地数据库,并通过 Web 仪表盘进行可视化展示。
### 1.2 核心功能
| 模块 | 功能说明 |
|------|----------|
| 数据采集 | 从微信读书 API 拉取书架、阅读统计、笔记本数据,存入本地数据库 |
| 总览仪表盘 | 累计阅读时长、阅读天数、藏书量、笔记数等核心指标 |
| 数据图表 | 年度阅读趋势(柱状图)、24h 时段分布(折线图)、偏好分类(饼图)、偏好作者(条形图) |
| 读书排行 | 阅读时长最久的 20 本书卡片展示 |
| 书架 | 404 本书的网格展示,支持分类筛选和"仅看已读完" |
| 笔记概览 | 有笔记的书籍列表,点击查看划线和想法详情 |
| 书籍详情 | 点击书架书籍弹出详情(书名、作者、出版社、ISBN、评分、阅读进度) |
| 笔记详情 | 点击笔记书籍查看划线(按章节分组)和想法/点评 |
| 推荐页面 | 个性化推荐书籍 + 关键词搜索,数据入库 |
### 1.3 技术栈
| 层级 | 技术 | 说明 |
|------|------|------|
| 前端 | HTML5 + CSS3 + 原生 JavaScript | 无框架依赖,轻量高效 |
| 图表 | ECharts 5.5.0 | 年度趋势、时段分布、分类饼图、作者排行 |
| 后端 | Python Flask | 轻量级 Web 框架,提供 RESTful API |
| 数据库 | MySQL 5.7+(主)/ SQLite(采集) | MySQL 为生产数据库,31 张表完整覆盖官方 API,SQLite 用于数据采集中间存储 |
| 数据采集 | 微信读书 Agent Gateway API | 通过 weread-skills 技能提供的 API 接口,覆盖 8 份官方 API 文档 |
| 版本控制 | Git | dev 分支开发,master 分支发布,遵循 Conventional Commits |
---
## 2. 系统架构
### 2.1 整体架构图
```
┌─────────────────────────────────────────────────────────┐
│ 用户浏览器(前端) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 总览仪表盘│ │ 数据图表 │ │ 书架列表 │ │ 推荐搜索 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ └───────────┴─────┬─────┴───────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ 健康检查模块 │ │
│ │ (MySQL 连接检测) │ │
│ └────────┬────────┘ │
└─────────────────────────┼───────────────────────────────┘
│ HTTP / RESTful API
┌─────────────────────────┼───────────────────────────────┐
│ Flask 后端服务 │
│ │ │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ API 路由层 │ │
│ │ /api/overview /api/shelf /api/book/detail │ │
│ │ /api/recommend /api/search /api/health ... │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ db_required 装饰器 │ │
│ │ (连接管理 + 错误处理 + 503 告警) │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ PyMySQL 数据访问层 │ │
│ └───────────┬──────────────────┬──────────────┘ │
│ │ │ │
│ ┌───────────▼─────┐ ┌────────▼─────────┐ │
│ │ MySQL 数据库 │ │ 微信读书 API 代理 │ │
│ │ weread_dashboard│ │ (按需获取+入库) │ │
│ └─────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────┼───────────────────────────────┐
│ 数据采集层(独立运行) │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ fetch_data.py 采集脚本 │ │
│ │ 拉取书架/统计/笔记 → SQLite → migrate_to_mysql│ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 2.2 数据流设计
```
微信读书 API
│
▼
fetch_data.py(采集脚本)
│
▼
weread.db(SQLite 中间存储)
│
▼
migrate_to_mysql.py(迁移脚本)
│
▼
MySQL weread_dashboard(生产数据库)
│
▼
Flask app.py(后端服务,端口 8080)
│
▼
前端页面(ECharts 可视化)
```
**按需数据流**(用户点击书籍/笔记时):
```
用户点击 → Flask API → 微信读书 API(实时获取)→ 入库 MySQL → 返回前端
↓(API 失败时)
从 MySQL 读取缓存数据 → 返回前端
```
### 2.3 目录结构
```
weread-dashboard/
├── app.py # Flask 后端服务(MySQL 数据源)
├── fetch_data.py # 数据采集脚本(SQLite)
├── migrate_to_mysql.py # SQLite → MySQL 数据迁移脚本
├── schema_mysql.sql # MySQL 建表语句(含中文注释)
├── requirements.txt # Python 依赖
├── weread.db # SQLite 数据库文件(采集中间存储)
├── README.md # 项目说明
├── docs/ # 文档目录
│ ├── TECHNICAL_DOC.md # 技术文档(本文件)
│ └── METADATA_DOC.md # 元数据文档
├── templates/
│ └── index.html # 前端页面
└── static/
├── css/
│ └── style.css # 样式文件
└── js/
└── app.js # 前端逻辑
```
---
## 3. 后端 API 设计
### 3.1 API 接口列表
| 接口 | 方法 | 说明 | 数据来源 |
|------|------|------|----------|
| `/api/health` | GET | 健康检查(MySQL 连接状态) | MySQL |
| `/api/overview` | GET | 总览数据(核心指标) | MySQL |
| `/api/yearly-trend` | GET | 年度阅读时长时间序列 | MySQL |
| `/api/top-books` | GET | 阅读时长排行 TOP 20 | MySQL |
| `/api/categories` | GET | 偏好分类 | MySQL |
| `/api/authors` | GET | 偏好作者 TOP 20 | MySQL |
| `/api/time-distribution` | GET | 24 小时时段分布 | MySQL |
| `/api/shelf` | GET | 书架列表(分页) | MySQL |
| `/api/notebooks` | GET | 笔记本概览 | MySQL |
| `/api/read-stats` | GET | 阅读统计摘要 | MySQL |
| `/api/archives` | GET | 书单列表 | MySQL |
| `/api/book/detail` | GET | 书籍详情(按需) | 微信读书 API + MySQL |
| `/api/book/notes` | GET | 笔记详情(按需) | 微信读书 API + MySQL |
| `/api/recommend` | GET | 个性化推荐(按需) | 微信读书 API + MySQL |
| `/api/search` | GET | 搜索书籍(按需) | 微信读书 API + MySQL |
### 3.2 接口详情
#### 3.2.1 健康检查
```
GET /api/health
```
**响应(正常)**:
```json
{
"status": "ok",
"database": "connected",
"message": "MySQL 连接正常"
}
```
**响应(异常,HTTP 503)**:
```json
{
"status": "error",
"database": "disconnected",
"message": "MySQL 连接失败: ..."
}
```
#### 3.2.2 总览数据
```
GET /api/overview
```
**响应**:
```json
{
"total_read_time": 1223850,
"total_read_time_str": "339小时57分钟",
"read_days": 304,
"year_read_time": 849029,
"year_read_time_str": "235小时50分钟",
"year_read_days": 198,
"shelf_count": 404,
"finished_count": 12,
"notebook_count": 32,
"total_notes": 1709,
"regist_time": "2024-03-15",
"last_read_time": "2026-07-17",
"fetch_time": "2026-07-17 09:50:00"
}
```
#### 3.2.3 书架列表(分页)
```
GET /api/shelf?page=1&per_page=60&category=文学&finished=1
```
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| page | int | 1 | 页码 |
| per_page | int | 60 | 每页数量 |
| category | string | "" | 分类筛选(模糊匹配) |
| finished | string | "0" | "1"=只看已读完 |
#### 3.2.4 书籍详情(按需)
```
GET /api/book/detail?book_id=34615967
```
实时调用微信读书 `/book/info` + `/book/getprogress` API,入库后返回。API 失败时回退到数据库缓存。
#### 3.2.5 错误处理
所有 API 接口在 MySQL 连接失败时统一返回:
```
HTTP 503 Service Unavailable
{
"error": "数据库连接失败",
"detail": "具体错误信息",
"alert": "MySQL 数据库无法连接,请检查 MySQL 服务是否已启动。"
}
```
---
## 4. 关键设计决策
### 4.1 数据库选择
- **生产环境使用 MySQL**:支持并发访问、事务管理、完善的权限体系
- **采集层使用 SQLite**:轻量级,无需额外服务,适合单机数据采集
- **迁移脚本桥接**:`migrate_to_mysql.py` 负责 SQLite → MySQL 的数据同步
### 4.2 按需获取策略
书籍详情、笔记详情、推荐、搜索等数据采用**按需获取**策略:
- 用户点击时实时调用微信读书 API
- 获取成功后入库 MySQL 缓存
- API 调用失败时自动回退到数据库缓存
- 避免初始化时大量 API 调用,提升用户体验
### 4.3 健康检查与告警机制
- 后端提供 `/api/health` 接口检测 MySQL 连接状态
- 前端页面加载时首先调用健康检查
- 连接失败时显示固定告警横幅,阻止后续数据加载
- 使用 `db_required` 装饰器统一处理数据库连接异常
### 4.4 数据模型设计规范
基于微信读书官方 8 份 API 文档的完整字段分析,数据模型遵循以下设计规范:
**双列时间戳模式**:所有整型 Unix 时间戳字段(`INT UNSIGNED`)均伴随一个 `_dt TIMESTAMP` 列,例如 `update_time` ↔ `update_time_dt`。便于直接查询展示,同时保留原始时间戳用于排序和计算。
**审计列**:每张表统一维护 `created_at`(创建时间)和 `updated_at`(更新时间),使用 MySQL `DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP` 自动维护。
**索引设计原则**:
- 主键:业务主键优先(如 `book_id`),无自然主键时使用 `BIGINT AUTO_INCREMENT`
- 唯一约束:防止重复数据(如 `uk_highlights_bookmark(book_id, bookmark_id)`)
- 复合索引:按实际查询模式设计(如 `idx_highlights_chapter(book_id, chapter_uid)`)
- 排序索引:常用排序字段加 `DESC`(如 `idx_books_read_update_time(read_update_time DESC)`)
**表覆盖范围**:31 张表完整覆盖 8 份官方 API 文档:
- shelf.md → books, shelf_albums, shelf_meta, archives
- readdata.md → reading_stats, read_times, read_longest, read_stat_items, prefer_categories, prefer_authors, prefer_publishers, prefer_cps, prefer_books, prefer_time, read_rank, medals, year_reports
- notes.md → notebooks, book_highlights, book_chapters, book_reviews, book_best_bookmarks, book_underlines, public_reviews
- book.md → book_details, book_progress
- discover.md → recommended_books, similar_books
- search.md → search_sessions, search_results
- fetch_meta → 系统元信息
### 4.5 Git 分支策略
- **dev 分支**:日常开发,功能迭代
- **master 分支**:稳定发布版本,通过 `--no-ff` 合并 dev
- 提交信息遵循 **Conventional Commits** 规范(`feat:` / `fix:` / `merge:`)
---
## 5. 部署与运行
### 5.1 环境要求
- Python 3.13+
- MySQL 5.7+
- 微信读书 API Key(通过 `WEREAD_API_KEY` 环境变量配置)
### 5.2 启动步骤
```bash
# 1. 设置微信读书 API Key
export WEREAD_API_KEY=wrk-xxxxxxxx
# 2. 安装 Python 依赖
pip install flask pymysql
# 3. 启动 MySQL 服务
sudo /usr/local/mysql/support-files/mysql.server start
# 4. 创建数据库并建表
mysql -u root -p < schema_mysql.sql
# 5. 采集数据(首次)
python fetch_data.py
# 6. 迁移数据到 MySQL
python migrate_to_mysql.py
# 7. 启动 Web 服务
python app.py
# 访问 http://127.0.0.1:8080
```
### 5.3 数据更新
```bash
# 重新采集最新数据
python fetch_data.py
# 同步到 MySQL
python migrate_to_mysql.py
```