# AI 开发提示词 — 项目架构与模块开发规范

> 在向 AI 提出开发需求时，将以下提示词附加在需求描述之后，AI 即可按照项目架构规范生成代码，避免多人协作时的合并冲突。

---

## 提示词内容（复制到你的需求后面）

```
## 项目架构与模块开发规范

### 一、项目概述

Under18 是一个前后端分离的 RBAC 权限管理脚手架，提供用户、角色、权限、字典、标签、日志等通用功能模块。采用模块化自动注册架构，新增功能模块时**严禁修改任何共享/公共文件**，所有新代码必须放在独立模块文件中。

**技术栈：**
- 后端：FastAPI + SQLAlchemy（异步）+ PostgreSQL + Alembic
- 前端：Vue 3 + Vite 5 + Element Plus + Pinia + Vue Router 4
- 缓存：cachetools.TTLCache（进程内，替代 Redis）
- 认证：JWT（HS256），Access Token 120min + Refresh Token 7天

### 二、后端规范（FastAPI）

#### 2.1 分层架构

```
API 层 (app/api/{模块名}.py)        — 路由定义、参数校验(Schema)、权限注入、响应封装
  ↓ 调用
Service 层 (app/services/{模块名}_service.py) — 纯业务逻辑，静态方法，接收 AsyncSession
  ↓ 操作
Model 层 (app/models/{模块名}.py)   — ORM 映射，继承 Base + TimestampMixin + SoftDeleteMixin
```

#### 2.2 新增模块只需创建以下独立文件，不需要修改任何已有文件：

1. **`backend/app/models/{模块名}.py`** — ORM 模型定义
   - 从 `app.core.database` 导入 `Base`
   - 从 `app.models.mixins` 导入 `TimestampMixin, SoftDeleteMixin`（日志类模型可不加 SoftDeleteMixin）
   - 模型类继承：`class SysXxx(Base, TimestampMixin, SoftDeleteMixin)`
   - 关联表（many-to-many）使用 `Table()` 定义在同一文件中
   - 每个模型需实现 `to_dict()` 方法手动序列化
   - 表名统一使用 `sys_` 前缀

2. **`backend/app/schemas/{模块名}.py`** — Pydantic 请求/响应模型
   - 每个模块的 schema 独立一个文件
   - 命名规范：`XxxCreateRequest`、`XxxUpdateRequest`、`XxxQueryRequest`
   - 从 `app.schemas.response` 导入 `PageQuery` 作为分页查询基类

3. **`backend/app/services/{模块名}_service.py`** — 业务逻辑层
   - 类名必须以 `Service` 结尾（如 `ArticleService`），全部使用 `@staticmethod`
   - 从 `app.models.{模块名}` 导入模型（不要从 app.models 或 app.models.models 导入）
   - 从 `app.schemas.{模块名}` 导入 schema（不要从 app.schemas.request 导入）
   - 所有方法第一个参数为 `db: AsyncSession`
   - 调用方式：`ArticleService.get_list(db, ...)`

4. **`backend/app/api/{模块名}.py`** — API 路由
   - 必须导出名为 `router` 的 `APIRouter` 实例
   - 示例：`router = APIRouter(prefix="/xxx", tags=["XXX管理"])`
   - 所有路由自动加上 `/api` 前缀（由 `api_router = APIRouter(prefix="/api")` 控制）
   - 从 `app.core.deps` 导入 `get_current_user`、`require_permission`
   - 从 `app.schemas.response` 导入 `success`、`error`、`page_result`
   - 路由文件会被 `app/api/__init__.py` 自动扫描注册，**不要修改 __init__.py**

#### 2.3 自动注册机制

| 层 | 扫描规则 | 约定 |
|----|---------|------|
| API 路由 | 扫描 `app/api/` 下所有 `.py`，查找 `router` 变量 | 文件必须导出 `router = APIRouter(...)` |
| Model | 扫描 `app/models/` 下所有 `.py`（跳过 `__init__.py` 和 `mixins.py`） | 确保模型被导入到 Base.metadata |
| Service | 扫描 `app/services/` 下所有 `_service.py`，收集以 `Service` 结尾的类 | 可直接 `from app.services import XxxService` |

**因此绝对不需要修改任何 `__init__.py` 文件。**

#### 2.4 已有模型导入路径

```python
from app.models.user import SysUser, sys_user_role       # 用户 + 用户角色关联表
from app.models.role import SysRole, sys_role_permission  # 角色 + 角色权限关联表
from app.models.permission import SysPermission           # 权限
from app.models.dict import SysDictType, SysDictData      # 字典类型 + 字典数据
from app.models.log import SysOperationLog, SysLoginLog   # 操作日志 + 登录日志
from app.models.tag import SysTag, sys_tag_object         # 标签 + 标签对象关联表
from app.models.mixins import TimestampMixin, SoftDeleteMixin  # 通用混入
```

#### 2.5 响应格式统一

```python
from app.schemas.response import success, error, page_result

