Reviewed-on: #4
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_URLLOCATION_DATABASE_URLPOO_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.txtdev-requirements.txt
更新依赖时建议使用:
python -m venv .venv
source .venv/bin/activate
pip install pip-tools
pip-compile requirements.in
pip-compile dev-requirements.in
如果要升级某个依赖,可以用:
pip-compile --upgrade-package fastapi requirements.in
pip-compile dev-requirements.in
本地启动
建议使用 Python 3.11 或以上版本。
- 创建虚拟环境并安装依赖
python -m venv .venv
source .venv/bin/activate
pip install -r dev-requirements.txt
- 准备环境变量
cp .env.example .env
- 初始化数据库
python -m scripts.run_migrations
- 启动服务
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/ - 统一 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
基础鉴权
当前项目提供一个单用户 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_USERNAMEAUTH_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 定义:
python scripts/export_openapi.py
导出结果会写入:
openapi/openapi.jsonopenapi/openapi.yaml
Docker Compose
当前默认 Compose 服务名为 app,容器名固定为 home-automation-app。
当前 Compose 分成两层:
docker-compose.yml:默认使用 registry image,适合部署 / 生产拉取docker-compose.override.yml:仅为本地开发追加build: .
本地开发启动方式:
docker compose up -d --build
上面的命令会自动叠加 docker-compose.override.yml,因此本地仍然会按当前工作目录重新 build。
如果要按生产方式直接从 registry 拉取并启动,显式只使用基础 compose 文件:
docker compose -f docker-compose.yml pull
docker compose -f docker-compose.yml up -d
持续查看日志:
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>
docker-compose.yml 中生产默认使用的 app image 当前为:
code.wanderingbadger.dev/tliu93/home-automation:latest
当前 workflow 不再把 image name 硬编码到特定 user package 路径,而是直接使用当前仓库标识生成镜像路径:
code.wanderingbadger.dev/${github.repository}:${tag}
在 Gitea 这里,package 更贴近 repo 归属的语义,主要体现在镜像命名路径本身,而不是额外的“绑定”动作。也就是说,当前发布方式是按仓库路径约定来对齐 repo/package 语义。
这个 workflow 会构建并推送 multi-arch image:
linux/amd64linux/arm64
推送的 tag:
- release tag 本身,例如
v1.0.0 latest
workflow 依赖以下 secrets:
REGISTRY_USERNAMEREGISTRY_TOKEN
CI 产出的 image 是给部署机直接 docker pull 使用的。部署机不需要 checkout 本仓库,也不需要本地执行 docker build。
运行测试
pytest
当前测试包含:
- app 基本启动测试
/statusendpoint 测试- 登录 / session 基础流程测试
OpenAPI 导出
FastAPI 默认会暴露 OpenAPI。若需要导出静态 schema 文件,可运行:
python scripts/export_openapi.py
输出文件会写到:
openapi/openapi.jsonopenapi/openapi.yaml
openapi/ 当前纳入版本控制。接口发生变更时,应重新运行导出脚本并同步提交生成的 schema 文件。
容器启动
- 准备环境变量文件
cp .env.example .env
- 启动容器
docker compose up --build
默认端口:
8000:8000
SQLite 持久化目录:
- 本地
./data - 容器内
/app/data