11
This commit is contained in:
53
.cursor/rules/pythonbackend-layers.mdc
Normal file
53
.cursor/rules/pythonbackend-layers.mdc
Normal 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)` 等转换。
|
||||
|
||||
## models(ORM)
|
||||
|
||||
- 继承 `app.database.Base`,`__tablename__` 复数蛇形。
|
||||
- 使用 SQLAlchemy 2 `Mapped[]` / `mapped_column`。
|
||||
- 在 `app/models/__init__.py` 导出,供 Alembic `env.py` import。
|
||||
|
||||
## schemas(Pydantic)
|
||||
|
||||
- **请求**:`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 前端文案风格一致。
|
||||
142
.cursor/rules/pythonbackend-overview.mdc
Normal file
142
.cursor/rules/pythonbackend-overview.mdc
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
description: pythonbackend 项目总览、分层架构与运行方式
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# pythonbackend 项目约定
|
||||
|
||||
aiclient 的 Python 后端,为桌面/前端提供 HTTP API。默认监听 `http://127.0.0.1:8001`(见根目录 `main.py`)。
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 组件 | 库 | 用途 |
|
||||
|------|-----|------|
|
||||
| Web | FastAPI + Uvicorn | 异步 HTTP、OpenAPI(`/docs`) |
|
||||
| 校验/配置 | Pydantic v2、`pydantic-settings` | 请求/响应模型、`.env` 配置 |
|
||||
| 数据库 | SQLAlchemy 2(async)+ **aiomysql** | MySQL 异步访问 |
|
||||
| 迁移 | Alembic | 表结构版本管理(异步 `alembic/env.py`) |
|
||||
| 缓存/会话 | **redis**(`redis.asyncio`) | JWT 会话存证、登出吊销 |
|
||||
| 安全 | passlib(bcrypt)、python-jose | 密码哈希、JWT 签发/校验 |
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
pythonbackend/
|
||||
├── main.py # 开发入口:uvicorn 启动 app.main:app
|
||||
├── requirements.txt
|
||||
├── .env / .env.example # 环境变量(不入库 .env)
|
||||
├── alembic.ini
|
||||
├── alembic/
|
||||
│ ├── env.py # 从 app.config 读 database_url,异步迁移
|
||||
│ └── versions/ # 迁移脚本
|
||||
└── app/
|
||||
├── main.py # FastAPI 工厂、CORS、lifespan、路由挂载
|
||||
├── config.py # Settings(get_settings 单例)
|
||||
├── database.py # AsyncEngine、Session、Base、get_db
|
||||
├── redis_client.py # init/close/get_redis、redis_dependency
|
||||
├── dependencies.py # FastAPI Depends(DbSession、CurrentUser 等)
|
||||
├── core/ # 与框架无关的工具(security)
|
||||
├── models/ # SQLAlchemy ORM 模型
|
||||
├── schemas/ # Pydantic 入参/出参、ApiResponse
|
||||
├── services/ # 业务逻辑(不依赖 Request/Response)
|
||||
└── api/v1/ # 路由层:薄控制器,组装 ApiResponse
|
||||
```
|
||||
|
||||
## 分层架构(自上而下)
|
||||
|
||||
```
|
||||
HTTP 请求
|
||||
→ api/v1/*.py 路由:解析 body、注入 Depends、捕获业务异常 → ApiResponse
|
||||
→ services/*.py 业务:查询/写入 DB、抛 AuthError 等,返回 schema 或模型
|
||||
→ models/*.py ORM:表定义,仅在 services / dependencies 使用
|
||||
→ database.py 连接池与 get_db(请求结束 commit,异常 rollback)
|
||||
|
||||
横切:
|
||||
→ schemas/ 请求体验证、响应类型;对外 JSON 字段 snake_case(注册 confirmPassword 例外见 auth schema)
|
||||
→ core/security.py 密码哈希、JWT、Redis session key 前缀
|
||||
→ dependencies.py 鉴权:Redis session 优先,否则回退 JWT sub
|
||||
→ redis_client.py lifespan 内 init_redis,路由经 redis_dependency 注入
|
||||
```
|
||||
|
||||
**原则**
|
||||
|
||||
- `api/` 不写 SQL、不直接操作 Redis 细节;调用 `services/`。
|
||||
- `services/` 不 import FastAPI 的 `Request`/`HTTPException`(业务错误用自定义异常,如 `AuthError`)。
|
||||
- 新增表:先 `models/` → Alembic 迁移 → 再 `schemas` + `services` + `api`。
|
||||
|
||||
## 配置(app/config.py)
|
||||
|
||||
- 从项目根 `.env` 加载,字段见 `.env.example`。
|
||||
- `database_url`:`mysql+aiomysql://...`
|
||||
- `redis_url`、`secret_key`、`access_token_expire_minutes`、`cors_origins`(逗号分隔或 `*`)。
|
||||
- 通过 `get_settings()` 获取,勿在模块顶层反复实例化 Settings。
|
||||
|
||||
## 数据库与会话
|
||||
|
||||
- `get_db()`:每个请求一个 `AsyncSession`,正常结束 `commit`,异常 `rollback`。
|
||||
- 路由使用类型别名 `DbSession = Annotated[AsyncSession, Depends(get_db)]`。
|
||||
- ORM 基类:`database.Base`;新模型须在 `alembic/env.py` 中 import 以纳入 `target_metadata`。
|
||||
|
||||
## Redis 与会话
|
||||
|
||||
- 应用 `lifespan`:`init_redis()` → 运行 → `close_redis()`。
|
||||
- 登录/注册成功:`services.auth.store_session(redis, token, user_id)`,key `session:{token}`,TTL 与 JWT 过期一致。
|
||||
- 登出:`revoke_session` 删除 key;鉴权时 Redis 无记录则回退解析 JWT(已登出会话失效)。
|
||||
|
||||
## 统一响应 ApiResponse
|
||||
|
||||
定义于 `app/schemas/common.py`:
|
||||
|
||||
- `ok: bool` — 业务是否成功
|
||||
- `message: str` — 用户可见提示(中文)
|
||||
- `data: T | None` — 成功载荷
|
||||
|
||||
业务失败(如用户名已存在)返回 **HTTP 200** + `ok: false`,勿抛未捕获异常。未认证访问受保护路由由 `dependencies.get_current_user` 抛 **401**(非 ApiResponse 信封)。
|
||||
|
||||
前端约定详见 aiclient 仓库 `.cursor/rules/aiclient-overview.mdc` 中「后端 API 约定」一节。
|
||||
|
||||
## 认证模块(当前实现)
|
||||
|
||||
| 层 | 文件 |
|
||||
|----|------|
|
||||
| 路由 | `app/api/v1/auth.py` |
|
||||
| 业务 | `app/services/auth.py` |
|
||||
| 模型 | `app/models/user.py` |
|
||||
| Schema | `app/schemas/auth.py` |
|
||||
| 挂载 | `app/api/v1/router.py` → `app/main.py` 前缀 `/api/v1` |
|
||||
|
||||
端点:`POST /auth/register|login|logout`,`GET /auth/me`;根路径 `GET /health`。
|
||||
|
||||
## Alembic
|
||||
|
||||
```bash
|
||||
# 项目根目录,激活 venv 后
|
||||
alembic upgrade head # 应用迁移
|
||||
alembic revision -m "描述" # 新建迁移(需人工编写 upgrade/downgrade)
|
||||
```
|
||||
|
||||
- `alembic/env.py` 使用异步引擎,URL 来自 `Settings.database_url`。
|
||||
- 改表后必须提交 `alembic/versions/` 下的迁移文件。
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
alembic upgrade head
|
||||
python main.py # 或: uvicorn app.main:app --reload --port 8001
|
||||
```
|
||||
|
||||
## 新增功能 checklist
|
||||
|
||||
1. `app/models/` 定义 ORM(如需持久化)
|
||||
2. `alembic revision` + `upgrade head`
|
||||
3. `app/schemas/` 请求/响应模型
|
||||
4. `app/services/` 业务函数
|
||||
5. `app/api/v1/` 路由,挂到 `router.py`
|
||||
6. 需登录:`dependencies.CurrentUser`;需 Redis:参数 `RedisClient`
|
||||
7. 对外 JSON 保持 `ApiResponse` 信封;错误文案简体中文
|
||||
|
||||
## 通用原则
|
||||
|
||||
- Python 3.11+ 类型注解;异步路由与 async service 一致。
|
||||
- 密码仅存 `password_hash`,禁止日志或响应中输出明文密码。
|
||||
- 生产环境必须修改 `SECRET_KEY`,勿提交 `.env`。
|
||||
Reference in New Issue
Block a user