6.4 KiB
6.4 KiB
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 §九.
Quick Start
bun install
bun run dev # Vite dev server, default port 5173
bun run build # Production build → dist/
Environment
.env is already configured. To change the API URL, edit .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 inApp.tsx. Root layout (routes/__root.tsx) handles auth guard — redirects to/loginwhen not authenticated. - Development order: Follow dev-spec.md §九 (Phase roadmap).
- Auth flow: Login page supports Token and username/password login. Token: POST
/admin/auth/login→ receive JWT. Password: POST/admin/auth/loginwith credentials → receive JWT. Both modes fall back to offline mode when backend is unavailable (stores aoffline_prefixed token locally). JWT stored in auth-store → attached asAuthorization: Bearer <jwt>on all subsequent requests. - API client: All admin API calls go through
lib/api-client.ts(ky v2). UsesbaseUrl+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 insrc/components/ui/— sometimes they end up in@/components/ui/at project root instead. - ky v2: Uses
baseUrl+prefix(notprefixUrl). Hooks receive a single state object ({ request },{ response }) instead of positional arguments. - TypeScript 6: Requires
"ignoreDeprecations": "6.0"in tsconfig when usingbaseUrl+pathsfor@/*aliases. - Tailwind v4: Uses
@import "tailwindcss"and@theme inlineblock (not@tailwind base/components/utilities). - Zod v4: Import from
zod/v4(notzod). Use@hookform/resolvers/zodfor form resolver. - TypeScript
verbatimModuleSyntax: All type-only imports must useimport typesyntax. Common:ColumnDeffrom TanStack Table,UseFormRegisterfrom react-hook-form,z.inferresults. - react-hook-form sub-components:
UseFormRegister<A>is not assignable toUseFormRegister<B>even when A extends B (contravariance). Prefer inlining fields or passing individualregister("field")results as props.
Design Docs
| Doc | Path | Notes |
|---|---|---|
| Dev spec (primary) | ./dev-spec.md | Full engineering spec — read before development |
| Product overview | ../docs/product-overview.md | Product scope, phases |
| Tech stack | ../docs/tech-stack.md | Full-stack decisions |
| duoqi-api spec | ../docs/specs/duoqi-api/dev-spec.md | Admin API endpoint definitions |
| Question format | ../docs/specs/shared/question-format-design.md | Question data model (core for CRUD) |
| Gamification | ../docs/specs/shared/gamification-monetization-design.md | Skill tree, subscription tiers |
| Analytics | ../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