Files
home-automation/README.md
T
tliu93 94747c75dd
pytest / test (push) Successful in 43s
docker-image / build-and-push (push) Successful in 3m37s
Align image publishing with repository path
2026-04-20 23:05:27 +02:00

313 lines
7.6 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.
# Home Automation Backend
这是当前 `home-automation` 项目的首个 Python 版本。
当前系统已经包含:
- 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 部署入口
当前明确不包含:
- Notion 模块
## 当前配置现实
当前系统仍然是三个独立的 SQLite 数据库文件,而不是单一数据库:
- `app` 级共享数据使用自己的 DB 文件
- `location` 模块使用自己的 DB 文件
- `poo` 模块使用自己的 DB 文件
当前阶段明确不借这次重构把这些 DB 合并。配置层已经显式反映这一点:
- `APP_DATABASE_URL`
- `LOCATION_DATABASE_URL`
- `POO_DATABASE_URL`
目前 auth、`location``poo` 都已经接到各自独立的数据库文件。
其中 `app` 级共享 DB 当前主要用于:
- 单个 admin 用户
- server-side session
- runtime config 持久化
这部分现在也使用 Alembic 管理:
- `app db` 不会在应用启动时自动创建
- 需要先运行 `python scripts/app_db_adopt.py`
- 这个脚本会创建新 DB 并建好 schema
## 当前目录
主要目录如下:
- `app/`: FastAPI 应用代码
- `alembic_app/`: App DB 的 Alembic migration 环境
- `alembic_location/`: Location DB 的 Alembic migration 环境
- `alembic_poo/`: Poo DB 的 Alembic migration 环境
- `tests/`: pytest 测试
- `docs/`: 当前系统说明文档
- `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
```
3. 初始化数据库
```bash
python scripts/app_db_adopt.py
python scripts/location_db_adopt.py
python scripts/poo_db_adopt.py
```
4. 启动服务
```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
当前默认使用 SQLite,并区分三个数据库文件:
- App DB`sqlite:///./data/app.db`
- Location DB`sqlite:///./data/locationRecorder.db`
- Poo DB`sqlite:///./data/pooRecorder.db`
- 数据目录:`./data/`
初始化 migration 环境后,可继续添加模型并生成迁移:
当前 `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/`
- App DB 初始化:`python scripts/app_db_adopt.py`
- Location DB 接管 / 初始化:`python scripts/location_db_adopt.py`
- Poo DB 接管 / 初始化:`python scripts/poo_db_adopt.py`
## 基础鉴权
当前项目提供一个单用户 admin 鉴权层,用于保护配置页面与管理能力。
- 认证模型:`username/password`
- 会话模型:server-side session + cookie
- 当前主要受保护页面:`/config`
- 当前公开页面:`/login`
- 当前公开 API:现有业务 API 暂未在这一轮统一收口到 auth 下
安全实现的当前边界:
- 密码使用 Argon2 做哈希存储
- 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 只用于首个用户落库,不是后续的完整配置管理方案。
当前前端主要有两条页面路径:
- `/login`
- `/config`
无论是本地 `host:port` 还是反向代理后的域名访问,登录成功后都使用相对路径跳转到 `/config`
## Config 持久化
当前 config 页面不会把修改写回 `.env`
当前原则是:
- `.env` 只负责 bootstrap / fallback
- app 启动先从 `.env` 读取数据库地址等基础配置
- 请求期读取配置时,优先使用 app DB 中的 `app_config`
- 如果数据库里没有对应值,再 fallback 到 `.env`
这意味着:
- location / poo / app DB 地址仍然属于 bootstrap 范畴
- 运行时可编辑配置主要通过 `app_config` 表持久化
- token / secret 这类运行时必须可取回的配置,目前允许明文存储在 config 表中
- 登录密码仍然单独使用 Argon2 哈希,不走 config 表明文存储
## 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
```
## 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/<owner>/<repo>`
当前 workflow 不再把 image name 硬编码到特定 user package 路径,而是直接使用当前仓库标识生成镜像路径:
- `code.wanderingbadger.dev/${github.repository}:${tag}`
在 Gitea 这里,package 更贴近 repo 归属的语义,主要体现在镜像命名路径本身,而不是额外的“绑定”动作。也就是说,当前发布方式是按仓库路径约定来对齐 repo/package 语义。
这个 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`
## 运行测试
```bash
pytest
```
当前测试包含:
- app 基本启动测试
- `/status` endpoint 测试
- 登录 / session 基础流程测试
## OpenAPI 导出
FastAPI 默认会暴露 OpenAPI。若需要导出静态 schema 文件,可运行:
```bash
python scripts/export_openapi.py
```
输出文件会写到:
- `openapi/openapi.json`
- `openapi/openapi.yaml`
`openapi/` 当前纳入版本控制。接口发生变更时,应重新运行导出脚本并同步提交生成的 schema 文件。
## 容器启动
1. 准备环境变量文件
```bash
cp .env.example .env
```
2. 启动容器
```bash
docker compose up --build
```
默认端口:
- `8000:8000`
SQLite 持久化目录:
- 本地 `./data`
- 容器内 `/app/data`