M1-T07: align docs to single-DB reality and re-export OpenAPI

Rewrite README (single app.db + one alembic_app chain, legacy data moved
once via scripts.migrate_legacy_data, accurate test list) and remove the
Grafana Provisioning section. Update architecture-overview to the unified
data layer (one Base, app-DB engine with WAL) and retire the
alembic_location / alembic_poo sections. Mark M1 done in the roadmap.
Re-export openapi/, which catches the spec up to the already-existing
/config/smtp/test and /public-ip/check endpoints (purely additive; M1's
DB-session dependency swap produced no schema change).

pytest 95 passed; ruff clean (pre-existing only); OpenAPI export idempotent.
This commit is contained in:
2026-06-12 17:13:28 +02:00
parent dc624bb7e5
commit 2f634006d2
5 changed files with 161 additions and 103 deletions
+35 -88
View File
@@ -5,7 +5,7 @@
当前系统已经包含:
- FastAPI Web 应用与服务端模板页面
- SQLite + SQLAlchemy + Alembic 的库结构
- SQLite + SQLAlchemy + Alembic 的库结构
- username/password + server-side session 鉴权
- runtime config 页面与 app DB 持久化
- public IPv4 monitor、历史持久化与定时检查
@@ -23,41 +23,32 @@
## 当前配置现实
当前系统仍然是三个独立的 SQLite 数据库文件,而不是单一数据库
当前系统使用单一 SQLite 数据库文件`app.db`),所有数据表都在其中
- `app` 级共享数据使用自己的 DB 文件
- `location` 模块使用自己的 DB 文件
- `poo` 模块使用自己的 DB 文件
- auth(单个 admin 用户、server-side session
- runtime config 持久化(`app_config` 表)
- public IPv4 当前状态与变化历史
- location 记录(`location` 表)
- poo 记录(`poo_records` 表)
当前阶段明确不借这次重构把这些 DB 合并。配置层已经显式反映这一点
配置层只保留一个数据库环境变量
- `APP_DATABASE_URL`
- `LOCATION_DATABASE_URL`
- `POO_DATABASE_URL`
目前 auth、`location``poo` 都已经接到各自独立的数据库文件。
`app.db` 不会在应用启动时自动创建,需要先运行:
其中 `app` 级共享 DB 当前主要用于:
```bash
python -m scripts.run_migrations
```
- 单个 admin 用户
- server-side session
- runtime config 持久化
- public IPv4 当前状态与变化历史
这部分现在也使用 Alembic 管理:
- `app db` 不会在应用启动时自动创建
- 需要先运行 `python scripts/app_db_adopt.py`
- 这个脚本会创建新 DB 并建好 schema
该命令会通过 Alembic 将 `app.db` 初始化或升级到最新 head(含 `location` / `poo_records` 表)。
## 当前目录
主要目录如下:
- `app/`: FastAPI 应用代码
- `alembic_app/`: App DB 的 Alembic migration 环境
- `alembic_location/`: Location DB 的 Alembic migration 环境
- `alembic_poo/`: Poo DB 的 Alembic migration 环境
- `alembic_app/`: App DB 的 Alembic migration 环境(同时管理 `location` / `poo_records` 表)
- `tests/`: pytest 测试
- `docs/`: 当前系统说明文档
- `scripts/`: 辅助脚本,例如 OpenAPI 导出
@@ -128,24 +119,22 @@ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
## 数据库与 Alembic
当前默认使用 SQLite,并区分三个数据库文件:
当前使用单一 SQLite 数据库文件:
- App DB`sqlite:///./data/app.db`
- Location DB`sqlite:///./data/locationRecorder.db`
- Poo DB`sqlite:///./data/pooRecorder.db`
- 数据目录:`./data/`
初始化 migration 环境后,可继续添加模型并生成迁移
所有模型(auth / config / public_ip / location / poo)共用同一个 `Base`,均通过单一 Alembic 链管理
当前 `app``location` `poo` 都已经有各自独立的 Alembic 链路。
- App Alembic 环境:`alembic_app.ini` + `alembic_app/`
- Location Alembic 环境:`alembic_location.ini` + `alembic_location/`
- Poo Alembic 环境:`alembic_poo.ini` + `alembic_poo/`
- Alembic 环境:`alembic_app.ini` + `alembic_app/`
- 统一 migration job`python -m scripts.run_migrations`
- App DB 初始化:`python scripts/app_db_adopt.py`
- Location DB 接管 / 初始化:`python scripts/location_db_adopt.py`
- Poo DB 接管 / 初始化:`python scripts/poo_db_adopt.py`
- App DB 接管 / 初始化:`python scripts/app_db_adopt.py`
历史 location / poo 数据(旧版本遗留的独立 DB 文件)已通过以下脚本一次性迁移至 `app.db`(幂等,不删除旧文件):
```bash
python -m scripts.migrate_legacy_data
```
## 基础鉴权
@@ -197,7 +186,7 @@ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
这意味着:
- location / poo / app DB 地址仍然属于 bootstrap 范畴
- app DB 地址`APP_DATABASE_URL`仍然属于 bootstrap 范畴
- 运行时可编辑配置主要通过 `app_config` 表持久化
- token / secret 这类运行时必须可取回的配置,目前允许明文存储在 config 表中
- 登录密码仍然单独使用 Argon2 哈希,不走 config 表明文存储
@@ -318,55 +307,6 @@ docker compose -f docker-compose.yml up -d
docker compose logs -f app
```
## Grafana Provisioning
当前仓库支持通过 Grafana provisioning 自动加载 SQLite datasource 和 repo 内的 dashboard 导出文件。
需要保留的文件路径如下:
- `grafana/provisioning/datasources/locationrecorder.yaml`
- `grafana/provisioning/datasources/poorecorder.yaml`
- `grafana/provisioning/dashboards/provider.yaml`
- `grafana/dashboards/locationrecorder.json`
- `grafana/dashboards/poorecorder.json`
这些文件的职责分别是:
- `grafana/provisioning/datasources/locationrecorder.yaml`:声明 `locationrecorder` SQLite datasource,并指向 `/data/home-automation/locationRecorder.db`
- `grafana/provisioning/datasources/poorecorder.yaml`:声明 `poorecorder` SQLite datasource,并指向 `/data/home-automation/pooRecorder.db`
- `grafana/provisioning/dashboards/provider.yaml`:告诉 Grafana 从 `/var/lib/grafana/dashboards` 扫描并加载 dashboard JSON
- `grafana/dashboards/locationrecorder.json`location recorder dashboard 导出文件,内容本身不需要在 compose 中改写
- `grafana/dashboards/poorecorder.json`poo recorder dashboard 导出文件,内容本身不需要在 compose 中改写
当前 `docker-compose.yml` 中,Grafana service 需要挂载以下目录:
- `./grafana/provisioning -> /etc/grafana/provisioning:ro`
- `./grafana/dashboards -> /var/lib/grafana/dashboards:ro`
同时保留现有 named volume `homeautomation_grafana_storage:/var/lib/grafana` 作为 Grafana 运行态数据存储。
一键启动前,至少需要以下文件已经存在:
- `grafana/provisioning/datasources/locationrecorder.yaml`
- `grafana/provisioning/datasources/poorecorder.yaml`
- `grafana/provisioning/dashboards/provider.yaml`
- `grafana/dashboards/locationrecorder.json`
- `grafana/dashboards/poorecorder.json`
启动方式:
```bash
docker compose up -d
```
启动后会发生的事情:
- Grafana 容器会安装 `frser-sqlite-datasource` 插件
- Grafana 会读取 `/etc/grafana/provisioning/datasources/` 下的 datasource YAML
- Grafana 会读取 `/etc/grafana/provisioning/dashboards/provider.yaml`
- Grafana 会从 `/var/lib/grafana/dashboards/` 自动导入两个 dashboard JSON
- 现有 Grafana named volume 继续负责保存 Grafana 运行态数据,不会覆盖 repo 内的 dashboard 与 provisioning 文件
## Container Image CI
项目提供了一个 release image workflow
@@ -411,9 +351,16 @@ pytest
当前测试包含:
- app 基本启动测试
- `/status` endpoint 测试
- 登录 / session 基础流程测试
- app 启动与 `/status` 检查
- 登录 / session / 鉴权流程
- runtime config 读写
- public IPv4 monitor
- SMTP 配置与测试发信
- location / poo recorder 端点
- Home Assistant inbound 集成
- TickTick OAuth
- 部署与迁移(`run_migrations`
- legacy 数据迁移脚本(`migrate_legacy_data`
## OpenAPI 导出