# 成功：return success(data=xxx)
# 失败：return error(message="xxx", code=400)
# 分页：return page_result(items=xxx, total=xxx, page=xxx, page_size=xxx)
```

响应体格式：
```json
{ "code": 200, "message": "success", "data": {...} }
{ "code": 200, "message": "success", "data": { "items": [], "total": 0, "page": 1, "page_size": 10 } }
{ "code": 400, "message": "错误信息", "data": null }
```

#### 2.6 权限校验

- **路由级**：`dependencies=[Depends(require_permission("模块:资源:操作"))]`
- **按钮级**：前端使用 `v-permission="'模块:资源:操作'"` 指令
- **权限编码格式**：`模块:资源:操作`，如 `content:article:list`
- **超级管理员豁免**：角色为 `admin` 的用户自动拥有全部权限

#### 2.7 认证与安全

- **密码加密**：`SHA-256(password + user_salt + global_salt)`，双重加盐
- **Token 体系**：Access Token（120min）+ Refresh Token（7天），HS256 算法
- **登录安全**：连续3次失败强制验证码；同IP 10次失败锁定30分钟；每IP每分钟限20次登录请求
- **获取客户端IP**：使用 `SecurityMiddleware._get_client_ip(request)`

#### 2.8 数据库与配置

- **数据库**：PostgreSQL，异步驱动 asyncpg，连接由 `app.core.database` 管理
- **迁移**：Alembic，通过 `alembic revision --autogenerate` 生成
- **配置**：唯一来源 `config.yaml`，环境变量 `UNDER18_<键名>` 可覆盖
- **依赖注入**：`get_db()` 提供 AsyncSession，`get_current_user()` 提供当前用户

#### 2.9 路由定义注意事项

- 批量操作路由（如 `/batch`、`/clear/all`）必须定义在通配符路由（如 `/{id}`）之前，否则会被通配符匹配拦截

### 三、前端规范（Vue3 + Vite）

#### 3.1 新增模块只需创建以下独立文件，不需要修改任何已有文件：

1. **`frontend/src/router/modules/{模块名}.js`** — 路由配置
   - 必须 `export default` 一个路由配置对象
   - 会被 `router/index.js` 通过 `import.meta.glob` 自动扫描加载
   - **不要修改 `router/index.js`**

2. **`frontend/src/views/{模块路径}/{子路由}/index.vue`** — 页面组件
   - 视图文件路径必须与路由中的 `component` 导入路径一致

3. **`frontend/src/api/{模块名}.js`** — API 调用函数
   - 从 `@/utils/request` 导入 axios 实例
   - 函数命名：`getXxxList`、`createXxx`、`updateXxx`、`deleteXxx`

#### 3.2 路由配置模板

```javascript
// frontend/src/router/modules/{模块名}.js
export default {
  path: '/{模块路径}',
  component: () => import('@/layout/index.vue'),
  redirect: '/{模块路径}/{默认子路由}',
  meta: { title: '{菜单名称}', icon: '{ElementPlus图标名}' },
  children: [
    {
      path: '{子路由}',
      name: '{路由名}',
      component: () => import('@/views/{模块路径}/{子路由}/index.vue'),
      meta: { title: '{页面标题}', icon: '{图标}', permission: '{权限码}' },
    },
  ],
}
```

#### 3.3 侧边栏与权限

- 侧边栏菜单从 `router/modules/` 下的路由配置自动生成，**不需要修改 Sidebar.vue**
- 路由级权限：`meta.permission` 字段 + `filterRoutes()` 过滤无权限路由
- 按钮级权限：`v-permission="'模块:资源:操作'"` 指令，无权限则隐藏元素

#### 3.4 Store 与工具

- **用户状态**：`store/user.js` — token、userInfo、权限列表，手动同步 localStorage
- **应用状态**：`store/app.js` — 侧边栏折叠、设备类型
- **HTTP 请求**：`utils/request.js` — Axios 封装，自动添加 Bearer Token，统一错误处理（401弹窗重新登录、403无权限、429限流、500服务异常）
- **日期格式化**：`utils/index.js` 的 `formatDate()` 函数
- **防抖**：`utils/index.js` 的 `debounce()` 函数

#### 3.5 样式约定

- 主题色：`#2d9d5e`（绿色系），通过 CSS 变量覆盖 Element Plus 默认主题
- 布局变量：`--sidebar-width: 220px`，`--header-height: 56px`
- 新页面样式使用 `<style scoped>`，全局样式放在 `styles/` 目录

### 四、禁止修改的文件清单

以下文件是公共注册文件或核心基础设施，多人同时修改会导致严重合并冲突，**绝对禁止修改**：

**后端：**
- `app/api/__init__.py` — 路由自动注册
- `app/models/__init__.py` — 模型自动注册
- `app/services/__init__.py` — 服务自动注册
- `app/schemas/response.py` — 通用响应格式
- `app/core/` 目录下所有文件 — 核心基础设施（数据库、安全、中间件、缓存、依赖注入、配置）
- `app/main.py` — 应用入口

