Files
WeReadBoard/docs/METADATA_DOC.md
T
admin 507b9c5704 feat: switch to MySQL, add Chinese comments, health check, and technical docs
1. 数据源切换至 MySQL:
   - app.py 从 SQLite 切换到 PyMySQL,所有 API 读取 MySQL weread_dashboard 数据库
   - 新增 db_required 装饰器统一管理数据库连接和异常处理
   - 新增 /api/health 健康检查接口,检测 MySQL 连接状态
   - MySQL 连接失败时返回 HTTP 503 和告警信息
   - 修复 fetched_at 字段 Unix 时间戳到 MySQL TIMESTAMP 的兼容问题

2. 前端数据库连接告警:
   - 页面加载时优先调用 /api/health 检查 MySQL 连接
   - 连接失败时显示固定告警横幅,阻止后续数据加载
   - CSS 告警横幅样式(黄色背景、下滑动画)

3. 代码中文注释:
   - app.py:所有函数、API 接口、工具函数添加完整中文文档注释
   - fetch_data.py:所有 SQLite 建表语句添加列级中文注释
   - migrate_to_mysql.py:保留已有中文注释

4. 技术文档与元数据文档:
   - docs/TECHNICAL_DOC.md:项目概述、系统架构、API 设计、部署指南
   - docs/METADATA_DOC.md:18 张表完整字段说明、索引、表关系、数据类型规范
2026-07-17 10:26:07 +08:00

