配置 SSOT(TOML + .env) 统一错误契约 Auth 与事务边界 Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client 可观测性(OpenTelemetry + LGTM)
55 lines
4.7 KiB
Plaintext
55 lines
4.7 KiB
Plaintext
---
|
||
alwaysApply: true
|
||
---
|
||
|
||
# Backend Fastapi
|
||
|
||
## 架构规则
|
||
1. **`common/` / `utils/` / `shared/` / `helpers/` 禁止创建**:只有 truly cross-cutting 能力进 `core/`,业务 DTO/校验/错误码归 feature
|
||
2. **router 禁止操作 DB**:所有数据访问通过 repo,所有业务逻辑通过 service
|
||
3. **service 禁止 import adapter**:只依赖 port protocol,通过 DI 注入。代码中出现 `from adapters.xxx import ...` 即为违规
|
||
4. **feature 间禁止 import router**:跨 feature 调用通过 service 注入
|
||
5. **所有 schema 变更走 Alembic**:禁止直接 DDL
|
||
6. **新增 provider 必须实现 port protocol**:不得在 feature 中直接调用 SDK
|
||
7. **事务边界:repo 不提交,service 管事务**:`repo.py` 只做 `add/delete/query`,`commit/rollback` 由 service 或 Celery task 统一执行。`get_async_db()` 不自动 commit;禁止在 router/repo 中 `await db.commit()` / `session.commit()`
|
||
8. **port 边界不可打穿**:service 需要厂商增强能力时,必须扩充 port 或定义第二个窄 port,禁止直接引用 adapter 扩展方法
|
||
9. **quota 是独立 feature**:conversation、memoir、payment 如需配额检查,通过注入 `QuotaService`,不得直接 import quota 内部函数
|
||
10. **成功响应不强制包装**:`core/errors.py` 只统一错误响应格式 `{error_code, message, request_id}`,成功响应直接返回 Pydantic model / FileResponse / 原始结构
|
||
|
||
## 配置 SSOT(TOML + .env)
|
||
- **Secrets / bootstrap 仅进 `.env`**:`DATABASE_URL`、`SECRET_KEY`、各厂商 API key、支付私钥等 → `app/core/config.py` 的 `Settings`
|
||
- **产品 / 部署调参仅进 TOML**:`api/config/default.toml` + `api/config/{APP_ENV}.toml`(`development` / `staging` / `production`)
|
||
- **禁止**在 `Settings` 新增 `chat_*` / `memoir_*` / `memory_*` 等产品字段;`tests/test_settings_allowlist.py` 会拦截 env 反弹
|
||
- **禁止**业务代码散落 `os.getenv()`;读配置走既有入口:
|
||
- feature 常量:`from app.features.<feature>.constants import chat`(等)
|
||
- 运行时默认:`from app.core.runtime_constants import llm_defaults, tts_defaults, ...`
|
||
- deploy 开关:`settings.enable_tts` 等(`SettingsFacade` 代理到 TOML `[deploy]`)
|
||
- 改默认值时 **`default.toml` 与 `app_config_models.py` 必须同步**;`tests/test_default_toml_legacy_parity.py` 锁定关键默认行为
|
||
- 字段对照与运维说明见 `api/docs/configuration.md`
|
||
|
||
## 错误处理
|
||
- router / service **抛 `AppError` 子类**(`BadRequestError`、`AuthenticationError`、`NotFoundError`、feature 内 `AuthError` 等),**禁止** `HTTPException`
|
||
- 业务专用 `error_code` 登记在 `app/core/error_codes.py`,OpenAPI 通过 `ErrorResponse` 组件文档化
|
||
- 429 语义:`QuotaExceededError` vs `RateLimitedError`;勿用裸 `HTTPException(429)`(legacy handler 无法区分 quota)
|
||
- 客户端(`app-expo` / `app-eval-web`)统一用 `parseApiError` 读 `message` / `error_code`(兼容旧 `detail`)
|
||
|
||
## 事务 helpers(补充规则 7)
|
||
- 多步写、需原子提交 → `transactional()` / `transactional_sync()`(`app/core/db.py`)
|
||
- 外层事务 active 时、局部失败可独立回滚 → `transactional_nested()` / `transactional_nested_sync()`(savepoint)
|
||
- **同一 session 上连续两次 `transactional()` = 两次独立 commit**(WS 分段持久化等刻意为之);不要假设嵌套合并成一个事务
|
||
- Celery sync 路径用 `transactional_sync()` + `get_sync_db()`;外部副作用(SMS、COS、LLM)放在 commit 成功之后
|
||
|
||
## Redis / Celery
|
||
- 业务 key:`settings.redis_url_resolved`(通常 DB/0)
|
||
- Celery broker/backend:`settings.celery_redis_url_resolved`(通常 DB/1;compose 显式 `CELERY_REDIS_URL`)
|
||
- `REDIS_URL` 使用 DB/15 时必须显式设置 `CELERY_REDIS_URL`(无法 auto +1)
|
||
|
||
## 依赖管理(uv)
|
||
11. **依赖统一用 uv 管理**:禁止直接 `pip install`、禁止手动编辑 `pyproject.toml` 的 `[project.dependencies]` 或 `[dependency-groups]`
|
||
12. **新增依赖用 `uv add <pkg>`**,dev 依赖用 `uv add --dev <pkg>`,移除用 `uv remove <pkg>`
|
||
13. **`uv.lock` 必须纳入版本控制**:保证 CI 和本地环境精确一致
|
||
14. **安装环境统一用 `uv sync`**:开发环境 `uv sync --dev`,生产环境 `uv sync --no-dev`
|
||
15. **运行命令统一用 `uv run`**:如 `uv run pytest`、`uv run alembic upgrade head`、`uv run uvicorn ...`
|
||
16. 每次添加新代码时,一定要阅读已有部分代码,确保符合项目架构,pattern,loguru模式
|
||
17. **日志**:业务代码使用 `app.core.logging.get_logger(__name__)`(loguru `bind`);禁止在 `app` 包内用 `import logging` 取业务 logger;仅第三方 SDK / 适配器层可对标准库 `logging` 做桥接(如 `InterceptHandler`)
|