Repository navigation
feat: 新增CMS资源自定义管理功能 & 重构主题引入多套现代化主题 #465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,8 +5,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co | |
| ## Project Overview | ||
|
|
||
| VodHub is a pnpm monorepo with two applications: | ||
| - **Backend** (`apps/backend`): Hono-based video aggregation API that normalizes multiple video source providers into a unified REST API (categories, search, details, playback). Node.js >= 24, ESM. | ||
| - **Frontend** (`apps/frontend`): Vite + React 19 + React Router video player application with Ant Design 6, Zustand state management, and multi-theme support. | ||
| - **Backend** (`apps/backend`): Hono‑based video aggregation API that normalizes multiple video source providers into a unified REST API (categories, search, details, playback). Node.js ≥ 24, ESM. | ||
| - **Frontend** (`apps/frontend`): Vite + React 19 + React Router video player application with Ant Design 6, Zustand state management, and multi‑theme support. | ||
|
|
||
| A shared package (`packages/shared`) provides core TypeScript types used by both apps. | ||
|
|
||
| ## Common Development Commands | ||
|
|
||
|
|
@@ -17,114 +19,188 @@ pnpm dev # Start both backend and frontend dev servers | |
| pnpm dev:backend # Backend only (tsx watch) | ||
| pnpm dev:frontend # Frontend only (vite dev) | ||
| pnpm lint # Lint all apps | ||
| pnpm lint:fix # Lint with auto-fix | ||
| pnpm lint:fix # Lint with auto‑fix | ||
| pnpm typecheck # Type check all apps | ||
| pnpm format # Prettier write | ||
| pnpm format:check # Prettier check | ||
| pnpm commit # Interactive conventional commit | ||
| pnpm build # Build all apps (backend + frontend) | ||
| ``` | ||
|
|
||
| ### Backend-Specific Commands | ||
| ### Backend‑Specific Commands | ||
| ```bash | ||
| pnpm --filter @vodhub/backend start # Start backend without watch | ||
| pnpm --filter @vodhub/backend build # Build backend (generates routes first) | ||
| pnpm --filter @vodhub/backend gen:routes # Generate route registry | ||
| pnpm --filter @vodhub/backend lint # Lint backend only | ||
| pnpm --filter @vodhub/backend lint:fix # Lint backend with auto‑fix | ||
| pnpm --filter @vodhub/backend typecheck # Type check backend only | ||
| ``` | ||
|
|
||
| ### Frontend-Specific Commands | ||
| ### Frontend‑Specific Commands | ||
| ```bash | ||
| pnpm --filter @vodhub/frontend build # Production build | ||
| pnpm --filter @vodhub/frontend preview # Preview production build | ||
| pnpm --filter @vodhub/frontend lint # Lint frontend only | ||
| pnpm --filter @vodhub/frontend lint:fix # Lint frontend with auto‑fix | ||
| pnpm --filter @vodhub/frontend typecheck # Type check frontend only | ||
| ``` | ||
|
|
||
| ## Backend Architecture | ||
|
|
||
| ### Route System | ||
| - **URL Pattern**: `GET/POST /api/vodhub/<provider>/<action>` | ||
| - **Actions**: `home`, `homeVod`, `category`, `detail`, `play`, `search` | ||
| - **Auto-discovery**: Routes are automatically registered via `directory-import` in `apps/backend/src/routes/registry.ts` | ||
| - **Production optimization**: Routes are pre-generated to `registry.gen.ts` for faster startup | ||
| - **Auto‑discovery**: Routes are automatically registered via `directory‑import` in `apps/backend/src/routes/registry.ts` | ||
| - **Production optimization**: Routes are pre‑generated to `registry.gen.ts` for faster startup | ||
|
|
||
| ### Provider Types | ||
| 1. **CMS Providers** (Recommended): Only need `namespace.ts` and `index.ts` using `createCMSRoutes()` factory | ||
| 2. **Custom Providers**: Individual route files (`home.ts`, `category.ts`, etc.) with custom logic | ||
|
|
||
| ### CMS Management & Proxy | ||
| - **Proxy API**: `ALL /api/vodhub/proxy` – forwards requests to user‑defined CMS URLs using `x-proxy-target` and `x-proxy-action` headers to translate actions to the target CMS's API format | ||
| - **Frontend store**: CMS configurations are managed locally via `useCmsStore` (Zustand + localStorage) for immediate UI updates; backend API synchronization may be added in the future. | ||
|
|
||
| ### Middleware Order | ||
| 1. `cors()` - CORS handling | ||
| 2. `trimTrailingSlash()` - Trailing slash normalization | ||
| 3. `compress()` - Response compression | ||
| 4. `jsonReturn` - JSON response serialization | ||
| 5. `cache` - Redis/memory caching with deduplication | ||
| 1. `cors()` – CORS handling | ||
| 2. `trimTrailingSlash()` – trailing slash normalization | ||
| 3. `compress()` – response compression | ||
| 4. `jsonReturn` – JSON response serialization | ||
| 5. `cache` – Redis/memory caching with deduplication | ||
|
|
||
| ### Caching System | ||
| - Two-level cache: memory LRU + optional Redis via Keyv | ||
| - Deduplication: Prevents concurrent identical requests | ||
| - Cache key format: `vod-hub:redis-cache:${path}${bodyHash}` | ||
| - Error responses: Set `Cache-Control: no-cache` to prevent caching failures | ||
| - Two‑level cache: memory LRU + optional Redis via Keyv | ||
| - Deduplication: prevents concurrent identical requests | ||
| - Cache key format: `vod‑hub:redis‑cache:${path}${bodyHash}` | ||
| - Error responses: set `Cache‑Control: 'no‑cache'` to prevent caching failures | ||
|
|
||
| ### Error Handling Pattern | ||
| All handlers must follow this structure: | ||
| ```typescript | ||
| try { | ||
| logger.info(`${ACTION_MESSAGE.INFO} - ${namespace.name}`); | ||
| logger.info(`${ACTION_MESSAGE.INFO} ‑ ${namespace.name}`); | ||
| const res = await someRequest(); | ||
| if (res.code === 1) { // CMS convention | ||
| return { code: SUCCESS_CODE, message: ACTION_MESSAGE.SUCCESS, data: [...] }; | ||
| return { code: SUCCESS_CODE, message: ACTION_MESSAGE.SUCCESS, data: […] }; | ||
| } | ||
| logger.error(`${ACTION_MESSAGE.ERROR} - ${namespace.name} - ${JSON.stringify(res)}`); | ||
| logger.error(`${ACTION_MESSAGE.ERROR} ‑ ${namespace.name} ‑ ${JSON.stringify(res)}`); | ||
| return { code: ERROR_CODE, message: ACTION_MESSAGE.ERROR, data: [] }; | ||
| } catch (error) { | ||
| ctx.res.headers.set('Cache-Control', 'no-cache'); | ||
| logger.error(`${ACTION_MESSAGE.ERROR} - ${namespace.name} - ${error}`); | ||
| ctx.res.headers.set('Cache‑Control', 'no‑cache'); | ||
| logger.error(`${ACTION_MESSAGE.ERROR} ‑ ${namespace.name} ‑ ${error}`); | ||
| return { code: SYSTEM_ERROR_CODE, message: ACTION_MESSAGE.ERROR, data: [] }; | ||
| } | ||
| ``` | ||
|
|
||
| **Status Codes**: | ||
| - `SUCCESS_CODE = 0` - Successful response | ||
| - `ERROR_CODE = -1` - Business logic error (upstream failure) | ||
| - `SYSTEM_ERROR_CODE = -2` - Exception/catch error | ||
| - `SUCCESS_CODE = 0` – successful response | ||
| - `ERROR_CODE = -1` – business logic error (upstream failure) | ||
| - `SYSTEM_ERROR_CODE = -2` – exception/catch error | ||
|
|
||
| ### Import Conventions | ||
| - **Groups**: Built‑ins → external packages → internal modules (`@/`), separated by blank lines | ||
| - **Alphabetization**: Imports within each group should be alphabetized (case‑insensitive) | ||
| - **Type imports**: Use `import type` for type‑only imports | ||
| - **Node built‑ins**: Use the `node:` prefix (e.g., `import { join } from 'node:path'`) | ||
|
|
||
| ### Route Object Shape | ||
| Each custom route file exports a `route` object with the following properties: | ||
| - `path`: string or string[] – URL path segment(s) | ||
| - `name`: string – route identifier (matches filename) | ||
| - `example`: string – example URL path | ||
| - `description`: string – what the route does | ||
| - `handler`: (ctx: Context) => Promise<T> | T | ||
| - `method?`: 'GET' | 'POST' – defaults to GET | ||
|
|
||
| ### Handler Naming | ||
| - The handler function must be named `handler` (constant) in each route file | ||
| - Use typed `RouteItem<T>` generic for route definitions | ||
|
|
||
| ## Frontend Architecture | ||
|
|
||
| ### Tech Stack | ||
| - **Framework**: Vite + React 19 + React Router + TypeScript | ||
| - **UI**: Ant Design 6 with SCSS Modules | ||
| - **Framework**: Vite + React 19 + React Router + TypeScript | ||
| - **UI**: Ant Design 6 with SCSS Modules | ||
| - **State Management**: Zustand stores with `persist` middleware | ||
| - **Video Player**: xgplayer + HLS.js | ||
| - **Styling**: CSS variables for multi-theme support | ||
| - **Styling**: CSS variables for multi‑theme support | ||
|
|
||
| ### Theme System | ||
| Three built-in themes defined in `lib/themes/index.ts`: | ||
| - **midnight**: Dark with red accent | ||
| - **aurora**: Light with cyan accent | ||
| - **cyber**: Dark with purple accent | ||
| Three built‑in themes defined in `lib/themes/index.ts`: | ||
| - **midnight**: dark with red accent | ||
| - **aurora**: light with cyan accent | ||
| - **cyber**: dark with purple accent | ||
|
Comment on lines
129
to
+133
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 更新内置主题列表,避免文档与实现不一致。 Line 130-133 仍写的是旧的 建议调整-Three built‑in themes defined in `lib/themes/index.ts`:
-- **midnight**: dark with red accent
-- **aurora**: light with cyan accent
-- **cyber**: dark with purple accent
+Three built‑in themes defined in `lib/themes/index.ts`:
+- **vercel**: light with black primary and blue accent
+- **airbnb**: light with Rausch red accent
+- **claude**: warm neutral palette with terracotta accent🧰 Tools🪛 LanguageTool[grammar] ~130-~130: Ensure spelling is correct (QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1) 🤖 Prompt for AI Agents |
||
|
|
||
| **Key Rule**: All colors must use CSS variables (`var(--color-bg-container)`) - never hardcode hex/rgba values. | ||
| **Key Rule**: All colors must use CSS variables (`var(--color‑bg‑container)`) – never hardcode hex/rgba values. | ||
|
|
||
| ### CSS Variables Reference | ||
| | Category | Variable | Description | | ||
| |---|---|---| | ||
| | Brand | `--color-primary` | Primary color | | ||
| | Brand | `--color-primary-light` | Light primary | | ||
| | Background | `--color-bg` | Page background | | ||
| | Background | `--color-bg-container` | Container background | | ||
| | Background | `--color-bg-elevated` | Elevated background | | ||
| | Background | `--color-bg-container-alpha` | Semi‑transparent container | | ||
| | Background | `--color-bg-elevated-alpha` | Semi‑transparent elevated | | ||
| | Background | `--color-bg-elevated-hover` | Hover state background | | ||
| | Text | `--color-text` | Primary text | | ||
| | Text | `--color-text-secondary` | Secondary text | | ||
| | Text | `--color-text-tertiary` | Tertiary text | | ||
| | Border | `--color-border` | Border | | ||
| | Border | `--color-border-secondary` | Secondary border | | ||
| | State | `--color-primary-alpha-low` | Selected state | | ||
| | State | `--color-primary-alpha-medium` | Border accent | | ||
| | State | `--color-primary-alpha-hover` | Hover state | | ||
| | State | `--color-primary-shadow` | Shadow | | ||
| | Overlay | `--color-overlay` | Overlay background | | ||
| | Overlay | `--color-overlay-border` | Overlay border | | ||
|
|
||
| ### State Management | ||
| - Stores in `lib/store/` with naming `use{Name}Store.ts` | ||
| - Zustand `persist` middleware for localStorage persistence | ||
| - Theme state updates both CSS variables and Ant Design theme config | ||
|
|
||
| ### Component Structure | ||
| - Components are client-side by default (no `'use client'` directive needed) | ||
| - SCSS Modules with `vod-next-` class prefix (historical naming convention) | ||
| - Components are client‑side by default (no `'use client'` directive needed) | ||
| - SCSS Modules with `vod‑next‑` class prefix (historical naming convention) | ||
| - Props defined with `interface` and destructured in params | ||
| - Components use `export default` | ||
|
|
||
| ### Error Handling | ||
| - **HTTP errors**: Rejected via Axios interceptor (`Promise.reject(error)`) | ||
| - **API calls**: Wrap in try/catch, re‑throw as `Promise.reject` | ||
| - **UI errors**: Display with Ant Design `message` component | ||
|
|
||
| ### Performance Guidelines | ||
| - Use `React.memo` to avoid unnecessary re‑renders | ||
| - Use `useMemo` and `useCallback` for expensive computations | ||
| - Use `React.lazy()` with `Suspense` for heavy components (e.g., video player) | ||
| - Use `Suspense` for async loading | ||
|
|
||
| ### Design System | ||
| - See `DESIGN.md` for Vercel‑inspired visual guidelines (colors, typography, shadows, component styling). | ||
|
|
||
| ### CMS Management UI | ||
| - Component: `components/cms‑management/index.tsx` | ||
| - Store: `lib/store/useCmsStore.ts` (localStorage only) | ||
| - Allows adding, editing, deleting, and testing custom CMS sources | ||
| - Changes are persisted locally in localStorage; backend API synchronization may be added in the future | ||
|
|
||
| ## Shared Types | ||
|
|
||
| Core types defined in `packages/shared/src/types/index.ts`: | ||
| - `Namespace` - Provider metadata | ||
| - `HomeData`, `HomeVodData`, `CategoryVodData` - Data structures | ||
| - `DetailData`, `PlayData`, `SearchData` - Response types | ||
| - `ApiResponse<T>` - Standard API response wrapper | ||
| - `Namespace` – provider metadata | ||
| - `HomeData`, `HomeVodData`, `CategoryVodData` – data structures | ||
| - `DetailData`, `PlayData`, `SearchData` – response types | ||
| - `ApiResponse<T>` – standard API response wrapper | ||
|
|
||
| ## Deployment | ||
|
|
||
| ### Docker Compose | ||
| - **Development**: `docker-compose up -d` (uses `docker-compose.yml`) | ||
| - **Production**: `docker-compose -f docker-compose.prod.yml up -d` (includes Redis, log persistence) | ||
| - **Development**: `docker‑compose up ‑d` (uses `docker‑compose.yml`) | ||
| - **Production**: `docker‑compose ‑f docker‑compose.prod.yml up ‑d` (includes Redis, log persistence) | ||
|
|
||
| ### Production Environment | ||
| - **Services**: frontend, backend, redis | ||
|
|
@@ -135,10 +211,10 @@ Core types defined in `packages/shared/src/types/index.ts`: | |
| ## Development Standards | ||
|
|
||
| ### Code Style | ||
| - **Backend**: Named exports only, `any` disallowed, `no-explicit-any: error` | ||
| - **Backend**: Named exports only, `any` disallowed (`no‑explicit‑any: error`) | ||
| - **Frontend**: `any` allowed, `export default` for components, named exports for utilities | ||
| - **Imports**: Builtins → externals → internals, alphabetized, blank line between groups | ||
| - **Formatting**: Single quotes, no trailing commas, 4-space indent, 200 char width, semicolons | ||
| - **Formatting**: Single quotes, no trailing commas, 4‑space indent, 200‑char width, semicolons | ||
|
|
||
| ### Naming Conventions | ||
| | Item | Convention | Example | | ||
|
|
@@ -149,15 +225,21 @@ Core types defined in `packages/shared/src/types/index.ts`: | |
| | Frontend components | `PascalCase` | `VodList` | | ||
| | Frontend hooks | `use` prefix | `useIsMobile` | | ||
| | Frontend stores | `use` + `Store` suffix | `useSettingStore` | | ||
| | Backend handler functions | `handler` | `const handler = async (ctx) => { … }` | | ||
|
|
||
| ### Git Workflow | ||
| - Husky + lint-staged for pre-commit hooks | ||
| - Husky + lint‑staged for pre‑commit hooks | ||
| - Commitlint enforces conventional commits | ||
| - `pnpm commit` for interactive commit messages | ||
|
|
||
| ### Code Quality Assurance | ||
| - **After generating code**: Always run `pnpm lint:fix` and `pnpm format` to ensure consistent style | ||
| - **Before committing**: Pre‑commit hooks automatically run linting and formatting | ||
| - **Type safety**: Run `pnpm typecheck` to verify TypeScript types across the monorepo | ||
|
|
||
| ## Important Notes | ||
| - No test framework is configured in this project | ||
| - Backend uses ESM (`"type": "module"`) | ||
| - CMS handlers check `res.code === 1` for upstream success | ||
| - All error responses return `data: []` (empty array) | ||
| - Route handlers must never throw - always return structured response | ||
| - Route handlers must never throw – always return structured response | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
对齐 proxy 路由方法约束。
Line 62 记录 proxy 是
ALL /api/vodhub/proxy,但 Line 114 只允许GET | POST。如果路由类型/生成器需要表达 proxy,这里会把维护者引到错误的 route shape。建议调整
Also applies to: 107-114
🤖 Prompt for AI Agents