525 lines
18 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.
# 微信读书数据展示网站 - 元数据文档
> 版本:1.2.0 | 更新时间:2026-07-17 | 数据库:MySQL weread_dashboard
---
## 1. 数据库概览
| 属性 | 值 |
|------|-----|
| 数据库名称 | weread_dashboard |
| 字符集 | utf8mb4 |
| 排序规则 | utf8mb4_unicode_ci |
| 存储引擎 | InnoDB |
| 表数量 | 18 |
| 数据总量 | 862 行 |
---
## 2. 表分类
| 分类 | 表名 | 说明 | 数据来源 |
|------|------|------|----------|
| **基础数据** | books | 书架书籍 | 采集脚本 |
| **基础数据** | reading_stats | 阅读统计概要 | 采集脚本 |
| **基础数据** | read_times | 阅读时长时间序列 | 采集脚本 |
| **基础数据** | read_longest | 阅读时长排行 | 采集脚本 |
| **基础数据** | prefer_categories | 偏好分类 | 采集脚本 |
| **基础数据** | prefer_authors | 偏好作者 | 采集脚本 |
| **基础数据** | prefer_time | 24h 时段分布 | 采集脚本 |
| **基础数据** | notebooks | 笔记本概览 | 采集脚本 |
| **基础数据** | read_stat_items | 统计摘要项 | 采集脚本 |
| **基础数据** | archives | 书单归档 | 采集脚本 |
| **基础数据** | fetch_meta | 采集元信息 | 采集脚本 |
| **按需数据** | book_details | 书籍详情 | 用户点击时获取 |
| **按需数据** | book_progress | 阅读进度 | 用户点击时获取 |
| **按需数据** | book_highlights | 划线内容 | 用户点击时获取 |
| **按需数据** | book_chapters | 章节信息 | 用户点击时获取 |
| **按需数据** | book_reviews | 想法/点评 | 用户点击时获取 |
| **按需数据** | recommended_books | 推荐书籍 | 用户浏览推荐时获取 |
| **按需数据** | search_results | 搜索结果 | 用户搜索时获取 |
---
## 3. 表结构详情
### 3.1 books - 书架书籍表
> 存储用户书架中的所有书籍基本信息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| book_id | VARCHAR(64) | 是 (PK) | - | 书籍唯一标识 |
| title | VARCHAR(255) | 是 | '' | 书名 |
| author | VARCHAR(255) | 否 | NULL | 作者 |
| cover | VARCHAR(512) | 否 | NULL | 封面图 URL |
| category | VARCHAR(128) | 否 | NULL | 分类(如"文学-古代诗词") |
| finish_reading | TINYINT(1) | 是 | 0 | 是否读完 (1=读完) |
| read_update_time | INT UNSIGNED | 否 | NULL | 最近阅读时间 (Unix 时间戳) |
| secret | TINYINT(1) | 是 | 0 | 是否私密 (1=私密) |
| is_top | TINYINT(1) | 是 | 0 | 是否置顶 (1=置顶) |
| update_time | INT UNSIGNED | 否 | NULL | 书籍更新时间 (Unix 时间戳) |
| deep_link | VARCHAR(512) | 否 | NULL | 微信读书深度链接 |
**索引**:
- PRIMARY KEY (book_id)
- idx_books_category (category)
- idx_books_finish_reading (finish_reading)
- idx_books_read_update_time (read_update_time DESC)
**记录数**:404
---
### 3.2 reading_stats - 阅读统计概要表
> 存储总体和年度的阅读统计数据
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(20) | 是 | - | 统计维度: overall/annually |
| period | VARCHAR(20) | 是 | '' | 周期标识: "overall" 或 "2026" |
| total_read_time | INT UNSIGNED | 是 | 0 | 总阅读时长 (秒) |
| read_days | INT UNSIGNED | 是 | 0 | 有效阅读天数 |
| day_average_read_time | DOUBLE | 否 | 0 | 日均阅读时长 (秒) |
| regist_time | INT UNSIGNED | 否 | NULL | 用户注册时间 (Unix 时间戳) |
| raw_json | LONGTEXT | 否 | NULL | 原始 API 返回 JSON |
| created_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 记录创建时间 |
**索引**:
- PRIMARY KEY (id)
- idx_reading_stats_mode (mode, period)
**记录数**:2
---
### 3.3 read_times - 阅读时长时间序列表
> 按年/月/日分桶的阅读时长数据
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(30) | 是 | - | 统计维度 (含 _daily 后缀) |
| period | VARCHAR(20) | 是 | '' | 周期标识 |
| bucket_timestamp | INT UNSIGNED | 是 | - | 分桶起始时间戳 |
| duration | INT UNSIGNED | 是 | 0 | 阅读时长 (秒) |
**索引**:
- PRIMARY KEY (id)
- idx_read_times_mode_period (mode, period)
- idx_read_times_bucket (bucket_timestamp)
**记录数**:21
---
### 3.4 read_longest - 阅读时长排行表
> 阅读时间最久的书籍排名
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(20) | 是 | - | 统计维度 |
| period | VARCHAR(20) | 是 | '' | 周期标识 |
| book_id | VARCHAR(64) | 是 | - | 书籍 ID |
| title | VARCHAR(255) | 否 | NULL | 书名 |
| author | VARCHAR(255) | 否 | NULL | 作者 |
| cover | VARCHAR(512) | 否 | NULL | 封面图 URL |
| read_time | INT UNSIGNED | 是 | 0 | 阅读时长 (秒) |
| tags | VARCHAR(512) | 否 | NULL | 标签 (JSON 数组) |
**索引**:
- PRIMARY KEY (id)
- idx_read_longest_mode (mode, period)
**记录数**:20
---
### 3.5 prefer_categories - 偏好分类表
> 用户阅读的书籍分类统计
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(20) | 是 | - | 统计维度 |
| period | VARCHAR(20) | 是 | '' | 周期标识 |
| category_id | INT UNSIGNED | 否 | NULL | 分类 ID |
| category_title | VARCHAR(128) | 否 | NULL | 分类名称 |
| parent_category_title | VARCHAR(128) | 否 | NULL | 父分类名称 |
| val | DOUBLE | 否 | 0 | 偏好权重 |
| reading_time | INT UNSIGNED | 否 | 0 | 该分类阅读时长 (秒) |
| reading_count | INT UNSIGNED | 否 | 0 | 该分类阅读本数 |
**索引**:
- PRIMARY KEY (id)
- idx_prefer_cat_mode (mode, period)
**记录数**:16
---
### 3.6 prefer_authors - 偏好作者表
> 用户阅读最多的作者统计
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(20) | 是 | - | 统计维度 |
| period | VARCHAR(20) | 是 | '' | 周期标识 |
| author_id | INT UNSIGNED | 否 | NULL | 作者 ID |
| name | VARCHAR(255) | 否 | NULL | 作者名称 |
| count | INT UNSIGNED | 否 | 0 | 阅读书本数 |
| read_time | VARCHAR(64) | 否 | NULL | 阅读时长 (格式化字符串) |
**索引**:
- PRIMARY KEY (id)
- idx_prefer_author_mode (mode, period)
**记录数**:20
---
### 3.7 prefer_time - 24小时时段分布表
> 一天中每个小时的阅读时长分布
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(20) | 是 | - | 统计维度 |
| period | VARCHAR(20) | 是 | '' | 周期标识 |
| hour_index | TINYINT UNSIGNED | 是 | - | 小时 (0-23) |
| duration | INT UNSIGNED | 是 | 0 | 阅读时长 (秒) |
**索引**:
- PRIMARY KEY (id)
- idx_prefer_time_mode (mode, period)
**记录数**:24
---
### 3.8 notebooks - 笔记本概览表
> 有笔记的书籍及其笔记统计
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| book_id | VARCHAR(64) | 是 (PK) | - | 书籍 ID |
| title | VARCHAR(255) | 否 | NULL | 书名 |
| author | VARCHAR(255) | 否 | NULL | 作者 |
| cover | VARCHAR(512) | 否 | NULL | 封面图 URL |
| review_count | INT UNSIGNED | 是 | 0 | 想法/点评数 |
| note_count | INT UNSIGNED | 是 | 0 | 划线数 |
| bookmark_count | INT UNSIGNED | 是 | 0 | 书签数 |
| reading_progress | INT UNSIGNED | 是 | 0 | 阅读进度 (0-100) |
| marked_status | TINYINT(1) | 是 | 0 | 标记状态 (1=读完) |
| sort | BIGINT | 否 | NULL | 排序值 |
**索引**:
- PRIMARY KEY (book_id)
**记录数**:32
---
### 3.9 read_stat_items - 统计摘要项表
> App 首页展示的阅读统计摘要
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| mode | VARCHAR(20) | 是 | - | 统计维度 |
| period | VARCHAR(20) | 是 | '' | 周期标识 |
| stat_name | VARCHAR(64) | 否 | NULL | 统计项名称 (读过/读完/阅读/笔记) |
| counts | VARCHAR(64) | 否 | NULL | 统计值文案 (如"404本") |
| scheme | VARCHAR(512) | 否 | NULL | App 跳转链接 |
**索引**:
- PRIMARY KEY (id)
- idx_read_stat_items_mode (mode, period)
**记录数**:8
---
### 3.10 archives - 书单归档表
> 用户创建的书单
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| name | VARCHAR(255) | 否 | NULL | 书单名称 |
| book_ids | LONGTEXT | 否 | NULL | 书籍 ID 列表 (JSON 数组) |
**索引**:
- PRIMARY KEY (id)
**记录数**:6
---
### 3.11 fetch_meta - 采集元信息表
> 记录数据采集的元信息
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| key | VARCHAR(64) | 是 (PK) | - | 元信息键名 |
| value | TEXT | 否 | NULL | 元信息值 |
**索引**:
- PRIMARY KEY (key)
**记录数**:1
---
### 3.12 book_details - 书籍详细信息表
> 来自微信读书 /book/info 接口,用户点击书籍时按需获取
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| book_id | VARCHAR(64) | 是 (PK) | - | 书籍 ID |
| title | VARCHAR(255) | 否 | NULL | 书名 |
| author | VARCHAR(255) | 否 | NULL | 作者 |
| translator | VARCHAR(255) | 否 | NULL | 译者 |
| cover | VARCHAR(512) | 否 | NULL | 封面图 URL |
| intro | LONGTEXT | 否 | NULL | 书籍简介 |
| category | VARCHAR(128) | 否 | NULL | 分类 |
| publisher | VARCHAR(255) | 否 | NULL | 出版社 |
| publish_time | VARCHAR(32) | 否 | NULL | 出版时间 |
| isbn | VARCHAR(32) | 否 | NULL | ISBN 号 |
| word_count | INT UNSIGNED | 否 | 0 | 总字数 |
| new_rating | DECIMAL(5,1) | 否 | 0 | 评分 (百分制) |
| new_rating_count | INT UNSIGNED | 否 | 0 | 评分人数 |
| fetched_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 获取时间 |
**索引**:
- PRIMARY KEY (book_id)
**记录数**:1
---
### 3.13 book_progress - 阅读进度表
> 来自微信读书 /book/getprogress 接口
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| book_id | VARCHAR(64) | 是 (PK) | - | 书籍 ID |
| progress | TINYINT UNSIGNED | 是 | 0 | 阅读进度百分比 (0-100) |
| chapter_uid | INT UNSIGNED | 否 | NULL | 当前阅读章节 UID |
| chapter_offset | INT UNSIGNED | 否 | NULL | 当前章节内偏移量 |
| update_time | INT UNSIGNED | 否 | NULL | 最后阅读时间 (Unix 时间戳) |
| record_reading_time | INT UNSIGNED | 否 | 0 | 累计阅读时长 (秒) |
| finish_time | INT UNSIGNED | 否 | NULL | 读完时间 (Unix 时间戳) |
| is_start_reading | TINYINT(1) | 是 | 0 | 是否已开始阅读 |
| fetched_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 获取时间 |
**索引**:
- PRIMARY KEY (book_id)
**记录数**:1
---
### 3.14 book_highlights - 划线内容表
> 来自微信读书 /book/bookmarklist 接口
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| book_id | VARCHAR(64) | 是 | - | 书籍 ID |
| bookmark_id | VARCHAR(64) | 否 | NULL | 划线唯一 ID |
| chapter_uid | INT UNSIGNED | 否 | NULL | 所在章节 UID |
| mark_text | LONGTEXT | 否 | NULL | 划线原文内容 |
| create_time | INT UNSIGNED | 否 | NULL | 创建时间 (Unix 时间戳) |
| type | TINYINT | 否 | NULL | 划线类型 |
| range_text | VARCHAR(64) | 否 | NULL | 位置范围 |
| color_style | TINYINT | 否 | NULL | 划线颜色样式 |
| fetched_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 获取时间 |
**索引**:
- PRIMARY KEY (id)
- idx_highlights_book_id (book_id)
- idx_highlights_chapter (book_id, chapter_uid)
**记录数**:142
---
### 3.15 book_chapters - 章节信息表
> 来自微信读书 /book/bookmarklist 接口的 chapters 字段
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| book_id | VARCHAR(64) | 是 | - | 书籍 ID |
| chapter_uid | INT UNSIGNED | 是 | - | 章节 UID |
| chapter_idx | INT UNSIGNED | 否 | NULL | 章节序号 |
| title | VARCHAR(255) | 否 | NULL | 章节标题 |
**索引**:
- PRIMARY KEY (id)
- UNIQUE KEY uk_book_chapter (book_id, chapter_uid)
**记录数**:77
---
### 3.16 book_reviews - 个人想法/点评表
> 来自微信读书 /review/list/mine 接口
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| book_id | VARCHAR(64) | 是 | - | 书籍 ID |
| review_id | VARCHAR(64) | 否 | NULL | 想法唯一 ID |
| content | LONGTEXT | 否 | NULL | 想法内容文本 |
| create_time | INT UNSIGNED | 否 | NULL | 创建时间 (Unix 时间戳) |
| star | TINYINT | 否 | -1 | 评分 (0-5, -1=无评分) |
| chapter_name | VARCHAR(255) | 否 | NULL | 所在章节名称 |
| is_finish | TINYINT(1) | 否 | 0 | 是否书评 (1=书评) |
| fetched_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 获取时间 |
**索引**:
- PRIMARY KEY (id)
- idx_reviews_book_id (book_id)
**记录数**:19
---
### 3.17 recommended_books - 推荐书籍表
> 来自微信读书 /book/recommend 接口
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| book_id | VARCHAR(64) | 是 | - | 书籍 ID |
| title | VARCHAR(255) | 否 | NULL | 书名 |
| author | VARCHAR(255) | 否 | NULL | 作者 |
| cover | VARCHAR(512) | 否 | NULL | 封面图 URL |
| intro | TEXT | 否 | NULL | 书籍简介 |
| category | VARCHAR(128) | 否 | NULL | 分类 |
| reason | VARCHAR(512) | 否 | NULL | 推荐理由 |
| reading_count | INT UNSIGNED | 否 | 0 | 在读人数 |
| new_rating | DECIMAL(5,1) | 否 | 0 | 评分 (百分制) |
| new_rating_count | INT UNSIGNED | 否 | 0 | 评分人数 |
| rating_title | VARCHAR(32) | 否 | NULL | 评分标签 (神作/力荐等) |
| fetched_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 获取时间 |
**索引**:
- PRIMARY KEY (id)
- idx_recommended_book_id (book_id)
- idx_recommended_fetched (fetched_at DESC)
**记录数**:48
---
### 3.18 search_results - 搜索结果表
> 来自微信读书 /store/search 接口
| 字段名 | 数据类型 | 是否必填 | 默认值 | 说明 |
|--------|----------|----------|--------|------|
| id | BIGINT | 是 (PK) | AUTO | 自增主键 |
| keyword | VARCHAR(255) | 是 | - | 搜索关键词 |
| book_id | VARCHAR(64) | 是 | - | 书籍 ID |
| title | VARCHAR(255) | 否 | NULL | 书名 |
| author | VARCHAR(255) | 否 | NULL | 作者 |
| cover | VARCHAR(512) | 否 | NULL | 封面图 URL |
| intro | TEXT | 否 | NULL | 书籍简介 |
| publisher | VARCHAR(255) | 否 | NULL | 出版社 |
| category | VARCHAR(128) | 否 | NULL | 分类 |
| reading_count | INT UNSIGNED | 否 | 0 | 在读人数 |
| new_rating | DECIMAL(5,1) | 否 | 0 | 评分 (百分制) |
| new_rating_count | INT UNSIGNED | 否 | 0 | 评分人数 |
| rating_title | VARCHAR(32) | 否 | NULL | 评分标签 |
| search_idx | INT UNSIGNED | 否 | 0 | 搜索序号 |
| fetched_at | TIMESTAMP | 是 | CURRENT_TIMESTAMP | 获取时间 |
**索引**:
- PRIMARY KEY (id)
- idx_search_keyword (keyword)
- idx_search_book_id (book_id)
**记录数**:20
---
## 4. 表关系说明
### 4.1 实体关系
```
books (书架)
├── book_id ──── book_details (书籍详情) [1:1 按需]
├── book_id ──── book_progress (阅读进度) [1:1 按需]
├── book_id ──── book_highlights (划线) [1:N 按需]
├── book_id ──── book_chapters (章节) [1:N 按需]
├── book_id ──── book_reviews (想法) [1:N 按需]
└── book_id ──── notebooks (笔记本概览) [1:1 有笔记的书]
read_longest (阅读排行)
└── book_id ──── books (书架) [N:1 关联]
recommended_books (推荐)
└── book_id (独立,不关联 books)
search_results (搜索)
└── book_id (独立,不关联 books)
archives (书单)
└── book_ids (JSON 数组,逻辑关联 books)
```
### 4.2 逻辑分组
- **静态数据组**(采集时全量写入):books, reading_stats, read_times, read_longest, prefer_categories, prefer_authors, prefer_time, notebooks, read_stat_items, archives, fetch_meta
- **动态数据组**(用户操作时按需写入):book_details, book_progress, book_highlights, book_chapters, book_reviews, recommended_books, search_results
---
## 5. 数据类型规范
| MySQL 类型 | 用途 | 对应 SQLite 类型 |
|------------|------|------------------|
| VARCHAR(n) | 变长字符串(书名、作者等) | TEXT |
| LONGTEXT | 长文本(简介、划线内容) | TEXT |
| TEXT | 中等文本 | TEXT |
| INT UNSIGNED | 无符号整数(时间戳、计数) | INTEGER |
| TINYINT(1) | 布尔值(0/1) | INTEGER |
| TINYINT UNSIGNED | 小范围整数(小时 0-23、进度 0-100) | INTEGER |
| BIGINT | 自增主键 | INTEGER |
| DECIMAL(5,1) | 精度数值(评分) | REAL |
| DOUBLE | 浮点数(权重、日均时长) | REAL |
| TIMESTAMP | 时间戳(自动维护) | INTEGER (Unix 时间戳) |
---
## 6. 字符集与编码
- 数据库字符集:`utf8mb4`(支持完整 Unicode,包括 Emoji)
- 排序规则:`utf8mb4_unicode_ci`(不区分大小写,支持多语言排序)
- 连接字符集:`utf8mb4`(PyMySQL 连接配置中指定)
- 前端编码:`UTF-8`(HTML meta 标签声明)