**前端：**
- `src/router/index.js` — 路由自动注册入口 + 守卫
- `src/layout/` 目录下所有文件 — 布局组件（侧边栏、顶栏）
- `src/utils/` 目录下所有文件 — 通用工具
- `src/store/` 目录下所有文件 — 全局状态管理
- `src/styles/` 目录下所有文件 — 全局样式
- `src/main.js` — 应用入口

### 五、命名规范速查

| 层 | 文件名 | 类/变量名 | 数据库表名 |
|----|--------|----------|-----------|
| Model | `{模块名}.py` | `Sys{Entity}` | `sys_{entity}` |
| Schema | `{模块名}.py` | `{Entity}CreateRequest` / `{Entity}UpdateRequest` | — |
| Service | `{模块名}_service.py` | `{Entity}Service` | — |
| API | `{模块名}.py` | `router = APIRouter(prefix="/模块/资源")` | — |
| 权限编码 | — | `模块:资源:操作` | — |
| 前端路由 | `modules/{模块名}.js` | `export default { path: '/模块路径', ... }` | — |
| 前端API | `api/{模块名}.js` | `getXxxList` / `createXxx` / `updateXxx` / `deleteXxx` | — |
```

---

## 使用示例

假设你要开发一个"文章管理"模块，向 AI 提问时这样写：

> 请帮我开发一个"文章管理"功能模块，包含文章的增删改查，文章有标题、内容、分类、状态（草稿/发布）等字段。
>
> [粘贴上面的提示词内容]

AI 就会：
- 创建 `backend/app/models/article.py`（不碰 models/__init__.py）
- 创建 `backend/app/schemas/article.py`（独立文件）
- 创建 `backend/app/services/article_service.py`（不碰 services/__init__.py）
- 创建 `backend/app/api/article.py`（不碰 api/__init__.py）
- 创建 `frontend/src/router/modules/article.js`（不碰 router/index.js）
- 创建 `frontend/src/views/article/index.vue`
- 创建 `frontend/src/api/article.js`

每个文件都是独立的，不同人开发不同模块，零冲突！

---

## 六、部署与启动注意事项

### 6.1 前端启动问题：根目录误装 node_modules

**问题描述：** 在项目根目录（`under18/`）下执行 `npm install` 会生成根目录的 `package.json`、`package-lock.json` 和 `node_modules/`，导致 `npx vite` 使用根目录的 Vite（版本可能不一致且依赖不完整）而非 `frontend/node_modules/` 中完整版本的 Vite，表现为 Vite 启动后所有请求返回 404。

**典型场景：** 在根目录安装全局依赖（如 `npm install echarts`）时误装到了根目录而非 `frontend/` 目录。

**正确做法：**
- 前端依赖安装必须在 `frontend/` 目录下执行：`cd frontend && npm install xxx --save`
- 启动前端时使用 frontend 自带的 Vite：`cd frontend && npx vite` 或 `cd frontend && node_modules/.bin/vite`
- **禁止在项目根目录下执行 `npm install`**

**如已误装，清理方法：**
```bash
# 删除根目录下误装的文件
rm package.json package-lock.json
rm -rf node_modules/
```

### 6.2 后端启动：PYTHONPATH 设置

**问题描述：** 直接在 `backend/` 目录执行 `uvicorn app.main:app` 可能报 `ModuleNotFoundError: No module named 'app'`，因为 Python 找不到 `app` 包。

**正确启动方式：**
```bash
cd backend
set PYTHONPATH=c:\Users\hunter\Desktop\under18\backend   # Windows
# export PYTHONPATH=/path/to/under18/backend              # Linux/Mac
venv/Scripts/python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
```

### 6.3 完整启动流程

**前置条件：**
- 数据库使用远程 PostgreSQL（`config.yaml` 中配置的 `111.229.199.210:12345`），无需本地启动
- Python 虚拟环境位于项目根目录 `venv/`
- 前端依赖已安装在 `frontend/node_modules/`

**启动步骤：**
```bash
# 1. 启动后端
cd c:\Users\hunter\Desktop\under18\backend
set PYTHONPATH=c:\Users\hunter\Desktop\under18\backend
c:\Users\hunter\Desktop\under18\venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

# 2. 启动前端（新终端）
cd c:\Users\hunter\Desktop\under18\frontend
npx vite --host 0.0.0.0 --port 5173
# 或使用完整路径：node_modules\.bin\vite --host 0.0.0.0 --port 5173

# 3. 访问
# 前端：http://localhost:5173
# 后端API文档：http://127.0.0.1:8000/api/docs
# 后端健康检查：http://127.0.0.1:8000/api/health
```

### 6.4 生产构建

```bash
cd frontend
npm run build    # 输出到 frontend/dist/
```

构建产物为静态文件，需配合 Nginx 等Web服务器部署，并配置 `/api` 反向代理到后端。
