Files
doluedu-fastapi-template/AGENTS.md

149 lines
6.4 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.

# AGENTS.md — fastapi-template 开发规范mongodb 分支)
> 本分支为 **MongoDBBeanie单后端**:无 alembic、无 SQLAlchemy。
> Document 模型写 `src/{domain}/mongo.py`,新增 Document 必须在 `src/mongo.py::_collect_documents()` 登记。
本文件是 AI Agent / 开发者在本仓库工作的**必读规范**。先读这个,再动手。
通用 FastAPI 最佳实践参考 [docs/AGENTS_GENERIC.md](./docs/AGENTS_GENERIC.md) 与 [docs/BEST_PRACTICES_ZH.md](./docs/BEST_PRACTICES_ZH.md)。
## 0. 这个模板是什么
FastAPI 生产级项目骨架。**核心特性:`DB_BACKEND` 一个环境变量切换 MySQL / MongoDB业务代码零改动**。
任何修改都不得破坏这个特性——router/schemas 永远不允许 import 具体 DB 实现。
## 1. 技术栈基线
| 项 | 版本 | 说明 |
|---|---|---|
| Python | ≥3.11 | 用 `X \| Y``StrEnum` |
| FastAPI | ≥0.115 | 依赖注入一律 `Annotated[T, Depends(...)]` |
| Pydantic | v2 | 禁用 v1 API`.dict()` / `json_encoders` |
| SQLAlchemy | 2.0 async | `AsyncSession` + `async_sessionmaker`,禁 sync session |
| Beanie | ≥1.27 | MongoDB ODM |
| 包管理 | **uv** | 禁 pip/poetry/conda加依赖 `uv add xxx` |
| Lint | ruff | 提交前 `uv run ruff check --fix .` 必须零告警 |
| 测试 | pytest + pytest-asyncio + httpx | `asyncio_mode=auto` |
## 2. 目录结构铁律
按**域domain**组织,不按文件类型。一个域一个包,照抄 `src/items/`
```
src/{domain}/
├── router.py # 路由:只做参数校验和调用 repo禁写 SQL/查询
├── schemas.py # Pydantic 契约:与 DB 无关,前后端共用语义
├── dependencies.py # 定义 Repo Protocol + 按 DB_BACKEND 选实现
├── mysql.py # MySQL ORM 模型 + MySQLXxxRepo
├── mongo.py # Beanie Document + MongoXxxRepo
├── service.py # (可选)跨 repo 的复杂业务逻辑
├── constants.py # (可选)常量、错误码
└── exceptions.py # (可选)域内异常,继承 src.exceptions.AppError
```
- 新增域后必做三件事:① `src/mongo.py::_collect_documents()` 登记 Document
`alembic/env.py` import mysql 模型;③ `src/main.py` include_router。
- 跨域 import 必须显式模块名:`from src.items import constants as item_constants`,禁 `import *`
- 全局共享的东西才放 `src/`config / exceptions / database / mongo
## 3. 双数据库后端规范(本模板灵魂)
```python
# ✅ router 只依赖 Protocol
async def get_item(item_id: str, repo: ItemRepoDep): ...
# ✅ dependencies.py 模块加载时选定实现
get_item_repo = _get_mysql_repo if settings.DB_BACKEND == "mysql" else _get_mongo_repo
# ❌ 禁止在 router/schemas/service 里出现
from src.items.mysql import Item # 不许!
from src.items.mongo import ItemDoc # 不许!
```
- 两个 repo 实现**同一 Protocol**,方法签名逐字一致。
- schemas 的 `id` 统一用 `str`MySQL int 自增 / Mongo ObjectId 都转 str
转换在各 repo 的 `to_out()` 里完成。
- MySQL 改表结构 → 必须 `alembic revision --autogenerate` 生成迁移,禁手改生产库。
- Mongo 新增 Document → 只登记 `_collect_documents()`beanie 自动建索引。
- `src/database.py``src/mongo.py` 只在 lifespan / dependencies 里被引用;
非对应后端模式下它们可以 import 但**不得产生连接**engine 惰性,别主动 connect
## 4. 异步纪律
| 场景 | 写法 |
|---|---|
| 可 await 的 I/O | `async def` |
| 只有同步 SDK | `def`FastAPI 自动进线程池)或 `run_in_threadpool` |
| CPU 密集 >50ms | 扔任务队列,别放请求路径 |
```python
# ❌ async 路由里调用阻塞库 = 冻结整个事件循环
@router.get("/bad")
async def bad():
time.sleep(5)
# ✅
@router.get("/ok")
def ok():
time.sleep(5)
```
## 5. 配置与异常
- 配置只走 `src/config.py``settings`pydantic-settings域级配置放 `{domain}/config.py``env_prefix="XXX_"`
- 禁在代码里硬编码 DSN / 密钥;`.env` 不入库,`.env.example` 必须同步更新。
- 业务异常继承 `AppError`404 用 `NotFoundError`;统一由 `register_exception_handlers` 输出 `{"detail": ...}`
- 禁裸 `except:`,禁 `except Exception: pass`
## 6. Pydantic 规范
```python
# ✅ 约束写清楚required 和 optional 二选一,别自相矛盾
name: str = Field(min_length=1, max_length=128)
age: int | None = Field(default=None, ge=0) # 可选
age: int = Field(ge=18) # 必填
# ❌ 矛盾写法
age: int = Field(ge=18, default=None)
```
- 序列化定制用 `@field_serializer`,不用 `json_encoders`
- 入参模型XxxCreate/XxxUpdate与出参模型XxxOut分开`XxxUpdate` 全字段可选 + `model_dump(exclude_unset=True)`
## 7. 测试规范
- 测试从第一天就是异步:`httpx.AsyncClient` + `ASGITransport`,见 `tests/conftest.py`
- 测试库与开发库隔离Mongo 用 `app_test`MySQL 用 `app_test`
- 每个域至少覆盖create / get / list / update / delete + 404 路径。
- 跑 MySQL 后端测试:`DB_BACKEND=mysql uv run pytest`
## 8. Git 规范
- 提交信息Conventional Commits —— `feat: xxx` / `fix: xxx` / `refactor:` / `docs:` / `test:` / `chore:`
- 主分支 `main`;功能开发开 `feature/xxx` 分支,提 PR 合并。
- 提交前自检三连:`uv run ruff check --fix . && uv run pytest`,全绿才推。
## 9. 常用命令速查
```bash
uv sync # 装依赖
uv add fastapi # 加依赖dev 依赖uv add --dev xxx
uv run uvicorn src.main:app --reload # 开发起服务
uv run pytest # 测试
uv run ruff check --fix . # lint
uv run alembic revision --autogenerate -m "msg" # MySQL 迁移
docker compose up -d --build # 容器化整套
```
## 10. 反模式清单Review 时逐条核对)
- [ ] router 里出现 SQL / `ItemDoc.find()` 等具体 DB 调用
- [ ] async 路由里调用 requests / time.sleep 等阻塞库
- [ ] `print` 调试残留(用 `logging`
- [ ] 硬编码连接串 / 密钥
- [ ] `from x import *`、裸 except
- [ ] 改了 MySQL 模型没生成 alembic 迁移
- [ ] 新增 Mongo Document 没登记 `_collect_documents()`
- [ ] 新域只在单一后端实现(两个 repo 必须成对)
- [ ] 提交信息 freestyle非 Conventional Commits