mirror of
https://github.com/KingHWJ/WeReadBoard.git
synced 2026-11-03 18:24:58 +08:00
169 lines
12 KiB
Markdown
169 lines
12 KiB
Markdown
# 阅间设计 Demo 使用说明
|
||
|
||
## 范围与启动
|
||
|
||
这是独立的静态设计 Demo,不调用微信读书接口,不需要 API Key,也不修改现有 Flask 服务、数据采集脚本和 8080 页面。功能与接口的后续实现进度统一维护在 [功能目标清单](feature-checklist.md)。
|
||
|
||
该 Demo 是历史设计探索,用于保留早期交互样例,不代表当前正式入口。
|
||
|
||
在项目根目录执行:
|
||
|
||
```sh
|
||
python3 -m http.server 8765 --bind 127.0.0.1 --directory web-demo
|
||
```
|
||
|
||
访问 `http://127.0.0.1:8765`。也可以直接打开 `web-demo/index.html`;推荐通过本地服务器使用,以便浏览器稳定保存目标数据。
|
||
|
||
无需安装前端依赖。页面由以下文件构成:
|
||
|
||
| 文件 | 内容 |
|
||
|---|---|
|
||
| `web-demo/index.html` | 页面外壳、导航、详情与目标编辑弹窗 |
|
||
| `web-demo/styles.css` | 暗亮主题、书封示意、响应式排版 |
|
||
| `web-demo/demo-data.js` | 书籍、书单、初始目标、笔记与点评样例 |
|
||
| `web-demo/app.js` | 页面渲染、目标操作、搜索筛选、导出 |
|
||
|
||
## 保存与数据边界
|
||
|
||
目标使用当前来源的 `localStorage` 键 `weread-demo-goals`,主题使用 `weread-demo-theme`。刷新后保留;更换浏览器、地址或端口不会自动迁移;清除网站数据会清除本地目标。
|
||
|
||
书单加入目标时保存当前书籍集合,后续不自动跟随书单变化。同一目标内书籍去重,已读完直接计为完成。新增目标必须有名称、有效时间范围和至少一本书。
|
||
|
||
本地存储读取失败时显示示例目标并提示,不自动覆盖原存储;保存失败时保留编辑表单并提示重试。
|
||
|
||
所有阅读数据、书单成员、封面、目录、笔记和点评都是示例。用户编辑的目标只保存在本机,不会写回微信读书。公开书单完整成员获取方式仍需接口验证。
|
||
|
||
## 使用入口
|
||
|
||
- 阅读目标:新建目标,填写日期,勾选书籍或点击书单快捷加入,保存后可再编辑。
|
||
- 我的书架:切换我的书单、有声书、文章收藏与阅读状态。
|
||
- 发现好书:选择搜索类型;右侧预览状态可查看加载、空结果、失败及重试效果。
|
||
- 书籍详情:从卡片进入,切换目录、个人笔记、热门划线、点评、相似推荐。
|
||
- 笔记:按书目和类型筛选,导出当前书目的划线与想法,书签仅显示数量。
|
||
|
||
## 验证
|
||
|
||
语法检查:
|
||
|
||
```sh
|
||
node --check web-demo/app.js
|
||
node --check web-demo/demo-data.js
|
||
```
|
||
|
||
交互验收记录见 [功能目标清单](feature-checklist.md)。真实 API、鉴权、分页和服务器持久化尚未验证。
|
||
|
||
## 与旧版的关系
|
||
|
||
旧版仪表盘已归档到 `legacy/classic/`。当前正式看板由根目录的 `app.py`、`fetch_data.py`、`templates/` 和 `static/` 提供;历史设计 Demo 位于 `web-demo/`,两者可以独立预览。
|
||
|
||
## 正式看板的紧凑样式
|
||
|
||
正式看板由 `templates/index.html` 和 `static/css/styles.css` 提供,使用现有启动方式,不新增依赖、配置或环境变量。上文的 `web-demo/` 是独立的历史设计 Demo,本次样式调整仅应用于正式看板。
|
||
|
||
刷新正式看板即可加载样式;若浏览器仍显示旧间距,强制刷新页面。检查阅读概览、我的书架、阅读目标在桌面和手机宽度下的展示,并切换暗色主题。目标数据的保存方式由当前应用逻辑决定,样式不参与存储。
|
||
|
||
## 正式看板的阅读目标数据库
|
||
|
||
正式页面的目标通过 `/api/reading/goals` 保存到 MySQL。浏览器只保留编辑草稿和页面状态,刷新或换浏览器后从同一服务读取目标。上文 `web-demo/` 的本地存储说明仅适用于静态 Demo。
|
||
|
||
沿用 `reading_api.py` 的 `WEREAD_DB_HOST`、`WEREAD_DB_PORT`、`WEREAD_DB_USER`、`WEREAD_DB_PASSWORD` 和 `WEREAD_DB_NAME` 配置,不新增依赖。服务仍使用当前个人账号的数据;多个浏览器连接同一服务时共享目标,没有新增多用户隔离。
|
||
|
||
手动部署新代码时,在项目根目录按文件名顺序执行迁移。下面命令复用服务配置,幂等创建项目迁移定义的表:
|
||
|
||
```sh
|
||
python3 - <<'PY'
|
||
from pathlib import Path
|
||
import pymysql
|
||
from reading_api import MYSQL_CONFIG
|
||
|
||
with pymysql.connect(**MYSQL_CONFIG) as conn:
|
||
with conn.cursor() as cur:
|
||
for migration in sorted(Path('migrations').glob('*.sql')):
|
||
for sql in migration.read_text(encoding='utf-8').split(';'):
|
||
if sql.strip():
|
||
cur.execute(sql)
|
||
print('数据库迁移已完成')
|
||
PY
|
||
PORT=8080 python3 app.py
|
||
```
|
||
|
||
使用已安装 `requirements.txt` 的 Python 环境。若 8080 已有本项目实例,先停止旧实例再启动,使 Flask 加载新接口。迁移可重复执行;运行账户需要目标表的读写权限。目标表不参与 `fetch_data.py` 的采集覆盖。
|
||
|
||
## 网站登录认证
|
||
|
||
正式页面和所有 `/api/*` 接口(包括 `/api/reading/*`、旧 `/api/v2/*` 与健康检查)都要求登录。未登录访问页面会跳转 `/login`;未登录直接请求 API 返回 401。CSS、JavaScript 等静态资源不包含个人数据,可公开加载。登录变更请求使用 CSRF token。
|
||
|
||
账号保存在 MySQL 的 `weread_auth` 表,密码以 Werkzeug 单向哈希存储。部署脚本会按文件名顺序执行 `migrations/*.sql`,其中 `002_site_auth.sql` 创建账号表。表中只允许一个管理员账号。
|
||
|
||
服务启动需要配置稳定的 `WEREAD_SESSION_SECRET`,用于签名会话;会话固定有效 5 天,Cookie 设置为 HttpOnly、SameSite=Lax,且 `WEREAD_SESSION_COOKIE_SECURE` 默认开启。生产环境必须通过 HTTPS 访问;仅本机 HTTP 预览时可设为 `WEREAD_SESSION_COOKIE_SECURE=0`。
|
||
|
||
首次部署还需在 systemd 环境中临时配置 `WEREAD_AUTH_SETUP_TOKEN`。可在服务器生成两个独立随机值:
|
||
|
||
```sh
|
||
python3 -c 'import secrets; print(secrets.token_urlsafe(48))'
|
||
```
|
||
|
||
将一个结果配置为 `WEREAD_SESSION_SECRET`,另一个配置为 `WEREAD_AUTH_SETUP_TOKEN`,重启服务后访问 `/login`。数据库尚无账号时,页面要求一次性口令、管理员用户名和至少 12 位密码;成功后只将密码哈希写入 MySQL,并关闭当前进程的初始化入口。然后从 systemd 配置中移除 `WEREAD_AUTH_SETUP_TOKEN` 并再次重启。若数据库已有账号,初始化表单不会开放。
|
||
|
||
不要把上述值写入 Git、浏览器代码或公开聊天。初始化口令不能省略:没有它,任何公网访问者都可能抢先创建管理员账号。当前应用不提供密码找回入口;需由管理员在服务器侧重置数据库中的哈希。
|
||
|
||
应用本身未实现登录尝试限流。公网部署还应在 Nginx 或其他可信入口对 `POST /auth/login` 配置频率限制,不能信任客户端自行传入的转发 IP。
|
||
|
||
## GitHub Webhook 自动部署
|
||
|
||
服务器部署使用根目录的 `deploy.sh`。脚本会先拉取指定分支,再检测 Python 环境;若项目 `.venv` 不存在,会自动用系统 `python3` 或 `python` 创建 `.venv`,随后安装 `requirements.txt`、按顺序执行 `migrations/*.sql`,并重启 systemd 服务。
|
||
|
||
当前服务器配置可按下列默认值使用:
|
||
|
||
```sh
|
||
PROJECT_DIR=/opt/weread-board/WeReadBoard
|
||
SERVICE_NAME=weread.service
|
||
VENV_DIR=/opt/weread-board/WeReadBoard/.venv
|
||
```
|
||
|
||
GitHub Actions 文件位于 `.github/workflows/deploy.yml`,现在只负责测试和部署脚本检查。生产部署由 GitHub Webhook 触发:仓库 `Settings -> Webhooks` 的 Payload URL 配置为 `https://laohang.space/github/webhook`,Secret 与服务器 `/etc/weread-webhook.env` 中的 `GITHUB_WEBHOOK_SECRET` 一致,事件只选择 push。
|
||
|
||
服务器 Webhook 服务使用 `/etc/weread-webhook.env`,至少配置 `GITHUB_WEBHOOK_SECRET`、`GITHUB_REPOSITORY=KingHWJ/WeReadBoard`、`DEPLOY_PROJECT_DIR` 和 `DEPLOY_SCRIPT`。代码内固定只允许 `master`,不接受环境变量覆盖。Nginx 将 HTTPS 请求转发至本机 `127.0.0.1:9001`;Webhook 会校验 HMAC-SHA256、仓库和分支,并在已有部署运行时拒绝重复启动。
|
||
|
||
如果在服务器手动部署,可执行:
|
||
|
||
```sh
|
||
cd /opt/weread-board/WeReadBoard
|
||
DEPLOY_BRANCH=master ./deploy.sh
|
||
```
|
||
|
||
`deploy.sh` 会优先读取项目根目录 `.env`;没有 `.env` 时,会读取 `weread.service` 当前 `Environment=` 配置。按截图中的 service 写法也能拿到端口、API Key 和数据库配置。若以后改用普通部署用户,需要允许该用户免密执行 `systemctl restart weread.service`。
|
||
|
||
浏览器旧目标不会自动覆盖数据库。在原访问地址打开“阅读目标”,点击“导入已有目标”;数据库已有同一 ID 时跳过,整批成功才标记导入完成。`weread-goals` 原数据保留,`weread-goals-imported` 只记录已导入。不同浏览器、域名和端口的旧存储需要分别在原地址导入。
|
||
|
||
正式网站域名 `laohang.space` 的页脚展示工信部 ICP 备案号 `浙ICP备202607916号-1`,点击后跳转至工信部备案查询平台。公安联网备案数据码不是公安备案号,因此不在页脚作为公安备案信息展示。
|
||
|
||
保存失败会保留表单并提示重试;读取失败显示错误和重试按钮,不冒充空列表。若新建提示 ID 已存在,刷新目标列表确认上次请求是否已经保存。数据库不可用或尚未执行迁移时,目标接口返回 503,不退回浏览器保存。
|
||
|
||
验证命令:
|
||
|
||
```sh
|
||
python3 -m unittest discover -s tests -p 'test_reading_goals*.py' -v
|
||
node --test tests/goals_frontend.test.cjs
|
||
node --check static/js/app.js
|
||
node --check static/js/weapi.js
|
||
```
|
||
|
||
真实数据库验证需先执行迁移,再显式运行 `WEREAD_TEST_MYSQL=1 python3 -m unittest discover -s tests -p 'test_reading_goals_mysql.py' -v`。测试创建唯一测试目标并清理,只操作本次生成的 ID。
|
||
|
||
## 日常维护与故障排查
|
||
|
||
端口冲突、请求失败、Python 环境、HTTPS 证书和 systemd 服务的诊断步骤统一维护在 [日常维护与故障排查](troubleshooting.md)。接口路径、监听端口、Python 或 `.venv` 选择、启动脚本、systemd 配置以及部署流程发生变化时,必须同步更新该文档的运行基线;新故障按日期追加记录并保留历史结论。
|
||
|
||
正式服务只保留一个监听端口。首页可以打开但 API 失败时,应分别检查 `/api/reading/status`、`/api/reading/shelf` 和 `/api/reading/dashboard`,根据 404、502 或超时定位到路由、上游服务或 TLS 环境,不能只用首页 200 作为启动成功标准。
|
||
|
||
本次样式收紧覆盖正式看板的概览、书架和阅读目标页。顶栏、标题区、筛选区、统计卡、书架网格、右侧目标摘要、目标介绍区和目标卡片均使用覆盖规则压缩占位;书架在窄屏固定两列,避免横向溢出。本地真实数据验收覆盖 1280 px 桌面和 390 px 手机宽度:桌面顶栏 58 px,统计卡从约 200 px 开始,书架一行 7 本,目标页介绍区约 67 px 高,目标卡约 317 px 宽;手机顶栏 56 px,书架两列,目标卡约 298 px 宽,概览、书架和目标页均未出现横向溢出。
|
||
|
||
当前书架电子书列表每页显示 48 本,页码导航位于列表下方;翻页会替换当前页内容。右侧排序框提供最近阅读、书名升序、书名降序和作者升序,置顶书籍始终优先;切换书架状态或排序会回到第 1 页。此功能使用已加载的书架数据,不需要数据库迁移。
|
||
|
||
## master Webhook 自动部署
|
||
|
||
`master` 分支 push 后由 GitHub Webhook 通知服务器。服务器校验签名后,在固定项目目录执行根目录 `deploy.sh`,完成拉取 `origin/master`、加载可选 `.env`、安装 Python 依赖、执行全部数据库迁移和重启 systemd 服务。`dev` 和其他分支不会部署,部署脚本也会拒绝非 `master` 分支。详细配置见 [master Webhook 自动部署](deploy-master.md)。
|
||
|
||
本次数据库验收已在 8080 正式看板完成:页面新建目标后刷新仍可读取,编辑后再次刷新仍可读取,并已清理临时验收目标。读取目标列表未完成时,新建和编辑入口只显示目标页的加载或错误状态,不会打开保存表单。
|