add get public and storage feature #6

Merged
tliu93 merged 4 commits from feature/public_ip into main 2026-04-29 13:16:58 +02:00
3 changed files with 206 additions and 0 deletions
Showing only changes of commit eda49489e0 - Show all commits
+76
View File
@@ -8,6 +8,8 @@
- SQLite + SQLAlchemy + Alembic 的三库结构
- username/password + server-side session 鉴权
- runtime config 页面与 app DB 持久化
- public IPv4 monitor、历史持久化与定时检查
- SMTP 配置、测试发信与 public IPv4 changed 邮件通知
- location recorder
- poo recorder
- Home Assistant inbound / outbound integration
@@ -40,6 +42,7 @@
- 单个 admin 用户
- server-side session
- runtime config 持久化
- public IPv4 当前状态与变化历史
这部分现在也使用 Alembic 管理:
@@ -199,6 +202,79 @@ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
- token / secret 这类运行时必须可取回的配置,目前允许明文存储在 config 表中
- 登录密码仍然单独使用 Argon2 哈希,不走 config 表明文存储
当前已经接入 config 页面的运行时配置包括:
- 基础系统配置
- auth cookie 相关配置
- SMTP 基础配置
- TickTick OAuth 配置
- Home Assistant 配置
其中 SMTP password 与其他 secret 字段一致:
- 页面不明文回显
- 留空提交时保留旧值
- 用于测试发信与自动通知时不会写入响应
## Public IPv4 Monitor
当前系统已经提供最小可用的 public IPv4 monitor
- 使用单一 provider 检查当前公网 IPv4
- 将状态与变化历史持久化到 app DB
- 提供受保护的手动检查入口:`GET /public-ip/check`
- 启动时注册 APScheduler job,默认每 4 小时检查一次
当前 app DB 中与此功能相关的新表:
- `public_ip_state`
- `public_ip_history`
状态语义如下:
- `first_seen`:首次发现当前公网 IPv4
- `unchanged`:与上次状态一致
- `changed`:公网 IPv4 发生变化
- `error`:provider 请求失败或返回无效值
## SMTP 与邮件通知
当前系统已经提供最小可用的 SMTP 能力:
- SMTP 配置可在 `/config` 页面填写并保存到 `app_config`
- 可通过 config 页面发送测试邮件
- 邮件 `From` 头支持显示名,例如 `Home Automation <sender@example.com>`
当前 SMTP 配置项包括:
- `SMTP_ENABLED`
- `SMTP_HOST`
- `SMTP_PORT`
- `SMTP_USERNAME`
- `SMTP_PASSWORD`
- `SMTP_FROM_NAME`
- `SMTP_FROM_ADDRESS`
- `SMTP_TO_ADDRESS`
- `SMTP_USE_STARTTLS`
当前 public IPv4 monitor 已与 SMTP sender 接通,但只处理一个很小的通知场景:
- 当 public IPv4 check 结果为 `changed` 时,自动发送一封英文纯文本邮件
以下情况不会发邮件:
- `first_seen`
- `unchanged`
- `error`
当前通知邮件内容固定,不提供模板系统,正文会包含:
- previous IP
- current IP
- detected time
手动测试时,如果需要再次模拟一次 IP 变化,可以临时修改 `public_ip_state.current_ipv4` 为一个保留测试地址,然后再次调用 `GET /public-ip/check`
## OpenAPI
可使用下面的脚本重新导出当前 API 定义:
+4
View File
@@ -32,6 +32,7 @@
- `api/`
- HTTP routes
- 当前已迁入 `/login``/logout``/admin`
- 当前已迁入 `GET /public-ip/check`
- 当前已迁入 `POST /homeassistant/publish` 第一版入口
- 当前已迁入 `POST /poo/record``GET /poo/latest`
- `models/`
@@ -42,6 +43,8 @@
- `services/`
- 业务服务层
- 当前已迁入 config page 的 DB 持久化逻辑
- 当前已迁入 public IPv4 检查、状态持久化与变化通知逻辑
- 当前已迁入 SMTP 发信与测试发信逻辑
- `integrations/`
- 外部系统适配层
- 当前已迁入 Home Assistant outbound adapter
@@ -80,6 +83,7 @@ pytest 测试目录。后续可以在这里自然扩展:
- 当前数据库继续使用 SQLite
- 当前不引入前后端分离
- 当前不设计 Notion 模块
- 当前通知能力仍保持极小范围,不引入独立通知中心或多渠道抽象
## 关于 Notion
+126
View File
@@ -0,0 +1,126 @@
# Public IPv4 Monitor 与邮件通知
本文档说明当前 public IPv4 monitor 与 SMTP 邮件通知能力的职责边界和运行方式。
## 当前范围
当前实现只覆盖一个很小的通知能力:
- 定期或手动检查当前公网 IPv4
- 将当前状态和变化历史持久化到 app DB
- 仅在公网 IPv4 发生变化时发送一封英文纯文本邮件
当前明确不包含:
- Namecheap API 自动更新
- IPv6 检查
- 错误告警邮件
- 重复提醒 / 升级告警
- Telegram / Slack / Discord 通知
- 完整通知中心或模板系统
## 数据存储
当前数据全部进入 app DB。
相关表:
- `public_ip_state`
- 保存当前状态
- 逻辑上通常只有一行
- `public_ip_history`
- 保存首次发现和变化历史
当前不会把 public IP 状态放进 `app_config`
## 检查结果语义
一次检查会返回以下四种结果之一:
- `first_seen`
- `unchanged`
- `changed`
- `error`
行为约束:
- `first_seen`:写入当前 IP 和首条 history,但不发通知邮件
- `unchanged`:只更新时间和状态,不写 history,不发邮件
- `changed`:更新 `previous_ipv4` / `current_ipv4` / `last_changed_at`,写入 history,并发送邮件
- `error`:保留已有有效 IP,不写伪 history,也不发邮件
## 手动检查与定时检查
手动检查入口:
- `GET /public-ip/check`
约束:
- 需要现有鉴权
- 响应不暴露 IP 本身
- 只返回非敏感检查结果
定时检查:
- 应用启动时注册 APScheduler job
- 默认每 4 小时执行一次
- 与手动检查复用同一套 public IP check + notify 逻辑
## SMTP 通知
当前通知发信复用现有 SMTP sender。
依赖的配置项:
- `SMTP_ENABLED`
- `SMTP_HOST`
- `SMTP_PORT`
- `SMTP_USERNAME`
- `SMTP_PASSWORD`
- `SMTP_FROM_NAME`
- `SMTP_FROM_ADDRESS`
- `SMTP_TO_ADDRESS`
- `SMTP_USE_STARTTLS`
其中:
- `SMTP_FROM_NAME` 用于邮件头显示名
- `From` 头会渲染成 `Name <mail@domain>`
- SMTP envelope sender 仍然使用纯邮箱地址,保持兼容性
## 通知触发条件
只有在 `changed` 时发邮件。
不会发邮件的情况:
- `first_seen`
- `unchanged`
- `error`
这使得同一 IP 状态不会被重复通知,因为在首次变更之后,后续重复检查会变成 `unchanged`
## 邮件内容
当前邮件标题固定为:
- `Public IP changed`
正文为英文纯文本,至少包含:
- previous IP
- current IP
- detected time
当前正文还会附带一句 Namecheap trusted IP 的人工更新提示。
## 失败处理
当前通知发送是“尽力而为”的附加动作:
- public IP 状态持久化先完成
- 邮件发送失败不会回滚 public IP 状态
- 失败只记录 warning 日志
这样可以避免通知链路反过来影响主检查流程。