Files
DjangoAdmin_Flask_EleVue/CLAUDE.md
T
2026-09-12 18:57:19 +08:00

153 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
> **重构状态**:项目已按《重构方案-v2.md》完成 P1-P7 全部阶段。
> 后端源码位于 `src/`(core/common/modules/routes),API 统一 `/api/v1` 前缀,
> 服务层为「入参数据/出参数据 + BizError」范式,全项目 flake8 零告警。
## Project Overview
DjangoAdmin Flask+EleVue is a separated frontend-backend admin framework. Backend: Flask + SQLAlchemy + MySQL + Redis. Frontend: Vue 3 + Element Plus + TypeScript + Vite + Pinia. The project is primarily documented and commented in Chinese.
## Development Commands
### Backend (Python/Flask)
```bash
# Install dependencies
pip install -r requirements.txt
# Run dev server (default: 127.0.0.1:8021)
python app.py
# Database migrations (Flask-Migrate/Alembic)
flask db init # Initialize migration repository (already done)
flask db migrate # Generate migration from model changes
flask db upgrade # Apply migrations
flask db downgrade # Rollback migration
```
### Frontend (Vue 3 / ui/)
```bash
cd ui
# Install dependencies (uses pnpm)
pnpm install
# Run dev server (default: localhost:8001, proxies /api to backend :8021)
pnpm run dev
# Build for production
pnpm run build:prod
# Lint
pnpm run lint:eslint
pnpm run lint:prettier
pnpm run lint:stylelint
# Type check
pnpm run type:check
```
### Docker
```bash
cd docker
docker-compose up -d
```
## Architecture
### Backend Structure (Three-Layer Pattern)
Each business module follows a strict **View -> Service -> Model** separation:
- **`src/modules/<domain>/<name>/router.py`** — Route controllers (Flask Blueprint). Registered under `/api/v1` prefix (see `src/routes/v1.py`). Each file defines routes decorated with `@check_permission("sys:module:action")`. Routers parse request params, delegate to service functions, and wrap with `R.ok()`/`R.failed()`. Write operations check `FLASK_DEMO` first (via `@check_demo`).
- **`src/modules/<domain>/<name>/service.py`** — Business logic layer. **服务函数「入参数据/出参数据」**(不直接读 `request`,不返回 R);业务失败 `raise BizError`;私有辅助函数以 `_` 开头。数据访问委托 repository。标准 CRUD 模块继承 `BaseService`(`src/common/base_service.py`,含 page/detail/add/update/remove/update_status/list 模板方法 + before_*/after_*/_detail_dict/_enrich_page_records 覆写钩子),模块级代理函数暴露给 router 调用(router 零改动)。
- **`src/modules/<domain>/<name>/models.py`** — SQLAlchemy models. All models inherit from `BaseModel` + `BaseDB` (in `src/common/`). Table names use `DB_PREFIX` (default `flask_`) + snake_case class name.
- **`src/modules/<domain>/<name>/repository.py`** — 数据访问层,继承 `BaseRepository`(`src/common/base_repository.py`)。
### AOP Transaction Management
The framework uses an AOP-style transaction interceptor (`src/middleware/transaction.py`) registered via `register_transaction(app)`. **Business code never calls commit/rollback directly.**
- `before_request`: marks transaction active
- `after_request`: auto-commits on POST/PUT/DELETE/PATCH only if HTTP 2xx AND `code==0` in response JSON; auto-rollbacks on business failures (`R.failed` returns HTTP 200 but `code=1`)
- `teardown_request`: rollback on unhandled exceptions
`BaseDB.save()` and `BaseDB.save_all()` call `db.session.flush()` only — the AOP interceptor handles commit. For special cases, use `@transactional` decorator, `@transactional_response` decorator, or `TransactionContext` context manager.
### Key Backend Modules
- **`src/app.py`** — App factory (`create_app()`). Initialization order: Flask core -> Redis config -> DB config -> JSON encoder -> CORS -> ProxyFix -> op_log/transaction -> register `/api/v1` routes -> init extensions -> middleware -> error handlers -> DI injection.
- **`src/routes/v1.py`** — API v1 路由注册中心。所有业务蓝图挂载到 `/api/v1` 前缀。
- **`src/middleware/`** — 中间件包(按职责拆分:`auth.py` 登录校验 + 白名单、`demo.py` 演示模式、`transaction.py` AOP 事务、`operation_log.py` 操作日志 + `@operation_log` 标题装饰器、`errors.py` 异常处理)。对外统一 `from src.middleware import ...`。
- **`src/core/permission.py`** — `check_permission` (RBAC decorator; superadmin user_id=1 bypasses; 权限数据通过 `current_app.extensions['permission_provider']` 注入,见 `src/app.py` `_inject_dependencies`).
- **`src/core/exceptions.py`** — `BizError` 业务异常(业务层 `raise BizError` 统一转 `R.failed`)。
- **`src/common/forms/`** — WTForms 验证表单。继承 `BaseForm`(含 `ArrayField` JSON 序列化)。
- **`src/common/constants/`** — 共享常量:`PAGE_SIZE=10`, `DEFAULT_PASSWORD="123456"`, `MESSAGE_OK/FAIL`, `SERIALIZE_EXCLUDE_FIELDS`.
- **`config/`** — Split into `base.py` (Flask host/port/debug/paths), `database.py` (SQLAlchemy URI, SSL options), `redis.py` (Redis URL), `auth.py` (JWT salt, permission toggle, login whitelist, internal API key). All read from `.env` via python-dotenv. `config/__init__.py` loads `.env` before any sub-module imports.
- **`src/extensions.py`** — Flask extension registration orchestration (`register_extends(app)`). 实例定义在 `src/core/`(database/redis_client/mail/scheduler)。
- **`src/core/`** — `response`(R 统一响应)、`jwt`、`password`(bcrypt)、`security`(get_user_id/get_username)、`redis_client`。
- **`src/common/utils/`** — `model_utils`(models_to_list/model_to_dict)、`request`(parse_request_body/parse_id_list)、`case_converter`(camelCase <-> snake_case)、`regular`(WTForms 错误提取)、`captcha`、`file`、`rich_text`、`ip`、`user_agent`、`formatter`、`json`、`ip2region`.
### Frontend Structure (ui/src/)
- **`api/`** — Axios API calls organized by module. Each function uses `http.request()` from `utils/http/axios/`. The HTTP client auto-prepends `VITE_GLOB_API_URL_PREFIX` (`/api`) and sends JWT as `Authorization: Bearer <token>`.
- **`views/`** — Page components matching backend modules (system, content, monitor, etc.).
- **`router/`** — Vue Router with dynamic route generation from backend menu data. `generator-routers.ts` transforms backend menu tree into Vue Router routes; `asyncImportRoute` uses `import.meta.glob('../views/**/*.{vue,tsx}')` for lazy loading.
- **`store/`** — Pinia stores: `user` (auth state), `asyncRoute` (dynamic routes), `projectSetting`, `tabsView`, `lockscreen`, `ossConfig`.
- **`components/`** — Reusable UI components.
- **`layout/`** — Main layout shell (sidebar, header, content area).
- **`hooks/`** — Composable functions.
- **`utils/`** — Frontend utilities (HTTP client with interceptors, date formatting, etc.).
### API Conventions
- Backend routes follow RESTful patterns: `GET /{module}/page`, `GET /{module}/detail/<id>`, `POST /{module}/add`, `PUT /{module}/update`, `DELETE /{module}/delete/<id>`, `PUT /{module}/status`, `GET /{module}/list`
- All responses use `R.ok(data=...)` / `R.failed(msg=...)` format with `{code, data, msg, ok}` structure
- Frontend response handler checks `code === 0` for success; `code=401` triggers re-login
- **统一约定:所有响应(含认证/权限失败 401/403)返回 HTTP 200 + 业务 code**,不返回对应 HTTP 状态码——前端按 `code` 判断(401 重登、403 无权限)。若需按 HTTP 状态码防护(WAF/代理),应解析业务 code 而非 HTTP status
- Permission strings follow pattern: `sys:module:action` (e.g., `sys:user:page`, `sys:role:add`)
- Frontend proxies `/api` prefix to backend via Vite dev server proxy (configured in `ui/.env.development` as `VITE_PROXY=[["/api","http://127.0.0.1:8021/"]]`)
### Naming Conventions
- Backend service functions: snake_case (e.g., `get_user_page`, `add_user`)
- Backend model tables: `flask_` prefix + snake_case (e.g., `flask_user`, `flask_role`)
- Service layer uses camelCase for parameters/return keys (matching frontend), snake_case for DB fields
- Private service functions prefixed with `_` (e.g., `_apply_filters`, `_build_page_data`)
- `BaseModel.__init__` auto-converts camelCase kwargs to snake_case and filters to valid model columns only
- `to_dict()` returns snake_case keys; services use `convert_snake_to_camel` when frontend needs camelCase
### Adding a New Module
1. Create model in `src/modules/<domain>/<name>/models.py` inheriting `BaseModel` + `BaseDB`
2. Create service in `src/modules/<domain>/<name>/service.py`(入参数据/出参数据 + raise BizError):
- 标准 CRUD 模块:`class XxxService(BaseService)` 指定 `repository/form/status_form/model_name`,差异逻辑覆写钩子,末尾暴露模块级代理函数(如 `get_xxx_page = XxxService.get_page`)供 router 调用
- 深度定制模块(如 user/auth):保持模块级函数 + raise BizError
3. Create repository in `src/modules/<domain>/<name>/repository.py` inheriting `BaseRepository`(标准模块需实现 `page(params)` 与 `list_enabled()`)
4. Create router in `src/modules/<domain>/<name>/router.py` with routes and permission decorators
5. Create schema in `src/modules/<domain>/<name>/schema.py` inheriting `BaseForm` if input validation needed(唯一性校验用 `XxxRepository.exists_by(filters, exclude_id)`,禁止直接 `Model.query`——查询只允许在 Repository 层)
6. Add the blueprint to `BLUEPRINTS` list in `src/routes/v1.py`
7. Add frontend API in `ui/src/api/{module}/`, views in `ui/src/views/{module}/`(API 前缀 /api/v1)
## Environment Configuration
All config is in `.env` at project root. Key settings:
- `FLASK_HOST` / `FLASK_PORT` (default 127.0.0.1:8021)
- `FLASK_SECRET_KEY` — must be >= 16 chars or app refuses to start
- `DB_*` — 数据库连接,**多库支持**(`config/database.py` 的 `_build_database_url()` 按 `DB_DRIVER` 构建 URL):`mysql`(默认)/`postgresql`/`mssql`/`sqlite`/`oracle`(oracledb 驱动,thin 模式无需 Oracle Client;`DB_DATABASE` 填 SERVICE_NAME)。切换只需改 `DB_DRIVER` + 账号,然后运行 `python scripts/setup_db.py`(`create_all` 建表 + 种子数据,幂等)。注意:`flask db migrate/upgrade`(方案 B)仍针对 MySQL,新建其它库请用 `scripts/setup_db.py`
- **跨库数据迁移**:`python scripts/migrate_db.py --src-driver=mysql --src-host=127.0.0.1 --src-port=3306 --src-db=<源库名> --src-user=root --src-pass=<密码> --dst-driver=postgresql --dst-host=127.0.0.1 --dst-port=5432 --dst-db=<目标库名> --dst-user=postgres --dst-pass=<密码> --drop-target-first`。CLI 显式参数、不依赖 `.env`;源/目标均支持 `mysql/postgresql/mssql/sqlite/oracle`(别名 `postgres=postgresql`、`sqlserver=mssql`、`sqlite3=sqlite`),自动建目标库 + `create_all` 建表 + 逐表泵数据 + 按方言重置自增(PG setval / MSSQL CHECKIDENT / Oracle 补 sequence+触发器)+ 逐表行数校验;先加 `--dry-run` 干跑核对计划
- `REDIS_*` — Redis connection
- `JWT_SALT` — JWT signing key; `JWT_EXPIRE_MINUTES` (default 20)
- `FLASK_DEMO` — Demo mode restricts write operations
- `PERMISSION_ENABLED` — Toggle auth middleware
- `INTERNAL_API_KEY` — Key for scheduler/internal calls (sent as `X-Internal-API-Key` or `X-Scheduler-Key` header)
- `LOGIN_WHITELIST_*` — Paths exempt from login check (exact, prefix, wildcard patterns)
- `PROXY_NUM` — Trusted proxy count for ProxyFix (0=none, 1=Nginx)
Frontend env in `ui/.env.development`: `VITE_PORT=8001`, `VITE_PROXY`, `VITE_GLOB_API_URL_PREFIX=/api`