12 KiB
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)
# 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/)
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
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/v1prefix (seesrc/routes/v1.py). Each file defines routes decorated with@check_permission("sys:module:action"). Routers parse request params, delegate to service functions, and wrap withR.ok()/R.failed(). Write operations checkFLASK_DEMOfirst (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 fromBaseModel+BaseDB(insrc/common/). Table names useDB_PREFIX(defaultflask_) + 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 activeafter_request: auto-commits on POST/PUT/DELETE/PATCH only if HTTP 2xx ANDcode==0in response JSON; auto-rollbacks on business failures (R.failedreturns HTTP 200 butcode=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/v1routes -> init extensions -> middleware -> error handlers -> DI injection.src/routes/v1.py— API v1 路由注册中心。所有业务蓝图挂载到/api/v1前缀。src/middleware/— 中间件包(按职责拆分:auth.py登录校验 + 白名单、demo.py演示模式、transaction.pyAOP 事务、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(含ArrayFieldJSON 序列化)。src/common/constants/— 共享常量:PAGE_SIZE=10,DEFAULT_PASSWORD="123456",MESSAGE_OK/FAIL,SERIALIZE_EXCLUDE_FIELDS.config/— Split intobase.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.envvia python-dotenv.config/__init__.pyloads.envbefore 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 useshttp.request()fromutils/http/axios/. The HTTP client auto-prependsVITE_GLOB_API_URL_PREFIX(/api) and sends JWT asAuthorization: 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.tstransforms backend menu tree into Vue Router routes;asyncImportRouteusesimport.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 === 0for success;code=401triggers 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
/apiprefix to backend via Vite dev server proxy (configured inui/.env.developmentasVITE_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 onlyto_dict()returns snake_case keys; services useconvert_snake_to_camelwhen frontend needs camelCase
Adding a New Module
- Create model in
src/modules/<domain>/<name>/models.pyinheritingBaseModel+BaseDB - 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
- 标准 CRUD 模块:
- Create repository in
src/modules/<domain>/<name>/repository.pyinheritingBaseRepository(标准模块需实现page(params)与list_enabled()) - Create router in
src/modules/<domain>/<name>/router.pywith routes and permission decorators - Create schema in
src/modules/<domain>/<name>/schema.pyinheritingBaseFormif input validation needed(唯一性校验用XxxRepository.exists_by(filters, exclude_id),禁止直接Model.query——查询只允许在 Repository 层) - Add the blueprint to
BLUEPRINTSlist insrc/routes/v1.py - Add frontend API in
ui/src/api/{module}/, views inui/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 startDB_*— 数据库连接,多库支持(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 connectionJWT_SALT— JWT signing key;JWT_EXPIRE_MINUTES(default 20)FLASK_DEMO— Demo mode restricts write operationsPERMISSION_ENABLED— Toggle auth middlewareINTERNAL_API_KEY— Key for scheduler/internal calls (sent asX-Internal-API-KeyorX-Scheduler-Keyheader)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