Merge branch 'refactor/backend-architecture' into development
This commit is contained in:
@@ -4,21 +4,29 @@ alwaysApply: true
|
||||
|
||||
# Backend Fastapi
|
||||
|
||||
## 架构规则
|
||||
1. **`common/` / `utils/` / `shared/` / `helpers/` 禁止创建**:只有 truly cross-cutting 能力进 `core/`,业务 DTO/校验/错误码归 feature
|
||||
2. **router 禁止操作 DB**:所有数据访问通过 repo,所有业务逻辑通过 service
|
||||
1. `**common/` / `utils/` / `shared/` / `helpers/` 禁止创建**:只有 truly cross-cutting 能力进 `core/`,业务 DTO/校验/错误码归 feature
|
||||
2. **router 是 HTTP + OpenAPI 契约边界**:所有数据访问通过 repo,所有业务逻辑通过 service;但 `response_model`、`status_code`、`responses`、`summary`、`description`、`tags` 等契约元数据必须定义在 router / `APIRouter` 上
|
||||
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 或 UoW 统一执行。`get_async_db()` 不自动 commit
|
||||
7. **事务边界:repo 不提交,service 管事务**:`repo.py` 只做 `add/delete/query`,`commit/rollback` 由 service 或 UoW 统一执行。`get_async_db()` 不自动 commit;`flush()` 仅在明确需要提前拿主键或触发约束检查时受控使用
|
||||
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 / 原始结构
|
||||
|
||||
## 依赖管理(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 ...`
|
||||
11. **配置统一通过 `pydantic-settings` 管理**:只允许在 `core/config.py` 中定义 `BaseSettings` / `SettingsConfigDict`;除配置模块外,禁止业务代码直接 `load_dotenv()`、`dotenv_values()` 或散落 `os.getenv()`
|
||||
12. **依赖真相源是 `api/pyproject.toml` + `api/uv.lock`**:`requirements.txt` 如存在仅作兼容导出,不作为主依赖入口
|
||||
13. **运行时基础库保持收敛**:Redis 客户端统一使用 `redis` / `redis.asyncio`,JWT 统一使用 `PyJWT`
|
||||
14. **service 装配走 FastAPI dependency graph**:router 只依赖 `get_xxx_service()`,不得在路由函数里手工 new service 或自行拼装 `db + adapter + settings`
|
||||
15. **每个 feature router 必须维护共享 tags / responses**:使用 `APIRouter(prefix=..., tags=..., responses=...)` 收敛文档边界与共享错误响应
|
||||
16. **内部接口显式隐藏**:不对外暴露的 path operation 使用 `include_in_schema=False`,禁止依赖“没人知道 URL”
|
||||
17. **OpenAPI 全局自定义只做增强**:`custom_openapi()` 只做全局 schema 增强,不替代 router 上的正常声明
|
||||
18. **WebSocket 协议必须独立成文**:实时消息 schema、错误、鉴权、状态流转、重连与幂等规则不得只存在于代码实现中
|
||||
19. **memory 的定义是素材检索与事实组织,不是聊天 persona 记忆**:不实现通用“记住这个”或面向终端用户的自然语言 `forget`
|
||||
20. **memory 必须采用混合检索**:至少包含 metadata filter + PostgreSQL FTS + vector retrieval;纯向量库不得作为唯一真相源
|
||||
21. **原始素材、摘要、事实、时间线必须分层存储**:不得把所有语义压进单一向量表
|
||||
22. **memory 写入必须可追溯**:summary / fact / timeline event 必须能追溯到 `source` 或 `chunk`
|
||||
23. **conversation / memoir 只通过 `MemoryService` 调用 memory**:不得直接查询 memory 表
|
||||
24. **memory feature 不得直接耦合具体 embedding SDK**:只依赖 `EmbeddingProvider`(可选 `Reranker` 同理)
|
||||
25. **所有 pgvector / FTS schema 变更必须走 Alembic**:索引、扩展、generated column、operator class 变更都要纳入 migration
|
||||
26. **章节生成必须优先使用 evidence bundle**:不得只凭当前会话上下文裸生成
|
||||
|
||||
36
.cursor/rules/backend-testing-strategy.mdc
Normal file
36
.cursor/rules/backend-testing-strategy.mdc
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
description: Backend testing strategy for meaningful business coverage
|
||||
globs: api/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Backend Testing Strategy
|
||||
|
||||
- 测试必须服务真实业务场景,禁止为了覆盖率、形式化 TDD 或“顺手测一下”而堆低价值用例。
|
||||
- 自动化优先覆盖:核心用户流程、鉴权/权限/配额/幂等、关键状态写入后的持久化结果、前端依赖的稳定 HTTP 契约。
|
||||
- 不优先覆盖:第三方库自身行为、纯实现细节、脆弱的调用顺序断言、低价值 getter/常量映射。
|
||||
- 默认优先写 HTTP 场景测试,而不是先写大量细碎单元测试。
|
||||
|
||||
## Test Infrastructure
|
||||
|
||||
- 不要直接 import `api/main.py` 跑测试;避免把 `.env`、startup/shutdown、Redis、模型预热等副作用带进测试。
|
||||
- 优先使用最小 `FastAPI()` 测试 app,按需挂载目标 router。
|
||||
- 用 `app.dependency_overrides` 替换数据库和外部依赖。
|
||||
- 用 `httpx.AsyncClient` + `ASGITransport` 进行异步 HTTP 测试。
|
||||
- `api/tests/conftest.py` 和 `api/tests/factories.py` 只提供通用基础设施,不要把具体业务测试硬编码进去。
|
||||
|
||||
## Test Layering
|
||||
|
||||
- HTTP 场景测试:注册、登录、刷新、登出、受保护资源访问、关键资源 CRUD、重要失败分支。
|
||||
- 纯单元测试:纯函数、规则计算、序列化、适配器错误分支与格式转换。
|
||||
- 手工 / E2E:WebSocket 多轮对话、真实短信、Celery + Redis + LLM 编排、支付/对象存储/ASR/图像生成联调。
|
||||
|
||||
## Decision Filter
|
||||
|
||||
新增测试前先问自己:
|
||||
|
||||
1. 这个测试保护的是哪条业务承诺?
|
||||
2. 失败后能否快速定位问题边界?
|
||||
3. 这个测试是否比只测内部函数更接近真实用户行为?
|
||||
|
||||
如果答不上来 2 个以上,通常不该立刻写这个测试。
|
||||
Reference in New Issue
Block a user