This commit is contained in:
fengchuanhn@gmail.com
2026-05-15 18:52:29 +08:00
commit cccd75767b
29 changed files with 958 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
---
description: app 包内分层编码规范API / Service / Model / Schema
globs: app/**/*
alwaysApply: false
---
# 分层编码规范
编辑 `app/` 下代码时遵循以下约定。
## api/v1路由层
- 使用 `APIRouter`,按领域分文件(如 `auth.py`),在 `router.py` 聚合。
- `response_model=ApiResponse[...]` 声明响应类型。
- 注入依赖:`DbSession`、`RedisClient`、`CurrentUser`(来自 `app.dependencies`)。
- 捕获 `services` 中的业务异常(如 `AuthError`),转为 `ApiResponse(ok=False, message=...)`。
- 不在路由内写 `select()` / `db.add()`;一行调用 service 后包装 `ApiResponse(ok=True, data=...)`。
- 副作用(写 Redis session可在路由层于 service 成功后调用,与现有 `auth.py` 一致。
## services业务层
- 函数签名显式接收 `AsyncSession` 及业务参数;返回 Pydantic schema 或简单类型。
- 业务可预期失败:`raise XxxError("中文说明")`,由 API 层捕获。
- 使用 `sqlalchemy.select` / `session.get`;密码用 `core.security.hash_password` / `verify_password`。
- 不返回 ORM 给 API 时,用 `UserPublic.model_validate(user)` 等转换。
## modelsORM
- 继承 `app.database.Base``__tablename__` 复数蛇形。
- 使用 SQLAlchemy 2 `Mapped[]` / `mapped_column`。
- 在 `app/models/__init__.py` 导出,供 Alembic `env.py` import。
## schemasPydantic
- **请求**`Field` 约束;与前端对齐的字段用 `alias` + `populate_by_name=True`(如 `confirmPassword`)。
- **响应**`model_config = ConfigDict(from_attributes=True)` 以便从 ORM 转换。
- **信封**:所有对外业务 JSON 经 `ApiResponse[T]`,勿在路由返回裸 dict`/health` 除外仍用 ApiResponse
## core
- 仅放无状态的纯函数/工具JWT、密码、常量前缀
- 不依赖 FastAPI、Session。
## dependencies
- 集中定义 `Annotated[..., Depends(...)]` 别名。
- 鉴权逻辑放在 `get_current_user`:先 Redis session再 JWT `sub` 查库。
## 命名与风格
- 文件名:领域名蛇形(`auth.py`)。
- API 路径:小写、复数资源或动词路径(`/auth/login`)。
- 用户可见 `message` 使用简体中文,与 aiclient 前端文案风格一致。