# Jimeng Clone — AI Video Generation Platform > This file is the single source of truth for AI-assisted development on this project. > AI agents (including Claude Code) should read this file first before making any changes. ## Quick Start ### Development Environment - **Backend**: Python 3.12 + Django 4.2 + DRF + SimpleJWT - **Frontend**: React 18 + Vite 6 + TypeScript 5 + Zustand - **Database**: SQLite (dev) / Aliyun RDS MySQL (prod) - **UI Library**: Arco Design (`@arco-design/web-react`) - **Charts**: ECharts 6 + echarts-for-react ### Setup Commands ```bash # Backend cd backend python -m venv venv && source venv/bin/activate pip install -r requirements.txt python manage.py migrate python manage.py runserver 8000 # Frontend cd web npm install npm run dev # Dev server at localhost:5173 npm run build # Production build: tsc -b && vite build ``` ### Test Commands ```bash # Frontend unit tests cd web && npx vitest run # Backend checks cd backend && python manage.py check ``` ### Admin Credentials (Dev) - Username: `admin` / Password: `admin123` ## Project Architecture ### Directory Structure ``` jimeng-clone/ ├── backend/ # Django REST Framework backend │ ├── config/ # Django settings, urls, wsgi │ │ ├── settings.py # Main config (DB, CORS, JWT, apps) │ │ └── urls.py # Root URL routing │ ├── apps/ │ │ ├── accounts/ # User auth: models, views, serializers, urls │ │ └── generation/ # Video generation: models, views, serializers, urls │ ├── requirements.txt # Python dependencies │ └── Dockerfile # Python 3.12 + gunicorn ├── web/ # React 18 + Vite frontend │ ├── src/ │ │ ├── App.tsx # Root router (all routes defined here) │ │ ├── main.tsx # Entry point │ │ ├── pages/ # Page-level components (one per route) │ │ ├── components/ # Reusable UI components │ │ ├── store/ # Zustand state stores │ │ ├── lib/ # Utilities (API client, log center) │ │ └── types/ # TypeScript type definitions │ ├── nginx.conf # Production nginx config │ └── Dockerfile # Node 18 + nginx ├── k8s/ # Kubernetes deployment configs ├── docs/ # PRD, design review documents ├── .gitea/workflows/ # CI/CD pipeline └── .autonomous/ # Autonomous skill task tracking ``` ### Key Files (Most Commonly Modified) - `web/src/App.tsx` — Route definitions. Modify when adding new pages. - `web/src/store/auth.ts` — Auth state (login/logout/JWT refresh) - `web/src/store/generation.ts` — Video generation state & API calls - `web/src/store/inputBar.ts` — Input bar state (mode, files, prompt) - `web/src/lib/api.ts` — Axios client with JWT interceptor. API base URL configured here. - `web/src/types/index.ts` — All TypeScript interfaces - `backend/config/settings.py` — Django settings (DB, CORS, JWT, installed apps) - `backend/config/urls.py` — Root URL routing - `backend/apps/accounts/models.py` — User model (extends AbstractUser) - `backend/apps/generation/models.py` — GenerationRecord + QuotaConfig models - `backend/apps/generation/views.py` — All API endpoints (video, admin, profile) - `backend/apps/generation/urls.py` — API URL patterns ## Development Conventions ### Code Style - **Frontend**: TypeScript strict mode, functional components, named exports - **Backend**: PEP 8, function-based views with `@api_view` decorator - **CSS**: Inline styles + Arco Design component props (no separate CSS modules) ### Naming Conventions - **React Components**: PascalCase files (e.g., `LoginPage.tsx`, `InputBar.tsx`) - **Stores**: camelCase files (e.g., `auth.ts`, `generation.ts`) - **Django Apps**: lowercase (e.g., `accounts`, `generation`) - **API URLs**: `/api/v1/` prefix, no trailing slashes in URL patterns - **Database**: snake_case (Django default) ### State Management Pattern - Zustand stores in `web/src/store/`, one store per domain - Each store exports a `use[Name]Store` hook - API calls are defined inside stores (not in components) - Pattern: `const doSomething = useAuthStore((s) => s.doSomething)` ### Component Pattern - Pages in `web/src/pages/` — full-page components mounted by router - Reusable components in `web/src/components/` - Protected routes use `` wrapper, admin routes add `requireAdmin` prop ### Backend Pattern - Function-based views with `@api_view(['GET', 'POST'])` decorator - Auth via `@permission_classes([IsAuthenticated])` - Admin endpoints check `request.user.is_staff` - Singleton pattern for QuotaConfig (pk always = 1) ## API Endpoints ### Auth (`/api/v1/auth/`) | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/v1/auth/register` | User registration (disabled) | | POST | `/api/v1/auth/login` | JWT login (returns access + refresh tokens, creates ActiveSession) | | POST | `/api/v1/auth/token/refresh` | Refresh JWT access token | | GET | `/api/v1/auth/me` | Get current user info + quota + team + must_change_password | | POST | `/api/v1/auth/change-password` | Change own password (clears must_change_password) | ### Video Generation (`/api/v1/`) | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/v1/media/upload` | Upload reference media files | | POST | `/api/v1/video/generate` | Submit video generation task | | GET | `/api/v1/video/tasks` | List user's generation tasks | | GET | `/api/v1/video/tasks/` | Get task status & result | ### Admin (`/api/v1/admin/`) | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/admin/stats` | Dashboard statistics & charts data | | GET | `/api/v1/admin/users` | List all users (search, filter, paginate) | | POST | `/api/v1/admin/users/create` | Create new user | | GET/PUT | `/api/v1/admin/users/` | Get/update user details | | PUT | `/api/v1/admin/users//quota` | Update user quota limits | | PUT | `/api/v1/admin/users//status` | Toggle user active status | | GET | `/api/v1/admin/records` | List all generation records | | GET/PUT | `/api/v1/admin/settings` | Get/update global settings (QuotaConfig) | | GET | `/api/v1/admin/teams` | List all teams | | POST | `/api/v1/admin/teams/create` | Create new team | | GET/PUT | `/api/v1/admin/teams/` | Get/update team details | | POST | `/api/v1/admin/teams//topup` | Add seconds to team pool | | PUT | `/api/v1/admin/teams//set-pool` | Directly set team total seconds pool | | POST | `/api/v1/admin/teams//admin` | Create team admin user | | GET | `/api/v1/admin/logs` | Audit logs (filter by action/operator/date) | | GET | `/api/v1/admin/assets/overview` | Content assets: global stats + per-team summary | | GET | `/api/v1/admin/assets/team//members` | Content assets: team members with video stats | | GET | `/api/v1/admin/assets/user//videos` | Content assets: user's completed videos (paginated) | ### Team Admin Assets (`/api/v1/team/assets/`) | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/team/assets/overview` | Team stats + per-member video summary | | GET | `/api/v1/team/assets/member//videos` | Member's completed videos (paginated) | ### Profile (`/api/v1/profile/`) | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/v1/profile/overview` | User consumption summary | | GET | `/api/v1/profile/records` | User's own generation records | ## Database Models ### User (extends AbstractUser) - `email` (unique), `daily_seconds_limit` (default: 600), `monthly_seconds_limit` (default: 6000) - `must_change_password` (default: True) — forces password change on first login - `team` (FK to Team), `is_team_admin` - `created_at`, `updated_at` ### GenerationRecord - `user` (FK), `task_id` (UUID), `ark_task_id`, `prompt`, `mode` (universal|keyframe) - `model` (seedance_2.0|seedance_2.0_fast), `aspect_ratio`, `duration`, `seconds_consumed` - `status` (queued|processing|completed|failed), `result_url`, `error_message`, `reference_urls` (JSON) - Index: (user, created_at) ### AdminAuditLog - `operator` (FK User, SET_NULL), `operator_name` (denormalized), `action` (12 choices) - `target_type`, `target_id`, `target_name`, `before` (JSON), `after` (JSON) - `ip_address`, `created_at` (indexed) ### ActiveSession - `user` (FK), `session_id` (UUID, unique), `device_type` (desktop|mobile|unknown) - `user_agent`, `created_at` - Used for concurrent session limiting via JWT session_id claim ### LoginRecord - `user` (FK), `ip_address`, `user_agent`, `created_at` (indexed) - Records every login for future anomaly detection ### QuotaConfig (Singleton, pk=1) - `default_daily_seconds_limit`, `default_monthly_seconds_limit` - `announcement`, `announcement_enabled` - `max_desktop_sessions` (default: 1), `max_mobile_sessions` (default: 0) - `updated_at` ## Frontend Routes | Path | Component | Auth | Description | |------|-----------|------|-------------| | `/login` | LoginPage | No | Login page | | `/` | VideoGenerationPage | Yes | Main video generation UI | | `/profile` | ProfilePage | Yes | User consumption overview | | `/admin/dashboard` | DashboardPage | Admin | Stats & charts | | `/admin/users` | UsersPage | Admin | User management | | `/admin/records` | RecordsPage | Admin | Generation records | | `/admin/settings` | SettingsPage | Admin | Global quota & announcement | | `/admin/logs` | AuditLogsPage | Admin | Admin operation audit logs | | `/admin/assets` | AdminAssetsPage | Admin | Content assets (team→member→video hierarchy) | | `/team/assets` | TeamAssetsPage | TeamAdmin | Team content assets (member→video hierarchy) | ## Incremental Development Guide ### How to Add Features to This Project This project was generated and maintained using **agent-auto**(多 Agent 协作自动开发系统)。 项目路径:`/Users/maidong/Desktop/zyc/研究openclaw/agent-auto/` 增量开发有两种方式: #### 方式 1:Direct AI Development(小改动) Bug 修复、UI 微调、单个接口等小改动,直接在 Claude Code 中描述需求即可。 Claude Code 会读取本文件(CLAUDE.md)理解项目上下文。 示例: - "Add a logout button to the navbar" - "Fix the date format in the records table" - "修改轮询间隔为 3 分钟" - "Change the default daily quota from 600 to 1200 seconds" **IMPORTANT — 每次改动后必须更新文档:** 1. **更新 `CLAUDE.md`**(本文件): - 新 API 端点 → 加到 API Endpoints 表 - 新页面/路由 → 加到 Frontend Routes 表 - 新 model/字段 → 加到 Database Models 区 - 配置变更 → 更新对应区 - 始终在底部 **Change History** 表加一行 2. **更新 Claude Code memory**(如有): - 更新 `~/.claude/projects/` 下的 memory 文件 - 确保跨会话的 AI 也能了解变更 3. **非架构性改动也要记录**: - Bug fix / UI 微调 / 依赖更新 / 配置值变更 → 都加到 Change History 未更新文档会导致后续 AI 会话使用过期上下文,引发冲突或重复工作。 #### 方式 2:agent-auto(大功能 / 全栈新模块) 涉及 3+ 文件、新模块、跨模块重构等复杂需求,使用 agent-auto 自动完成全流程: ``` 需求 → PRD → HTML 原型 → 设计评审 → 全栈代码 → 测试 → Bug 修复循环 → 完成 ``` **运行命令:** ```bash cd /Users/maidong/Desktop/zyc/研究openclaw/agent-auto # 增量需求(在已有项目上加功能) npx tsx src/index.ts --resume /Users/maidong/Desktop/zyc/研究openclaw/视频生成平台/jimeng-clone "你的增量需求描述" # 崩溃恢复 / 继续执行 npx tsx src/index.ts --resume /Users/maidong/Desktop/zyc/研究openclaw/视频生成平台/jimeng-clone ``` **agent-auto 会自动:** 1. 读取 `.agent-auto/state.json` 恢复项目状态 2. product-agent 修订 PRD(`docs/prd.md`) 3. design-agent 更新 HTML 原型(`prototype/`) 4. product-agent 设计评审(`docs/design-review.md`,APPROVED/REJECTED 循环) 5. dev-agent 增量开发(保留已有代码,只新增/修改) 6. test-agent 测试 + Bug 分类(`test-report.md`) 7. Bug 修复循环(CODE_BUG → dev-agent / DESIGN_BUG → design-agent / REQUIREMENT_BUG → product-agent) 8. 全部通过 → COMPLETE **状态持久化**:进度保存在 `.agent-auto/state.json`,中断后可随时 `--resume` 继续。 **Agent 记忆**:每个 Agent 有独立记忆文件(`.agent-auto/{agent-name}/memory.md`),跨轮次保持上下文。 #### 变更日志维护 每次需求开发完成、测试验收通过后,**必须**在 `docs/changelog.md` 中记录本次变更: - 按日期倒序添加新条目(最新的在最前面) - 包含:变更标题、状态/验收、变更内容、变更文件、触发原因 - 文件末尾有模板可直接复制使用 - Direct AI 和 agent-auto 两种方式均需记录 #### 何时用哪种方式 | 场景 | 方式 | |------|------| | Bug 修复 / 单行改动 | Direct AI | | UI 微调(按钮、颜色、文案) | Direct AI | | 添加单个 API 端点 | Direct AI | | 修改已有组件行为 | Direct AI | | 新功能模块(3+ 文件) | agent-auto | | 新增整页 CRUD(如管理页面) | agent-auto | | 跨多文件重构 | agent-auto | | 新增子系统(通知、支付、权限) | agent-auto | ### How to Add a New Page 1. Create page component in `web/src/pages/NewPage.tsx` 2. Add route in `web/src/App.tsx` inside ``: ```tsx } /> ``` 3. If it needs state, create store in `web/src/store/newPage.ts` 4. Add API calls in the store using `api.get()` / `api.post()` from `web/src/lib/api.ts` ### How to Add a New API Endpoint 1. Add view function in `backend/apps/generation/views.py` (or relevant app): ```python @api_view(['GET']) @permission_classes([IsAuthenticated]) def new_endpoint_view(request): return Response({'data': ...}) ``` 2. Add URL pattern in `backend/apps/generation/urls.py`: ```python path('new/endpoint', views.new_endpoint_view, name='new_endpoint'), ``` 3. Add TypeScript types in `web/src/types/index.ts` 4. Add API call in the relevant Zustand store ### How to Add a New Database Model 1. Define model in `backend/apps/generation/models.py` (or relevant app) 2. Run migrations: ```bash cd backend python manage.py makemigrations python manage.py migrate ``` 3. Register in admin: `backend/apps/generation/admin.py` 4. Create serializer if needed: `backend/apps/generation/serializers.py` ## Environment Variables | Variable | Description | Required | |----------|-------------|----------| | `DATABASE_URL` | MySQL connection string (prod) | Prod only | | `SECRET_KEY` | Django secret key | Yes | | `TOS_ACCESS_KEY` | Volcano Engine TOS AccessKeyId | Yes (upload) | | `TOS_SECRET_KEY` | Volcano Engine TOS SecretAccessKey | Yes (upload) | | `TOS_BUCKET` | Volcano TOS bucket name (default: `airdrama-media`) | Yes (upload) | | `TOS_ENDPOINT` | TOS endpoint URL (default: `https://tos-cn-beijing.volces.com`) | Yes (upload) | | `TOS_REGION` | TOS region (default: `cn-beijing`) | Yes (upload) | | `TOS_CDN_DOMAIN` | TOS CDN domain for permanent URLs (default: `https://airdrama-media.tos-cn-beijing.volces.com`) | Yes (upload) | | `ARK_API_KEY` | Volcano Engine ARK API key for Seedance | Yes (video gen) | | `ARK_BASE_URL` | ARK API base URL (default: `https://ark.cn-beijing.volces.com/api/v3`) | No | ## Deployment - **CI/CD**: Gitea Actions (`.gitea/workflows/deploy.yaml`) - **Registry**: Huawei Cloud SWR - **Orchestration**: Kubernetes (`k8s/` directory) - **Backend URL**: `video-huoshan-api.airlabs.art` - **Frontend URL**: `video-huoshan-web.airlabs.art` - **Database**: Aliyun RDS MySQL (`rm-7xv1uaw910558p1788o.mysql.rds.aliyuncs.com:3306`) ## Testing - **Unit Tests**: 227 tests in `web/` via Vitest — `cd web && npx vitest run` - **E2E Tests**: 49 tests via Playwright — `cd web && npx playwright test` - **Backend**: Django system checks — `cd backend && python manage.py check` - **Status**: 211 passing, 16 pre-existing path-resolution failures in phase2/phase3 tests - **Test DB Isolation**: E2E tests use `TESTING=true` env var → backend writes to `test_db.sqlite3` (not `db.sqlite3`). Playwright auto-starts a test backend on port 8000 with this env var. Dev data is never polluted by tests. ## Design Guidelines - **Color Palette**: `#0a0a0f` (bg), `#111118`, `#16161e`, `#2a2a38`, `#00b8e6` (accent) - **Typography**: Noto Sans SC (Chinese) + Space Grotesk (UI) + JetBrains Mono (code) - **Style**: Linear/Vercel dark theme aesthetic - **Responsive**: `grid-cols-4 max-lg:grid-cols-2` ## Change History > 完整变更日志见 [`docs/changelog.md`](docs/changelog.md),以下为摘要。 | Date | Change | Scope | |------|--------|-------| | 2025-01 | Phase 1: Core video generation UI | Frontend | | 2025-02 | Phase 2: Backend + Auth + Admin panel | Full stack | | 2025-03 | Phase 3: Seconds-based quota, profile page, ECharts dashboard | Full stack | | 2026-03 | Added CLAUDE.md for AI-assisted incremental development | Documentation | | 2026-03-13 | Phase 4: TOS upload + Seedance API integration + DB persistence | Full stack | | 2026-03-13 | Test DB isolation: TESTING=true → test_db.sqlite3, Playwright auto-starts test backend | Backend + Config | | 2026-03-13 | Removed mock data fallback from DashboardPage — charts show real data only | Frontend | | 2026-03-13 | LogCenterMiddleware: Django 中间件兜底异常上报(捕获 DRF 之外的导入/中间件/URL 解析错误) | Backend | | 2026-03-13 | custom_exception_handler: 未处理异常返回 JSON 500 而非 HTML | Backend | | 2026-03-13 | 前端轮询间隔从 5 秒改为 3 分钟 | Frontend | | 2026-03-13 | CLAUDE.md 增量开发指南更新为 agent-auto(替换 Autonomous Skill) | Documentation | | 2026-03-15 | v0.8.0: 音频引用支持 + 视频 TOS 持久化 + 移除硬编码密钥 + 渐进式轮询 | Full stack | | 2026-03-15 | TOS 桶切换到 airdrama-media (cn-beijing),K8s Secret 注入 TOS 密钥 | Infra | | 2026-03-15 | v0.8.1: Seedance API 友好错误提示 (SeedanceAPIError) + 前端 Mock 数据清理 | Full stack | | 2026-03-16 | v0.8.2: 管理后台 UI 修复 — DatePicker/Select 暗色主题、公告跑马灯、Toast 全局化、失败原因 tooltip | Full stack | | 2026-03-16 | v0.8.3: 团队详情抽屉→弹窗重构(VideoDetailModal 规范) + 修改秒数池功能 + member_count 修复 | Full stack | | 2026-03-16 | v0.8.4: 管理员操作审计日志 — AdminAuditLog 模型 + 12 处埋点 + 日志查询页面 | Full stack | | 2026-03-18 | v0.9.0: 首次登录强制改密 — must_change_password 字段 + ForceChangePasswordModal | Full stack | | 2026-03-18 | v0.9.0: 并发会话限制 — ActiveSession + SessionJWT + 可配置桌面/移动端会话数 | Full stack | | 2026-03-18 | v0.9.0: 登录记录 — LoginRecord 模型(IP + User-Agent)为异常检测打基础 | Backend | | 2026-03-18 | v0.9.0: Token 生命周期缩短 — access 30min, refresh 1天 | Backend | | 2026-03-18 | v0.9.0: 内容资产页 — 超管/团队管三级折叠式资产浏览(团队→成员→视频) | Full stack | ### Phase 4 Details (2026-03-13) **Backend new files:** - `backend/utils/tos_client.py` — Volcano Engine TOS upload via official `tos` SDK - `backend/utils/seedance_client.py` — Seedance/ARK API client (create_task, query_task) **Backend changes:** - `backend/config/settings.py` — Added TOS and ARK config - `backend/apps/generation/models.py` — Added `ark_task_id`, `result_url`, `error_message`, `reference_urls` (JSONField) - `backend/apps/generation/views.py` — New endpoints: `upload_media_view`, `video_tasks_list_view`, `video_task_detail_view`; Rewritten `video_generate_view` with Seedance integration - `backend/apps/generation/urls.py` — Added 3 routes: `media/upload`, `video/tasks`, `video/tasks/` - `backend/apps/generation/serializers.py` — Added `references` field to VideoGenerateSerializer - `backend/requirements.txt` — Added `tos>=2.7`, `requests>=2.31` - Migration: `0003_generationrecord_ark_task_id_and_more.py` **Frontend changes:** - `web/src/types/index.ts` — Added `BackendTask` interface, `tosUrl` to `UploadedFile`, `taskId`/`errorMessage` to `GenerationTask` - `web/src/lib/api.ts` — Added `mediaApi.upload()`, `videoApi.getTasks()`, `videoApi.getTaskStatus()`; Changed `videoApi.generate()` to JSON - `web/src/store/generation.ts` — Complete rewrite: async TOS upload + API calls + polling + `loadTasks()` for refresh persistence - `web/src/components/VideoGenerationPage.tsx` — Added `loadTasks()` on mount - `web/src/components/GenerationCard.tsx` — Video player for results, error state display **Flow:** Upload files → TOS → Generate API (Seedance) → DB record → Poll status → Display result