# CLAUDE.md — duoqi-admin > 多奇管理后台,基于 Vite + React + TypeScript + shadcn/ui + Tailwind CSS > 调用 duoqi-api 的 admin 端点,CSR 纯前端应用 ## Current Status **Phase 3 done + 补全完毕。** UGC 审核 + 举报处理 + 运营配置 + 多管理员支持 已完成。知识卡独立页面和题目列表排序已补全。Phase 1c 数据看板真实数据仍延后。所有计划内功能开发完毕,后续按需迭代。 Development follows the phased roadmap in [dev-spec.md](./dev-spec.md) §九. ## Quick Start ```bash bun install bun run dev # Vite dev server, default port 5173 bun run lint # ESLint check — run after every code change bun run build # Production build → dist/ ``` ## Environment `.env` is already configured. To change the API URL, edit `.env`: ```env VITE_API_BASE_URL=http://localhost:3000 # duoqi-api address ``` ## Architecture ``` src/ ├── main.tsx # Entry point ├── App.tsx # Root (router + layout) ├── styles/globals.css # Tailwind v4 + shadcn/ui CSS variables ├── routes/ # Pages (login, dashboard, questions/*, categories/*, ...) │ ├── knowledge-cards/ # Knowledge card management (知识卡管理) │ ├── reports/ # Report handling (举报处理) │ ├── admins/ # Admin management (管理员管理) │ └── settings/ # System settings (运营配置) ├── components/ │ ├── ui/ # shadcn/ui primitives │ ├── layout/ # Sidebar, Header, AdminLayout │ ├── charts/ # StatsCard, chart wrappers │ ├── category/ # Category CRUD (columns, dialogs) │ ├── question/ # Question CRUD (columns, form, StatusBadge, DistractorEditor, KnowledgeCardFields, StatusTransitionDialog, ImportQuestionsDialog, UgcReviewDialog) │ ├── skill-tree/ # Skill Tree chapter CRUD (columns, form dialog, delete dialog) │ ├── user/ # User CRUD (columns, UserProfileCard, GameStatsGrid, AnswerHistoryTable, ChapterProgressList, TierChangeDialog) │ ├── feedback/ # Feedback management (columns, FeedbackDetailDialog) │ └── settings/ # Settings tabs (EventConfigTab, PushTemplateTab, GeneralSettingsTab) ├── lib/ │ ├── api-client.ts # HTTP client for /admin/* endpoints │ ├── auth.ts # Admin JWT token management + current admin ID │ ├── utils.ts # Utility functions │ ├── csv-export.ts # Generic CSV export utility (BOM-compatible) │ ├── constants.ts # Status enums, difficulty levels, feedback/tier/report/event/push/admin labels │ └── api/ # API modules (question-api, category-api, report-api, settings-api, admin-api) ├── hooks/ # useAuth ├── stores/ # Zustand stores (auth-store) └── types/ # question, user, user-detail, feedback, category, report, settings, admin, api types ``` ## Key Patterns - **Routing**: React Router v7 library mode (`createBrowserRouter` + `RouterProvider`). Routes defined in `App.tsx`. Root layout (`routes/__root.tsx`) handles auth guard — redirects to `/login` when not authenticated. - **Development order**: Follow [dev-spec.md](./dev-spec.md) §九 (Phase roadmap). - **Lint first, CI as fallback**: Every code change must pass `bun run lint` locally before commit. CI lint is the safety net, not the first check. Run `bun run lint` after writing/modifying code — fix all errors before committing. - **Auth flow**: Login page supports Token and username/password login. Token: POST `/admin/auth/login` → receive JWT. Password: POST `/admin/auth/login` with credentials → receive JWT. Both modes fall back to offline mode when backend is unavailable (stores a `offline_` prefixed token locally). JWT stored in auth-store → attached as `Authorization: Bearer ` on all subsequent requests. - **API client**: All admin API calls go through `lib/api-client.ts` (ky v2). Uses `baseUrl` + `prefix: "/admin"`. Auto-attaches auth header. 401 responses trigger logout + redirect to `/login`. - **Data tables**: TanStack Table v8 headless + shadcn/ui styled components in `components/data-table/` - **Forms**: React Hook Form + Zod validation for all admin forms - **State**: Zustand for client state only; server state fetched via API client ## Gotchas - **shadcn/ui CLI**: After `bunx shadcn@latest add ...`, verify files land in `src/components/ui/` — sometimes they end up in `@/components/ui/` at project root instead. - **ky v2**: Uses `baseUrl` + `prefix` (not `prefixUrl`). Hooks receive a single state object (`{ request }`, `{ response }`) instead of positional arguments. - **TypeScript 6**: Requires `"ignoreDeprecations": "6.0"` in tsconfig when using `baseUrl` + `paths` for `@/*` aliases. - **Tailwind v4**: Uses `@import "tailwindcss"` and `@theme inline` block (not `@tailwind base/components/utilities`). - **Zod v4**: Import from `zod/v4` (not `zod`). Use `@hookform/resolvers/zod` for form resolver. - **TypeScript `verbatimModuleSyntax`**: All type-only imports must use `import type` syntax. Common: `ColumnDef` from TanStack Table, `UseFormRegister` from react-hook-form, `z.infer` results. - **react-hook-form sub-components**: `UseFormRegister` is not assignable to `UseFormRegister` even when A extends B (contravariance). Prefer inlining fields or passing individual `register("field")` results as props. ## Design Docs | Doc | Path | Notes | |-----|------|-------| | **Dev spec (primary)** | [./dev-spec.md](./dev-spec.md) | Full engineering spec — read before development | | Product overview | [../docs/product-overview.md](../docs/product-overview.md) | Product scope, phases | | Tech stack | [../docs/tech-stack.md](../docs/tech-stack.md) | Full-stack decisions | | duoqi-api spec | [../docs/specs/duoqi-api/dev-spec.md](../docs/specs/duoqi-api/dev-spec.md) | Admin API endpoint definitions | | Question format | [../docs/specs/shared/question-format-design.md](../docs/specs/shared/question-format-design.md) | Question data model (core for CRUD) | | Gamification | [../docs/specs/shared/gamification-monetization-design.md](../docs/specs/shared/gamification-monetization-design.md) | Skill tree, subscription tiers | | Analytics | [../docs/specs/shared/analytics-feedback-design.md](../docs/specs/shared/analytics-feedback-design.md) | Stats metrics, feedback data | ## 技术栈速查 - 框架:Vite + React 18 - 语言:TypeScript - UI:shadcn/ui + Tailwind CSS - 数据表格:TanStack Table v8 - 表单:React Hook Form + Zod - 图表:Recharts - HTTP:ky v2 - 状态:Zustand - 路由:React Router v7 - 包管理:bun