# D8D Starter 前端架构文档

## 版本信息
| 版本 | 日期 | 描述 | 作者 |
|------|------|------|------|
| 1.0 | 2025-09-15 | 初始前端架构文档 | Winston |

## 1. 模板和框架选择

### 现有技术栈分析
项目已经使用了现代化的React全栈技术栈：

**核心框架**:
- **React 19.1.0** - 最新版本，支持并发特性
- **TypeScript 5.8.3** - 类型安全，编译时错误检测

**构建工具**:
- **Vite 7.0.0** - 快速冷启动，热重载支持
- **Tailwind CSS 4.1.11** - 原子化CSS，实用优先

**UI组件库**:
- **shadcn/ui** - 基于Radix UI的无障碍组件库
- **Radix UI Primitives** - 无障碍基础组件

**状态管理**:
- **React Query 5.83.0** - 服务端状态管理，数据同步
- **React Hook Form 7.61.1** - 表单管理和验证

**路由系统**:
- **React Router 7.7.0** - 声明式客户端路由
- **双路由架构** - 管理后台(/admin/*)和用户前台(/*)分离

**API集成**:
- **Hono RPC 4.8.5** - 端到端类型安全API调用
- **自定义axios适配器** - 统一的错误处理

### 技术决策依据
- **选择React Query而非Redux**: 专注于服务端状态管理，减少客户端状态复杂度
- **Hono RPC而非传统REST**: 提供前后端统一的类型安全，减少接口不一致问题
- **Tailwind CSS v4**: 采用新的运行时配置，简化构建流程
- **shadcn/ui而非Ant Design**: 更现代的设计语言，更好的无障碍支持

## 2. 前端技术栈

| 类别 | 技术 | 版本 | 用途 | 决策依据 |
|------|------|------|------|-----------|
| 框架 | React | 19.1.0 | 用户界面构建 | 最新版本，并发特性支持 |
| UI库 | shadcn/ui | - | 组件库和设计系统 | 基于Radix UI，无障碍支持 |
| 状态管理 | React Query | 5.83.0 | 服务端状态管理 | 数据同步、缓存、自动重试 |
| 路由 | React Router | 7.7.0 | 客户端路由 | 声明式路由，数据加载支持 |
| 构建工具 | Vite | 7.0.0 | 开发服务器和构建 | 快速冷启动，热重载支持 |
| 样式方案 | Tailwind CSS | 4.1.11 | 原子化CSS框架 | 实用优先，设计一致性 |
| 类型安全 | TypeScript | 5.8.3 | 类型检查 | 编译时错误检测 |
| API客户端 | Hono RPC | 4.8.5 | 类型安全API调用 | 前后端统一类型定义 |
| 表单处理 | React Hook Form | 7.61.1 | 表单管理和验证 | 高性能，最小重渲染 |
| 图标库 | Lucide React | 0.536.0 | 图标系统 | 简洁一致的图标设计 |
| 测试框架 | Vitest + Testing Library | - | 组件测试 | 现代化测试工具，更好的TypeORM支持 |

## 3. 项目结构

```text
d8d-starter/
├── src/
│   ├── client/                 # 前端代码根目录
│   │   ├── admin/              # 管理后台界面
│   │   │   ├── components/     # 管理后台专属组件
│   │   │   ├── pages/          # 管理页面
│   │   │   ├── layouts/        # 管理后台布局
│   │   │   └── hooks/          # 管理后台专属hooks
│   │   ├── home/               # 用户前台应用 (已实现)
│   │   │   ├── components/     # Home专用组件 (ErrorPage, FilePreview等)
│   │   │   ├── hooks/          # Home专用Hooks (AuthProvider)
│   │   │   ├── layouts/        # 布局组件 (MainLayout)
│   │   │   ├── pages/          # 页面组件 (14个功能页面)
│   │   │   ├── routes.tsx      # 路由配置 (18个路由)
│   │   │   └── index.tsx       # Home应用入口
│   │   ├── components/         # 共享UI组件
│   │   │   └── ui/             # 基础UI组件 (shadcn/ui)
│   │   │       ├── button.tsx
│   │   │       ├── input.tsx
│   │   │       └── ...
│   │   ├── hooks/              # 共享React Hooks
│   │   │   └── use-mobile.ts   # 移动端检测hook
│   │   ├── lib/                # 工具库
│   │   │   └── utils.ts        # className工具函数 (cn)
│   │   ├── utils/              # 工具函数目录
│   │   │   ├── utils.ts        # 通用工具函数
│   │   │   ├── logger.ts       # 日志工具
│   │   │   └── ClientOnly.tsx  # 客户端渲染组件
│   │   └── api.ts              # API客户端配置
│   ├── server/                 # 后端代码
│   └── shared/                 # 前后端共享代码
├── public/                     # 静态资源
├── dist/                       # 构建输出
└── docs/                       # 文档
```

## 4. 组件标准

### 组件模板

```typescript
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/client/lib/utils"

const componentVariants = cva(
  "base-styles transition-all duration-200",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground",
        secondary: "bg-secondary text-secondary-foreground",
        destructive: "bg-destructive text-destructive-foreground",
        outline: "border border-input bg-background",
        ghost: "hover:bg-accent hover:text-accent-foreground",
      },
      size: {
        default: "h-9 px-4 py-2",
        sm: "h-8 rounded-md px-3 text-xs",
        lg: "h-10 rounded-md px-8",
        icon: "size-9",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface ComponentProps
  extends React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof componentVariants> {
  isLoading?: boolean
  disabled?: boolean
}

const Component = React.forwardRef<HTMLDivElement, ComponentProps>(
  ({ className, variant, size, isLoading = false, disabled = false, ...props }, ref) => {
    return (
      <div
        ref={ref}
        className={cn(
          componentVariants({ variant, size, className }),
          isLoading && "opacity-50 cursor-not-allowed",
          disabled && "pointer-events-none opacity-50"
        )}
        aria-disabled={disabled || isLoading}
        {...props}
      />
    )
  }
)
Component.displayName = "Component"

export { Component, componentVariants }
```

### 命名约定

**文件命名**:
- 组件文件: `PascalCase.tsx` (如: `UserProfile.tsx`)
- 工具文件: `camelCase.ts` (如: `formatDate.ts`)
- Hook文件: `useCamelCase.ts` (如: `useUserData.ts`)
- 类型文件: `camelCase.ts` (如: `apiTypes.ts`)

**组件命名**:
- 组件: `PascalCase` (如: `UserCard`)
- Props接口: `ComponentProps` (如: `ButtonProps`)
- 变体类型: `ComponentVariants` (如: `ButtonVariants`)

## 5. 状态管理

### 实际状态管理架构

基于对现有代码的分析，项目采用混合状态管理模式：

**React Context + React Query组合**:
- **认证状态**: 使用React Context管理用户认证状态
- **服务端数据**: 使用React Query管理API数据
- **本地UI状态**: 使用useState管理组件内部状态

### 认证状态管理 (React Context)

```text
src/
├── client/
│   ├── admin/
│   │   └── hooks/
│   │       └── AuthProvider.tsx    # 管理后台认证上下文
│   ├── home/
│   │   └── hooks/
│   │       └── AuthProvider.tsx    # 用户前台认证上下文
│   ├── hooks/
│   │   └── use-mobile.ts           # 共享移动端检测hook
│   └── api.ts                      # API客户端配置
```

### React Query使用模式

项目采用简单的React Query使用模式：

**配置方式**: 在每个入口文件独立创建QueryClient
```typescript
// 在入口文件中创建QueryClient
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 1,
      refetchOnWindowFocus: false,
    },
  },
})
```

**查询模式**: 直接在组件中使用useQuery
```typescript
// 数据查询示例
const { data: usersData, isLoading, refetch } = useQuery({
  queryKey: ['users', searchParams],
  queryFn: async () => {
    const res = await userClient.$get({ query: searchParams })
    if (res.status !== 200) throw new Error('获取失败')
    return await res.json()
  }
})
```

**数据变更模式**: 直接调用API客户端 + 手动refetch
```typescript
// 数据变更示例（未使用useMutation）
const handleCreateSubmit = async (data: CreateUserFormData) => {
  try {
    const res = await userClient.$post({ json: data })
    if (res.status !== 201) throw new Error('创建失败')
    toast.success('创建成功')
    refetch() // 手动重新获取数据
  } catch (error) {
    console.error('操作失败:', error)
    toast.error('操作失败，请重试')
  }
}
```

### 当前状态管理特点

1. **模块化认证**: 管理后台和用户前台有独立的认证Provider
2. **简单配置**: QueryClient在每个入口文件独立配置，无复杂全局配置
3. **混合模式**: Context管理认证状态 + React Query管理数据查询
4. **手动数据同步**: 数据变更后手动调用refetch更新缓存
5. **渐进式采用**: 逐步引入React Query，尚未全面使用useMutation

## 6. API集成

### Hono RPC集成模式

项目使用自定义的axios适配器实现Hono RPC客户端：

```typescript
// 自定义axios适配器 (src/client/api.ts)
const axiosFetch = async (url: RequestInfo | URL, init?: RequestInit) => {
  const requestHeaders: Record<string, string> = {};

  if (init?.headers instanceof Headers) {
    init.headers.forEach((value, key) => {
      requestHeaders[key] = value;
    })
  }

  const response = await axios.request({
    url: url.toString(),
    method: init?.method || 'GET',
    headers: requestHeaders,
    data: init?.body,
  }).catch((error) => {
    if (isAxiosError(error)) {
      return {
        status: error.response?.status,
        statusText: error.response?.statusText,
        data: error.response?.data,
        headers: error.response?.headers
      }
    }
    throw error;
  })

  const responseHeaders = new Headers();
  if (response.headers) {
    for (const [key, value] of Object.entries(response.headers)) {
      responseHeaders.set(key, value);
    }
  }

  // 处理204 No Content响应
  const body = response.status === 204
    ? null
    : responseHeaders.get('content-type')?.includes('application/json')
      ? JSON.stringify(response.data)
      : response.data;

  return new Response(
    body,
    {
      status: response.status,
      statusText: response.statusText,
      headers: responseHeaders
    }
  )
}

// Hono客户端实例导出
export const authClient = hc<AuthRoutes>('/', {
  fetch: axiosFetch,
}).api.v1.auth;

export const userClient = hc<UserRoutes>('/', {
  fetch: axiosFetch,
}).api.v1.users;

export const roleClient = hc<RoleRoutes>('/', {
  fetch: axiosFetch,
}).api.v1.roles;
```

### 类型安全集成

后端使用OpenAPIHono定义路由类型：
```typescript
// 服务器端路由定义 (src/server/api.ts)
const userRoutes = api.route('/api/v1/users', usersRouter)
const authRoutes = api.route('/api/v1/auth', authRoute)
const roleRoutes = api.route('/api/v1/roles', rolesRoute)

export type AuthRoutes = typeof authRoutes
export type UserRoutes = typeof userRoutes
export type RoleRoutes = typeof roleRoutes
```

### 使用模式

在组件中直接使用类型安全的客户端：
```typescript
// 使用Hono RPC客户端
const response = await userClient.$get({
  query: { page: 1, pageSize: 10, keyword: 'search' }
})

if (response.status === 200) {
  const data = await response.json()
  // 类型安全的data
}
```

## 7. 路由配置

### 当前路由架构

**双路由系统**:
- 管理后台路由: `/admin/*` (位于 `src/client/admin/routes.tsx`)
- 用户前台路由: `/*` (位于 `src/client/home/routes.tsx`)

**路由结构**:
```typescript
// 管理后台路由
- /admin/login      → 登录页面
- /admin            → 重定向到仪表板 (保护路由)
- /admin/dashboard  → 仪表板页面 (保护路由)
- /admin/users      → 用户管理页面 (保护路由)

// 用户前台路由
- /          → 首页
- /login     → 登录页面
- /register  → 注册页面
- /member    → 会员页面 (保护路由)
```

### 认证保护

```typescript
export const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
  const { isAuthenticated, isLoading } = useAuth();
  const navigate = useNavigate();

  useEffect(() => {
    if (!isLoading && !isAuthenticated) {
      navigate('/admin/login', { replace: true });
    }
  }, [isAuthenticated, isLoading, navigate]);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return null;
  }

  return children;
};
```

## 8. 样式指南

### 主题系统

基于CSS自定义属性的主题系统：

```css
:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  /* ... 更多设计token */
}

