- git 初始化 + .gitignore 补全(根 .env / logs / instance / __pycache__ 等) - 修复 utils/.gitignore 误将整个 utils/ 源码层忽略的问题,补入全部工具源码(含 ip2region.xdb) - 含后端全部代码:application / extensions / utils / config / migrations - 含前端 ui/(后续整体迁走) - 不含根 .env(含密钥,本地保留) Co-Authored-By: Claude <noreply@anthropic.com>
140 lines
9.0 KiB
Markdown
140 lines
9.0 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## 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:
|
|
|
|
- **`application/views/`** — Route controllers (Flask Blueprint). Each file defines routes using `@{module}_blue.route()`, decorated with `@check_permission("sys:module:action")`. Views are thin — they delegate to service functions and return `R.ok()`/`R.failed()` responses. Write operations check `FLASK_DEMO` first to block demo-mode writes.
|
|
- **`application/services/`** — Business logic layer. Contains all query building, data transformation, and orchestration. Functions receive data from `request` object directly (not passed as parameters from views). Private helpers prefixed with `_` (e.g., `_apply_filters`, `_build_page_data`).
|
|
- **`application/models/`** — SQLAlchemy models. All models inherit from `BaseModel` (provides id, create_user, create_time, update_user, update_time, is_delete fields) and `BaseDB` (provides save(), save_all(), delete() methods). Table names use `DB_PREFIX` (default `flask_`) + snake_case class name.
|
|
|
|
### AOP Transaction Management
|
|
|
|
The framework uses an AOP-style transaction interceptor (`application/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
|
|
|
|
- **`application/__init__.py`** — App factory (`create_app()`). Initialization order: Flask core -> Redis config -> DB config -> JSON encoder -> CORS -> ProxyFix -> AOP transaction -> register blueprints -> init extensions -> register middleware.
|
|
- **`application/views/__init__.py`** — Auto-discovery blueprint registration. Add module name to `_blueprint_modules` list; the system dynamically imports the module and registers any `Blueprint` instance found in it. No manual `app.register_blueprint()` needed.
|
|
- **`application/middleware/`** — `check_login` (before_request hook, JWT validation with token blacklist, whitelist matching via exact/prefix/wildcard patterns) and `check_permission` (RBAC decorator; superadmin user_id=1 bypasses all checks; internal calls via API key or IP whitelist also bypass).
|
|
- **`application/forms/`** — WTForms validation forms. All inherit `BaseForm` (in `forms/forms.py`) which handles `ArrayField` JSON serialization. Forms are instantiated with `data=json_data` from parsed request body.
|
|
- **`application/constants/`** — Shared constants: `PAGE_SIZE=10`, `DEFAULT_PASSWORD="123456"`, `MESSAGE_OK/FAIL`, `SERIALIZE_EXCLUDE_FIELDS` (is_delete, password, salt excluded from `to_dict()`).
|
|
- **`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.
|
|
- **`extensions/`** — Flask extension initialization: SQLAlchemy (`db`), Redis, APScheduler. All initialized via `register_extends(app)`.
|
|
- **`utils/`** — `R` (standardized JSON response: `{code, data, msg, ok}` where code=0 is success, code=1 is failure), `jwt` (JWT token handling with blacklist), `model_utils` (models_to_list, model_to_dict, format_datetime), `request` (parse_request_body, parse_id_list), `security` (get_user_id, get_username from JWT), `case_converter` (camelCase <-> snake_case for dict keys, recursive), `regular` (WTForms error extraction), `password` (bcrypt-based encrypt/verify — imported as `from utils import password` then used as `bcrypt.verify_password()` etc.), `captcha`, `file`, `content` (rich text + file URL handling), `redis_client`, `ip`, `user_agent`, `formatter`, `json`.
|
|
|
|
### 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
|
|
- 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 `application/models/{module}.py` inheriting `BaseModel` + `BaseDB`
|
|
2. Create service in `application/services/{module}.py` with business logic
|
|
3. Create view in `application/views/{module}.py` with routes and permission decorators
|
|
4. Add module name string to `_blueprint_modules` list in `application/views/__init__.py`
|
|
5. Create form in `application/forms/{module}.py` inheriting `BaseForm` if input validation needed
|
|
6. Add frontend API in `ui/src/api/{module}/`, views in `ui/src/views/{module}/`
|
|
|
|
## 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_*` — MySQL connection (database: `djangoadmin.flask.elevue`, prefix: `flask_`)
|
|
- `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`
|