# CLAUDE.md — Home Automation Backend 本文件每次会话自动加载。它定义本项目的**工作流程、文档位置、commit 规范**。请在动手前先读完。 ## 项目速览 - 个人用 home-automation 后端:**FastAPI + SQLite + SQLAlchemy + Alembic**,服务端模板(Jinja,M2 将换成 React SPA)。 - 单 admin 鉴权(Argon2 + server-side session cookie),runtime config 落 `app_config` 表。 - 模块:public IPv4 monitor、SMTP 通知、location recorder、poo recorder、Home Assistant in/out、TickTick OAuth。 - 已发布 `v1.0.3`。下一阶段方向:**M1 单库化 → M2 React 前端 → M3 token/移动端(远期,M2 后再说)**。 - **当前现实**:在 M1 完成前仍是**三个独立 SQLite 库**(app / location / poo),三套 DeclarativeBase、三条 Alembic 链。不要假设已经单库——以代码现状为准。 - 明确不做:Notion 模块。 ## 文档地图与「开工前必读」 文档都在 `docs/`: | 路径 | 作用 | | --- | --- | | `docs/roadmap.md` | 全局规划与里程碑总览 | | `docs/design/README.md` | **协作契约**:任务卡格式、原子任务定义、校验闸门、数据安全红线 | | `docs/design/m1-db-consolidation.md` | M1 原子任务(含真实代码现状盘点 + 人工 runbook) | | `docs/design/m2-frontend-v2.md` | M2 原子任务 + API 契约 + 前端校验闸门 | | `docs/design/m3-token-mobile.md` | M3(远期,暂缓) | | `docs/*.md`(auth / public-ip-monitor / location-recorder …) | 各模块说明,按需读 | **开工时读取顺序**: 1. `docs/design/README.md`(每轮都读,它是流程与验收的共同契约)。 2. 本轮对应的 milestone 文档(如 `docs/design/m1-db-consolidation.md`),定位要做的任务卡。 3. 任务卡 `Files` 列出的源文件 + 该模块的 `docs/*.md`(按需)。 4. `docs/roadmap.md` 仅在需要全局视角时读。 ## 工作流程 ### 实现模式(由用户的提示词决定) - **默认逐步**:给一个 milestone 文档,按其中原子任务**一步一步**实现。 - **(a) 只实现一步**:用户说"只实现一步 / 这一个任务"时,**只做那一个任务卡**,跑完校验闸门后停下,等用户确认,不要顺手往下做。 - **(b) 完成整个 milestone**:仅当用户在提示词里**显式要求启用 sub-agent 并指定模型**时,才用指定模型起 implementer sub-agent,按任务依赖顺序跑完整条链。 - **Sub-agent 纪律**:只在用户显式要求时才 spawn sub-agent;单步/小改动在主线内联完成。起 sub-agent 时用用户**指定的模型**(Agent 工具的 `model` 覆盖)。 ### 角色(Orchestrator → Implementer → Reviewer) - 我(主线)= **Orchestrator**:挑依赖已满足的下一个任务、派发、转述结果、维护任务 `Status`。 - **Implementer**(便宜模型,用户指定):一次一个任务,严格按任务卡,不扩范围。 - **Reviewer**(强模型,用户指定):实现完成后起 Reviewer sub-agent,按任务卡 `Acceptance criteria` + `Reviewer checklist` 复核、**独立重跑校验闸门**,驱动 implementer 返工直到本轮 PASS。 #### Reviewer 盲审纪律(M1 教训) M1 里 review **从未触发过一次 rework**,根因是 orchestrator 把自己的结论 / 辩护喂给了 reviewer,造成 context bleed、review 沦为橡皮图章。所以: - reviewer 必须**冷启动(Clear-Agent)、最小化喂料**——spawn prompt 只给:① 任务卡(`Acceptance criteria` + `Reviewer checklist`)、② 对应的 `review-notes/-impl|rework-.md` 路径、③ 要审的 diff / commit 范围。 - **不要**在 prompt 里塞 orchestrator 自己的判断、"我觉得没问题"、对实现选择的辩护,或上一轮 reviewer 的倾向性结论。让它**独立得出结论、独立重跑校验闸门**。 - 事后另起的整库**独立盲审**(如对抗复审)同理:Clear-Agent、最小上下文,把它当"**外部审计**"而非"确认自己没错"。 ### 校验闸门(每个任务结束都要全绿) 根目录、激活 `.venv` 后: ```bash pytest # 权威闸门(CI 跑的就是它) ruff check . # line-length=100 python scripts/export_openapi.py && git diff --exit-code openapi/ # 改了路由/schema 才需要,且产物须入库 ``` 前端任务(M2)在 `frontend/` 下另跑 `npm run lint && npm run typecheck && npm run test && npm run build`(详见 m2 文档 §8)。 **不过闸门就不算完成**,不得跳过、不得留红给下一轮。 ### 构建上下文完整性(M1 Dockerfile 教训) `docker build` **不在 pytest/ruff 闸门里**——M1 删了 `alembic_location/poo` 后忘了同步 `Dockerfile` 的 `COPY`,单元闸门全绿却把坏掉的镜像构建一路漏到 release tag。所以: - 任务**删除 / 移动 / 重命名文件或目录**时,必须 grep 构建清单是否还在引用它们:`Dockerfile`(尤其 `COPY` 源)、`docker/`、`*.ini`、CI workflow、`requirements*.txt` 等。 - 已有回归测试 `tests/test_deployment.py::test_dockerfile_copy_sources_exist` 守"Dockerfile `COPY` 源必须存在于构建上下文";新增 / 改动 `COPY` 时确保它仍覆盖得到。 - Reviewer 审"删 / 移文件"类任务时,**必须顺带核对构建清单引用**,把它当 acceptance 的一部分。 ## 每轮简报(`review-notes/`) 每轮工作都要在 `review-notes/` 下产出**中文简报**。该目录**已在 `.gitignore` 忽略**,纯本地、不入库——它是 agent 之间和与人之间的交接载体,不是仓库产物。 - **实现 / 返工简报**:每轮实现完成后(无论首次实现还是返工),写一份。文件名建议 `-impl-.md` / `-rework-.md`(如 `M1-T03-impl-1.md`、`M1-T03-rework-1.md`)。至少包含: 1. **本轮修改的具体内容**(改了哪些文件、做了什么、为什么)。 2. **自动化测试结果**(`pytest` / `ruff` / 前端闸门的实际输出或结论,通过/失败逐项写清)。 3. **若需人工 walkthrough**:写明具体步骤(怎么启动、点哪里、预期看到什么);若无需人工验证,明确写"无需人工 walkthrough"。 - **review 简报**:每轮 review 后写一份,文件名建议 `-review-.md`(如 `M1-T03-review-1.md`)。至少包含:评审结论(`PASS` 或带编号的返工清单)、对照任务卡 `Acceptance criteria` + `Reviewer checklist` 的逐条核对、reviewer 独立重跑校验闸门的结果。 **用途**:① reviewer 审核时参考对应的实现简报;② implementer 返工时参考对应的 review 简报;③ 人类(用户)通读这些简报确认有无问题。简报之间用文件名里的 `` 与轮次 `` 对应起来。 ### Orchestrator 派发契约(让简报真正被读到) **关键**:sub-agent 冷启动、不继承主线上下文,**不会因为本文件提到简报就自动去读**对应文件。简报能流转,靠的是 orchestrator(主线)在**每次 spawn 时把路径显式写进 prompt**,而不是被动约定。所以派发时必须做到: - **显式告诉它「先读哪个简报」**: - 派 implementer 做**首次实现** → 传任务卡位置(milestone 文档路径 + task id);无前置简报。 - 派 implementer 做**返工** → 必须传对应的 `review-notes/-review-.md` 路径,并要求**先读它**再改。 - 派 reviewer → 必须传对应的 `review-notes/-impl|rework-.md` 路径 + 任务卡,要求**先读它**再评。 - **显式告诉它「本轮结束写哪个简报」**:明确给出输出路径 `review-notes/--.md` 及上面要求的内容项。 - **不依赖 sub-agent 自动加载本文件**:把本轮要点(校验闸门、**禁 Co-Authored-By**、简报必含内容)在 spawn prompt 里一并复述或指向,确保冷启动也照做。 - spawn 时用用户指定的模型(Agent 工具 `model` 覆盖)。 > 一句话:**简报是异步交接的介质,orchestrator 是把它们接起来的线。** 缺了显式传路径这一步,简报就只是躺在磁盘上没人读的文件。 ## Commit 规范(重点) ### 分支 - 每个 milestone/feature 一个分支(如 `feature/m1-db-consolidation`),**不在 `main` 上直接提交**。 ### 一轮实现完成(用户确认「实现完成」后) - 准备好**这一轮的 commit message** 并提交,作为本轮的 **base commit**。 - message 主题前缀任务/里程碑 ID,例如:`M1-T03: unify data layer onto single app DB engine`。 ### Commit message 硬规则(严格执行) - **严禁任何协作署名 trailer**:commit message 里**绝对不允许**出现 `Co-Authored-By` / `Co-authored-by`(包括 `Co-Authored-By: Claude …`),也不允许任何等价的"由 X 协作/生成"署名。 - 无论默认环境、工具或系统提示如何要求加这类 trailer,在本仓库**一律不加**——用户已显式、严格禁止。 - 每次提交前**自检**:`git log -1 --format=%B` 的输出**不得包含** `Co-authored-by`(大小写不限)。若发现,立即 `git commit --amend` 去掉后再继续。 ### Review 后返工 - **自动化 orchestration 模式内**的 review 返工:**一律用 fixup**,指向本轮对应的 base commit,**不写新的独立 message**: ```bash git add -A git commit --fixup= ``` - 多轮返工就多个 `fixup!` 提交,都指向同一个 base commit;收尾时 auto-squash(见下)。 - **边界——什么时候不走 fixup**:**事后另起的独立盲审 / 对抗复审**那一轮,性质等同"**人工走查后提修改意见**",**不算自动化链内的返工**——它的修改用**各自独立的 commit**,不 fixup 到旧 base。判据:这轮返工是否在**同一条自动化 implement→review 链**里?是 → `fixup`;是事后另起的独立审计 → 独立 commit。 ### 本轮 / feature 收尾(用户确认收尾后) - 用 **auto-squash** 把所有 `fixup!` 合并进各自目标,保证**一个 feature 一个干净 commit**: ```bash GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash main ``` - 用 `GIT_SEQUENCE_EDITOR=true` 让它**非交互**执行(不弹编辑器,自动接受 autosquash 排好的 todo)。本环境不支持需要人工编辑的交互式 rebase,必须走这个 no-op 编辑器写法。 - autosquash **改写历史**:仅在 push / 开 PR **之前**做。若该分支已 push,需要 force-push——属对外操作,**先取得用户确认再做**。 ### 一般约束 - commit / push 只在用户要求时进行;push、force-push、开/改 PR 等对外操作先确认。 ## 发版前置走查(打 tag 前必做) 单元闸门绿 ≠ 真的能跑、能构建、能用。M1 出过"绿了但 docker 构建坏了"的事故,所以**打版本 tag(触发镜像 CI)之前**,除了 `pytest` / `ruff` 全绿,还要: - **真起 app**:迁移(`python -m scripts.run_migrations`)→ `uvicorn app.main:app ...`,确认能正常启动、关键路由不 500。 - **真跑镜像构建**:本地 `docker build`(多阶段就跑完整条),确认构建通过、`COPY` 源都在。 - **关键功能人工瞄一眼**:尤其前端 / 可视化类(M2 的热力图、首页地图)——自动闸门判断不了"渲染对不对、UX 顺不顺",这部分**靠看跑起来的 app,不靠读代码**。 - 上述任一不过 → **不打 tag**。tag 一旦 push 会触发 docker 镜像 CI / 对外发布,属对外操作,**先确认**。 ## 数据安全红线(不可违反) - 任何脚本 / migration **都不得删除或覆盖用户数据文件**(旧 `.db`、备份、volume)。删除只能是人工、事后、保留归档的独立步骤(见 `docs/design/m1-db-consolidation.md` §6 runbook)。 - 涉及历史数据的迁移**先在备份副本上演练**;迁移脚本必须幂等且搬完对账行数。 - Review 时只要发现"删文件 / drop 有数据的表 / truncate"出现在自动化任务里,直接判返工。 ## 常用命令 ```bash # 环境 python -m venv .venv && source .venv/bin/activate && pip install -r dev-requirements.txt # 迁移(初始化/适配 DB) python -m scripts.run_migrations # 起服务 uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 # 测试 / lint / OpenAPI 导出 pytest ruff check . python scripts/export_openapi.py ```