.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --primary: oklch(0.985 0 0);
  /* ... 暗色主题变量 */
}
```

### 样式方法论

- **原子化CSS**: 使用Tailwind工具类构建UI
- **CSS变量**: 通过CSS自定义属性实现主题切换
- **设计系统**: 基于shadcn/ui的组件设计规范
- **响应式**: 移动优先的响应式设计

## 9. 测试要求

### 测试策略

**测试框架**: Vitest + Testing Library
**测试位置**: `__tests__`文件夹与源码并列
**覆盖率目标**: 核心组件80%+覆盖率

### 测试模板

```typescript
describe('Button', () => {
  it('renders correctly with default variant', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByRole('button')).toHaveTextContent('Click me')
  })

  it('calls onClick handler when clicked', () => {
    const handleClick = vi.fn()
    render(<Button onClick={handleClick}>Click me</Button>)

    fireEvent.click(screen.getByRole('button'))
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
})
```

## 10. 环境配置

### 环境变量

```bash
# 实际环境变量配置（基于服务器端配置）
OSS_BASE_URL=https://oss.d8d.fun
APP_NAME=多八多Aider
```

## 11. 前端开发标准

### 关键编码规则

1. **类型安全**: 全面使用TypeScript，避免any类型
2. **组件设计**: 遵循单一职责原则
3. **性能优化**: 使用React.memo、useCallback等优化手段
4. **错误处理**: 统一的错误边界和异常处理
5. **可访问性**: 支持ARIA属性和键盘导航

### 快速参考

**常用命令**:
```bash
npm run dev      # 启动开发服务器
npm run build    # 生产构建
npm run test     # 运行测试
```

---

**文档状态**: 正式版
**下次评审**: 2025-10-15
**架构师**: Winston 🏗️