2025-07-15 17:44:39 +02:00
|
|
|
|
# Home Automation Backend
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
这是当前 `home-automation` 项目的首个 Python 版本。
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
当前系统已经包含:
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
- FastAPI Web 应用与服务端模板页面
|
|
|
|
|
|
- SQLite + SQLAlchemy + Alembic 的三库结构
|
|
|
|
|
|
- username/password + server-side session 鉴权
|
|
|
|
|
|
- runtime config 页面与 app DB 持久化
|
|
|
|
|
|
- location recorder
|
|
|
|
|
|
- poo recorder
|
|
|
|
|
|
- Home Assistant inbound / outbound integration
|
|
|
|
|
|
- TickTick OAuth 与 action task 集成
|
|
|
|
|
|
- pytest 测试与 OpenAPI 导出脚本
|
|
|
|
|
|
- Docker / Compose 部署入口
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
当前明确不包含:
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
|
|
|
|
|
- Notion 模块
|
|
|
|
|
|
|
2026-04-19 21:39:23 +02:00
|
|
|
|
## 当前配置现实
|
|
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
当前系统仍然是三个独立的 SQLite 数据库文件,而不是单一数据库:
|
2026-04-19 21:39:23 +02:00
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- `app` 级共享数据使用自己的 DB 文件
|
2026-04-19 21:39:23 +02:00
|
|
|
|
- `location` 模块使用自己的 DB 文件
|
2026-04-20 11:48:48 +02:00
|
|
|
|
- `poo` 模块使用自己的 DB 文件
|
2026-04-19 21:39:23 +02:00
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
当前阶段明确不借这次重构把这些 DB 合并。配置层已经显式反映这一点:
|
2026-04-19 21:39:23 +02:00
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- `APP_DATABASE_URL`
|
2026-04-19 21:39:23 +02:00
|
|
|
|
- `LOCATION_DATABASE_URL`
|
|
|
|
|
|
- `POO_DATABASE_URL`
|
|
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
目前 auth、`location` 和 `poo` 都已经接到各自独立的数据库文件。
|
|
|
|
|
|
|
|
|
|
|
|
其中 `app` 级共享 DB 当前主要用于:
|
|
|
|
|
|
|
|
|
|
|
|
- 单个 admin 用户
|
|
|
|
|
|
- server-side session
|
2026-04-20 15:56:10 +02:00
|
|
|
|
- runtime config 持久化
|
2026-04-20 15:16:47 +02:00
|
|
|
|
|
|
|
|
|
|
这部分现在也使用 Alembic 管理:
|
|
|
|
|
|
|
|
|
|
|
|
- `app db` 不会在应用启动时自动创建
|
|
|
|
|
|
- 需要先运行 `python scripts/app_db_adopt.py`
|
|
|
|
|
|
- 这个脚本会创建新 DB 并建好 schema
|
2026-04-19 21:39:23 +02:00
|
|
|
|
|
2026-04-19 20:19:58 +02:00
|
|
|
|
## 当前目录
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
主要目录如下:
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
|
|
|
|
|
- `app/`: FastAPI 应用代码
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- `alembic_app/`: App DB 的 Alembic migration 环境
|
2026-04-20 11:48:48 +02:00
|
|
|
|
- `alembic_location/`: Location DB 的 Alembic migration 环境
|
|
|
|
|
|
- `alembic_poo/`: Poo DB 的 Alembic migration 环境
|
2026-04-19 20:19:58 +02:00
|
|
|
|
- `tests/`: pytest 测试
|
2026-04-20 20:40:04 +02:00
|
|
|
|
- `docs/`: 当前系统说明文档
|
2026-04-19 20:19:58 +02:00
|
|
|
|
- `scripts/`: 辅助脚本,例如 OpenAPI 导出
|
|
|
|
|
|
|
|
|
|
|
|
## 依赖管理
|
|
|
|
|
|
|
|
|
|
|
|
项目现在采用 `pip-tools` 管理依赖:
|
|
|
|
|
|
|
|
|
|
|
|
- 生产依赖源文件:`requirements.in`
|
|
|
|
|
|
- 开发依赖源文件:`dev-requirements.in`
|
|
|
|
|
|
- 编译产物:
|
|
|
|
|
|
- `requirements.txt`
|
|
|
|
|
|
- `dev-requirements.txt`
|
|
|
|
|
|
|
|
|
|
|
|
更新依赖时建议使用:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python -m venv .venv
|
|
|
|
|
|
source .venv/bin/activate
|
|
|
|
|
|
pip install pip-tools
|
|
|
|
|
|
pip-compile requirements.in
|
|
|
|
|
|
pip-compile dev-requirements.in
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
如果要升级某个依赖,可以用:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
pip-compile --upgrade-package fastapi requirements.in
|
|
|
|
|
|
pip-compile dev-requirements.in
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 本地启动
|
|
|
|
|
|
|
|
|
|
|
|
建议使用 Python 3.11 或以上版本。
|
|
|
|
|
|
|
|
|
|
|
|
1. 创建虚拟环境并安装依赖
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python -m venv .venv
|
|
|
|
|
|
source .venv/bin/activate
|
|
|
|
|
|
pip install -r dev-requirements.txt
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 准备环境变量
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cp .env.example .env
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
3. 初始化数据库
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python scripts/app_db_adopt.py
|
|
|
|
|
|
python scripts/location_db_adopt.py
|
|
|
|
|
|
python scripts/poo_db_adopt.py
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
4. 启动服务
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
启动后可访问:
|
|
|
|
|
|
|
|
|
|
|
|
- 应用首页:`http://localhost:8000/`
|
|
|
|
|
|
- 健康检查:`http://localhost:8000/status`
|
|
|
|
|
|
- Swagger UI:`http://localhost:8000/docs`
|
|
|
|
|
|
- ReDoc:`http://localhost:8000/redoc`
|
|
|
|
|
|
|
|
|
|
|
|
## 数据库与 Alembic
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
当前默认使用 SQLite,并区分三个数据库文件:
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- App DB:`sqlite:///./data/app.db`
|
2026-04-19 21:39:23 +02:00
|
|
|
|
- Location DB:`sqlite:///./data/locationRecorder.db`
|
|
|
|
|
|
- Poo DB:`sqlite:///./data/pooRecorder.db`
|
2026-04-19 20:19:58 +02:00
|
|
|
|
- 数据目录:`./data/`
|
|
|
|
|
|
|
|
|
|
|
|
初始化 migration 环境后,可继续添加模型并生成迁移:
|
|
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
当前 `app`、`location` 和 `poo` 都已经有各自独立的 Alembic 链路。
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- App Alembic 环境:`alembic_app.ini` + `alembic_app/`
|
2026-04-20 11:48:48 +02:00
|
|
|
|
- Location Alembic 环境:`alembic_location.ini` + `alembic_location/`
|
|
|
|
|
|
- Poo Alembic 环境:`alembic_poo.ini` + `alembic_poo/`
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- App DB 初始化:`python scripts/app_db_adopt.py`
|
2026-04-20 11:48:48 +02:00
|
|
|
|
- Location DB 接管 / 初始化:`python scripts/location_db_adopt.py`
|
|
|
|
|
|
- Poo DB 接管 / 初始化:`python scripts/poo_db_adopt.py`
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
2026-04-20 15:16:47 +02:00
|
|
|
|
## 基础鉴权
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
当前项目提供一个单用户 admin 鉴权层,用于保护配置页面与管理能力。
|
2026-04-20 15:16:47 +02:00
|
|
|
|
|
|
|
|
|
|
- 认证模型:`username/password`
|
|
|
|
|
|
- 会话模型:server-side session + cookie
|
2026-04-20 15:56:10 +02:00
|
|
|
|
- 当前主要受保护页面:`/config`
|
|
|
|
|
|
- 当前公开页面:`/login`
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- 当前公开 API:现有业务 API 暂未在这一轮统一收口到 auth 下
|
|
|
|
|
|
|
|
|
|
|
|
安全实现的当前边界:
|
|
|
|
|
|
|
2026-04-20 15:26:36 +02:00
|
|
|
|
- 密码使用 Argon2 做哈希存储
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- session cookie 使用 `HttpOnly`
|
|
|
|
|
|
- `Secure` 默认随 `APP_ENV` 切换:非 development 时默认开启
|
|
|
|
|
|
- `SameSite=Lax`
|
|
|
|
|
|
- 登录表单和登出表单都有基础 CSRF 防护
|
|
|
|
|
|
|
|
|
|
|
|
首次启动时,如果 `APP_DATABASE_URL` 对应的 auth DB 里还没有用户,应用会使用:
|
|
|
|
|
|
|
|
|
|
|
|
- `AUTH_BOOTSTRAP_USERNAME`
|
|
|
|
|
|
- `AUTH_BOOTSTRAP_PASSWORD`
|
|
|
|
|
|
|
|
|
|
|
|
创建初始 admin 用户。当前默认就是:
|
|
|
|
|
|
|
|
|
|
|
|
- username: `admin`
|
|
|
|
|
|
- password: `admin`
|
|
|
|
|
|
|
|
|
|
|
|
首次登录后会被要求立即修改密码。这个 bootstrap 只用于首个用户落库,不是后续的完整配置管理方案。
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
当前前端主要有两条页面路径:
|
2026-04-20 15:56:10 +02:00
|
|
|
|
|
|
|
|
|
|
- `/login`
|
|
|
|
|
|
- `/config`
|
|
|
|
|
|
|
|
|
|
|
|
无论是本地 `host:port` 还是反向代理后的域名访问,登录成功后都使用相对路径跳转到 `/config`。
|
|
|
|
|
|
|
|
|
|
|
|
## Config 持久化
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
当前 config 页面不会把修改写回 `.env`。
|
2026-04-20 15:56:10 +02:00
|
|
|
|
|
|
|
|
|
|
当前原则是:
|
|
|
|
|
|
|
|
|
|
|
|
- `.env` 只负责 bootstrap / fallback
|
|
|
|
|
|
- app 启动先从 `.env` 读取数据库地址等基础配置
|
|
|
|
|
|
- 请求期读取配置时,优先使用 app DB 中的 `app_config` 表
|
|
|
|
|
|
- 如果数据库里没有对应值,再 fallback 到 `.env`
|
|
|
|
|
|
|
|
|
|
|
|
这意味着:
|
|
|
|
|
|
|
|
|
|
|
|
- location / poo / app DB 地址仍然属于 bootstrap 范畴
|
|
|
|
|
|
- 运行时可编辑配置主要通过 `app_config` 表持久化
|
|
|
|
|
|
- token / secret 这类运行时必须可取回的配置,目前允许明文存储在 config 表中
|
|
|
|
|
|
- 登录密码仍然单独使用 Argon2 哈希,不走 config 表明文存储
|
|
|
|
|
|
|
2026-04-20 20:40:04 +02:00
|
|
|
|
## OpenAPI
|
|
|
|
|
|
|
|
|
|
|
|
可使用下面的脚本重新导出当前 API 定义:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python scripts/export_openapi.py
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
导出结果会写入:
|
|
|
|
|
|
|
|
|
|
|
|
- `openapi/openapi.json`
|
|
|
|
|
|
- `openapi/openapi.yaml`
|
|
|
|
|
|
|
|
|
|
|
|
## Docker Compose
|
|
|
|
|
|
|
|
|
|
|
|
当前默认 Compose 服务名为 `app`,容器名固定为 `home-automation-app`。
|
|
|
|
|
|
|
|
|
|
|
|
启动方式:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose up -d --build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
持续查看日志:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose logs -f app
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-04-20 22:18:54 +02:00
|
|
|
|
## Container Image CI
|
|
|
|
|
|
|
|
|
|
|
|
项目提供了一个 release image workflow:
|
|
|
|
|
|
|
|
|
|
|
|
- workflow 文件:`.github/workflows/docker-image.yml`
|
|
|
|
|
|
- 触发条件:push 匹配 `v*` 的 tag,例如 `v1.0.0`
|
|
|
|
|
|
- registry:`code.wanderingbadger.dev`
|
|
|
|
|
|
- image:`code.wanderingbadger.dev/tliu93/home-automation`
|
|
|
|
|
|
|
|
|
|
|
|
这个 workflow 会构建并推送 multi-arch image:
|
|
|
|
|
|
|
|
|
|
|
|
- `linux/amd64`
|
|
|
|
|
|
- `linux/arm64`
|
|
|
|
|
|
|
|
|
|
|
|
推送的 tag:
|
|
|
|
|
|
|
|
|
|
|
|
- release tag 本身,例如 `v1.0.0`
|
|
|
|
|
|
- `latest`
|
|
|
|
|
|
|
|
|
|
|
|
workflow 依赖以下 secrets:
|
|
|
|
|
|
|
|
|
|
|
|
- `REGISTRY_USERNAME`
|
|
|
|
|
|
- `REGISTRY_TOKEN`
|
|
|
|
|
|
|
|
|
|
|
|
CI 产出的 image 是给部署机直接 `docker pull` 使用的。部署机不需要 checkout 本仓库,也不需要本地执行 `docker build`。
|
|
|
|
|
|
|
2026-04-19 20:19:58 +02:00
|
|
|
|
## 运行测试
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
pytest
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
当前测试包含:
|
|
|
|
|
|
|
|
|
|
|
|
- app 基本启动测试
|
|
|
|
|
|
- `/status` endpoint 测试
|
2026-04-20 15:16:47 +02:00
|
|
|
|
- 登录 / session 基础流程测试
|
2026-04-19 20:19:58 +02:00
|
|
|
|
|
|
|
|
|
|
## OpenAPI 导出
|
|
|
|
|
|
|
|
|
|
|
|
FastAPI 默认会暴露 OpenAPI。若需要导出静态 schema 文件,可运行:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python scripts/export_openapi.py
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
输出文件会写到:
|
|
|
|
|
|
|
|
|
|
|
|
- `openapi/openapi.json`
|
|
|
|
|
|
- `openapi/openapi.yaml`
|
|
|
|
|
|
|
2026-04-19 23:25:13 +02:00
|
|
|
|
`openapi/` 当前纳入版本控制。接口发生变更时,应重新运行导出脚本并同步提交生成的 schema 文件。
|
|
|
|
|
|
|
2026-04-19 20:19:58 +02:00
|
|
|
|
## 容器启动
|
|
|
|
|
|
|
|
|
|
|
|
1. 准备环境变量文件
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cp .env.example .env
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 启动容器
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose up --build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
默认端口:
|
|
|
|
|
|
|
|
|
|
|
|
- `8000:8000`
|
|
|
|
|
|
|
|
|
|
|
|
SQLite 持久化目录:
|
|
|
|
|
|
|
|
|
|
|
|
- 本地 `./data`
|
|
|
|
|
|
- 容器内 `/app/data`
|