🚀 前端代码生成标准模板与代码规范约束规则

基于 OpenClaw + Claude Code 的端到端研发自动化系统

文档版本:v1.0 | 生成日期:2026 年 3 月 14 日 | 适用框架:React/Vue/Angular + TypeScript

研发角色 Agent:前端开发工程师 Agent | 支持人机协同

第一章:概述与设计原则

📌 核心目标:建立一套完整的、可被 AI 理解执行的前端代码生成标准体系,实现从需求到代码的自动化转换,同时保证代码质量、一致性和可维护性。

1.1 适用范围

本规范适用于基于 OpenClaw + Claude Code 的端到端研发自动化系统中的前端开发环节,覆盖以下技术栈:

1.2 设计原则

✨ AI 优先原则

  • 所有规范必须能被 AI 模型准确理解
  • 提供明确的约束条件和示例代码
  • 避免模糊表述和主观判断
  • 支持 Spec Coding(规格驱动编码)工作流

🏗️ 工程化原则

  • 统一的目录结构和文件组织
  • 严格的类型安全和代码检查
  • 自动化的代码格式化和 linting
  • 完善的测试覆盖和质量门禁

🔄 可维护性原则

  • 组件高内聚低耦合
  • 清晰的职责划分和边界
  • 一致的命名和代码风格
  • 完善的文档和注释规范

⚡ 性能优化原则

  • 按需加载和代码分割
  • 避免不必要的重渲染
  • 优化的资源管理和缓存策略
  • 首屏加载时间 < 2s

1.3 AI Coding 工作流集成

本规范深度集成到 OpenClaw + Claude Code 的研发自动化流程中,具体节点如下:

  1. 需求分析 → PRD 设计:AI 提取前端功能需求点
  2. 技术方案设计:AI 生成前端架构设计文档
  3. API 接口协议设计:AI 生成 OpenAPI/Swagger 规范
  4. AI Coding:Claude Code 根据本规范自动生成代码
  5. Unit Test:AI 生成单元测试代码
  6. 集成测试:AI 生成 E2E 测试脚本
  7. Code Review:AI 自动审查代码合规性
  8. CI/CD 部署:自动化构建和部署流程

第二章:项目目录结构标准模板

📁 设计思想:采用特性优先(Feature-First)的组织方式,按业务模块划分,而非按文件类型划分,便于大型项目的维护和团队协作。

2.1 标准目录结构(React + TypeScript + Vite)

project-root/
├── .github/                      # GitHub 配置(Actions, Templates)
│   ├── workflows/
│   │   ├── ci.yml                 # CI 流水线配置
│   │   └── cd.yml                 # CD 部署配置
│   └── pull_request_template.md
│
├── .vscode/                      # VSCode 工作区配置
│   ├── settings.json
│   ├── extensions.json
│   └── launch.json
│
├── public/                       # 静态资源(不经过构建)
│   ├── favicon.ico
│   ├── robots.txt
│   └── manifest.json
│
├── src/                          # 源代码目录
│   ├── main.tsx                 # 应用入口
│   ├── App.tsx                  # 根组件
│   ├── vite-env.d.ts            # Vite 类型声明
│   │
│   ├── features/                 【核心】业务特性模块(按领域划分)
│   │   ├── user/                 # 用户相关功能
│   │   │   ├── components/       # 用户模块专属组件
│   │   │   │   ├── UserProfile.tsx
│   │   │   │   ├── UserList.tsx
│   │   │   │   └── index.ts      # 统一导出
│   │   │   ├── hooks/            # 用户模块自定义 Hooks
│   │   │   │   ├── useUser.ts
│   │   │   │   └── useUserList.ts
│   │   │   ├── services/         # 用户模块 API 服务
│   │   │   │   └── userService.ts
│   │   │   ├── types/            # 用户模块类型定义
│   │   │   │   └── user.types.ts
│   │   │   ├── store/            # 用户模块状态管理
│   │   │   │   └── userStore.ts
│   │   │   └── index.ts          # 模块统一导出
│   │   │
│   │   ├── product/              # 产品相关功能
│   │   │   ├── components/
│   │   │   ├── hooks/
│   │   │   ├── services/
│   │   │   ├── types/
│   │   │   └── store/
│   │   │
│   │   └── order/                # 订单相关功能
│   │       └── ...
│   │
│   ├── components/               # 通用基础组件(跨业务复用)
│   │   ├── ui/                   # 原子级 UI 组件
│   │   │   ├── Button/
│   │   │   │   ├── Button.tsx
│   │   │   │   ├── Button.styles.ts
│   │   │   │   ├── Button.test.tsx
│   │   │   │   └── index.ts
│   │   │   ├── Input/
│   │   │   ├── Modal/
│   │   │   └── ...
│   │   ├── layout/               # 布局组件
│   │   │   ├── Header.tsx
│   │   │   ├── Footer.tsx
│   │   │   └── Sidebar.tsx
│   │   └── index.ts
│   │
│   ├── pages/                    # 页面组件(路由级别)
│   │   ├── HomePage.tsx
│   │   ├── LoginPage.tsx
│   │   ├── UserProfilePage.tsx
│   │   └── index.tsx             # 路由配置
│   │
│   ├── hooks/                    # 全局通用 Hooks
│   │   ├── useAuth.ts
│   │   ├── useDebounce.ts
│   │   ├── useLocalStorage.ts
│   │   └── index.ts
│   │
│   ├── services/                 # 全局 API 服务层
│   │   ├── api.ts                # Axios 实例配置
│   │   ├── interceptors.ts       # 请求/响应拦截器
│   │   └── types.ts              # API 响应类型
│   │
│   ├── store/                    # 全局状态管理
│   │   ├── index.ts              # Store 初始化
│   │   └── middleware.ts         # 中间件配置
│   │
│   ├── styles/                   # 全局样式
│   │   ├── globals.css           # 全局 CSS 变量和重置
│   │   ├── themes.ts             # 主题配置
│   │   └── mixins.ts             # 样式混入
│   │
│   ├── utils/                    # 工具函数
│   │   ├── format.ts
│   │   ├── validate.ts
│   │   ├── helpers.ts
│   │   └── index.ts
│   │
│   ├── constants/                # 常量定义
│   │   ├── routes.ts
│   │   ├── config.ts
│   │   └── index.ts
│   │
│   ├── types/                    # 全局类型定义
│   │   ├── common.types.ts
│   │   ├── api.types.ts
│   │   └── index.ts
│   │
│   └── assets/                   # 静态资源(经过构建)
│       ├── images/
│       ├── fonts/
│       └── icons/
│
├── tests/                        # 测试文件
│   ├── unit/                     # 单元测试
│   ├── integration/              # 集成测试
│   ├── e2e/                      # E2E 测试
│   ├── mocks/                    # Mock 数据
│   └── setup.ts                  # 测试环境配置
│
├── docs/                         # 项目文档
│   ├── architecture.md
│   ├── api-spec.md
│   └── deployment.md
│
├── scripts/                      # 构建脚本
│   ├── generate-types.ts
│   └── optimize-assets.js
│
├── .env                          # 环境变量(本地)
├── .env.example                  # 环境变量模板
├── .eslintrc.cjs                 # ESLint 配置
├── .prettierrc                   # Prettier 配置
├── .stylelintrc                  # Stylelint 配置
├── tsconfig.json                 # TypeScript 配置
├── vite.config.ts                # Vite 配置
├── vitest.config.ts              # Vitest 配置
├── package.json                  # 依赖管理
├── README.md                     # 项目说明
└── CLAUDE.md                     【重要】AI Coding 规范文件

2.2 CLAUDE.md 文件规范 AI 必读

CLAUDE.md 是 AI Coding 的核心配置文件,用于指导 Claude Code 按照项目规范生成代码。

# CLAUDE.md - AI Coding 规范配置文件
# 此文件定义了 AI 在生成代码时必须遵循的规则和约束

## 项目技术栈
- **Framework**: React 18.2+ with TypeScript 5.3+
- **Build Tool**: Vite 5.0+
- **State Management**: Zustand 4.4+
- **HTTP Client**: Axios 1.6+
- **UI Library**: Ant Design 5.12+
- **Styling**: TailwindCSS 3.4+ with CSS Modules
- **Testing**: Vitest + @testing-library/react
- **Package Manager**: pnpm 8.10+

## 代码生成规则

### 必须遵守
1. 所有组件必须使用 TypeScript,禁止使用 any 类型
2. 函数组件优先,使用箭头函数语法
3. Props 必须定义明确的 interface 或 type
4. 所有异步操作必须有错误处理
5. 组件必须有 displayName
6. 导出顺序:默认导出在前,命名导出在后

### 禁止行为
1. ❌ 禁止使用 class 组件
2. ❌ 禁止使用隐式 any
3. ❌ 禁止直接修改 state(必须使用 setState)
4. ❌ 禁止在 render 方法中创建对象/数组
5. ❌ 禁止使用 eval() 和 new Function()

## 文件命名规范
- 组件文件:PascalCase.tsx (例:UserProfile.tsx)
- Hook 文件:use*.ts (例:useAuth.ts)
- 服务文件:*.service.ts (例:user.service.ts)
- 类型文件:*.types.ts (例:user.types.ts)
- 样式文件:*.module.css 或 *.styles.ts
- 测试文件:*.test.tsx 或 *.test.ts

## 组件模板
\`\`\`tsx
import React from 'react';
import { FC } from 'react';

interface ComponentNameProps {
  /** 属性描述 */
  propName: string;
}

export const ComponentName: FC<ComponentNameProps> = ({ propName }) => {
  // 组件逻辑
  
  return (
    <div className="component-name">
      {propName}
    </div>
  );
};

ComponentName.displayName = 'ComponentName';
\`\`\`

## API 调用规范
1. 使用 services 层封装 API 调用
2. 所有 API 函数必须返回 Promise
3. 使用 try-catch 处理错误
4. 使用 Axios 拦截器统一处理认证和错误

## 状态管理规范
1. 优先使用 Zustand 进行状态管理
2. Store 文件放在 features/*/store/目录
3. 使用 selector 模式访问状态
4. 避免在组件中直接调用 setState

## 测试要求
1. 每个组件必须有单元测试
2. 测试覆盖率要求:语句>80%, 分支>70%
3. 使用 Testing Library 最佳实践
4. Mock 外部依赖(API、定时器等)

## Git 提交规范
遵循 Conventional Commits:
- feat: 新功能
- fix: 修复 bug
- docs: 文档更新
- style: 代码格式
- refactor: 重构
- test: 测试相关
- chore: 构建/工具相关

第三章:代码命名规范约束规则

3.1 文件和目录命名

类型 命名规则 示例 说明
组件文件 PascalCase.tsx UserProfile.tsx React 组件必须使用大驼峰
Hook 文件 usePascalCase.ts useAuth.ts, useUserProfile.ts 自定义 Hook 必须以 use 开头
服务文件 camelCase.service.ts userService.ts, authService.ts 服务层文件添加.service 后缀
类型定义 camelCase.types.ts user.types.ts 类型定义文件添加.types 后缀
工具函数 camelCase.ts format.ts, validate.ts 按功能分类组织
常量文件 UPPER_CASE.ts 或 camelCase.ts API_ENDPOINTS.ts 纯常量用大写,配置用小写
样式文件 camelCase.module.css UserProfile.module.css CSS Modules 必须添加.module 后缀
测试文件 camelCase.test.ts(x) UserProfile.test.tsx 测试文件与被测组件同名
目录名 kebab-case 或 camelCase user-profile/userProfile/ 特性目录推荐 kebab-case

3.2 变量和函数命名

✅ 正确示例

// 变量命名
const userName = 'John';          // camelCase
const USER_ROLE = 'ADMIN';        // UPPER_CASE 常量
const UserList = () => {...};     // PascalCase 组件

// 函数命名
function getUserById(id: number) {...}
const handleClick = () => {...};
const useUserProfile = () => {...}; // Hook

// 布尔值变量
const isLoading = true;
const hasPermission = false;
const canEdit = true;

// 集合类型
const userList: User[] = [];
const userMap: Map<number, User> = new Map();

❌ 错误示例

// 禁止的命名
const user_name = 'John';         // ❌ snake_case
const UserName = 'John';          // ❌ 变量用 PascalCase
const USER_NAME = 'John';         // ❌ 非常量用大写
let data: any;                    // ❌ 使用 any
const tmp = 'value';              // ❌ 无意义命名
const flag = true;                // ❌ 不明确布尔值

// 函数命名
function get_user() {...}          // ❌ snake_case
function GetData() {...}           // ❌ 函数用 PascalCase
const clickHandle = () => {...};  // ❌ 事件处理应为 handleClick

3.3 TypeScript 类型命名

// Interface 命名 - PascalCase
interface UserProfile {
  id: number;
  name: string;
}

// Type Alias 命名 - PascalCase
type UserRole = 'ADMIN' | 'USER' | 'GUEST';

// Props 类型命名 - 组件名 + Props
interface UserProfileProps {
  userId: number;
  showAvatar?: boolean;
}

// State 类型命名 - 组件名 + State
interface UserProfileState {
  isLoading: boolean;
  error: string | null;
}

// Event Handler 类型命名 - On + 事件名
type OnUserClick = (userId: number) => void;

// API Response 类型命名 - 功能名 + Response
interface UserListResponse {
  data: User[];
  total: number;
  page: number;
}

// API Request 类型命名 - 功能名 + Request
interface CreateUserRequest {
  name: string;
  email: string;
}

3.4 CSS 类名命名(BEM + 语义化)

/* BEM 命名规范 */
/* Block */
.user-profile { }

/* Element */
.user-profile__avatar { }
.user-profile__name { }

/* Modifier */
.user-profile--active { }
.user-profile__name--highlighted { }

/* 状态前缀 */
.is-loading { }
.is-disabled { }
.has-error { }

/* JS 钩子类名(不添加样式) */
.js-user-modal { }

第四章:组件开发规范与模板

4.1 组件分类与职责

组件类型 存放位置 职责 示例
原子组件 components/ui/ 不可拆分的基础 UI 元素 Button, Input, Icon
分子组件 components/ui/ 原子组件的组合 SearchBar, FormField
业务组件 features/*/components/ 特定业务功能的组件 UserProfile, ProductCard
布局组件 components/layout/ 页面结构和布局 Header, Footer, Sidebar
页面组件 pages/ 完整页面,路由级别 HomePage, LoginPage
模板组件 components/templates/ 页面布局模板 DashboardLayout, AuthLayout

4.2 标准组件模板 AI 生成必用

import React, { FC, memo } from 'react';
import styles from './ComponentName.module.css';

/**
 * 组件名称:ComponentName
 * 功能描述:简要描述组件功能
 * 使用示例:
 * <ComponentName propName="value" />
 */

// Props 类型定义
export interface ComponentNameProps {
  /** 属性 1 描述 */
  prop1: string;
  
  /** 属性 2 描述(可选) */
  prop2?: number;
  
  /** 子元素 */
  children?: React.ReactNode;
  
  /** 点击事件处理 */
  onClick?: () => void;
}

// 组件定义
export const ComponentName: FC<ComponentNameProps> = memo(({ 
  prop1, 
  prop2 = 0, 
  children,
  onClick 
}) => {
  // ========== Hooks 区域 ==========
  // 自定义 Hooks 调用
  
  // ========== State 区域 ==========
  // 本地状态定义
  
  ========== Effects 区域 ==========
  // useEffect 逻辑
  
  // ========== Handlers 区域 ==========
  const handleClick = () => {
    onClick?.();
  };
  
  // ========== Render 区域 ==========
  return (
    <div 
      className={styles.container}
      data-testid="component-name"
      role="button"
      tabIndex={0}
      onClick={handleClick}
    >
      <h1 className={styles.title}>{prop1}</h1>
      {children}
    </div>
  );
});

// 设置显示名称
ComponentName.displayName = 'ComponentName';

// 导出默认(可选)
export default ComponentName;

4.3 组件开发约束规则

⚠️ 必须遵守的约束:
  • 组件必须是纯函数,不能有副作用(副作用放在 useEffect)
  • Props 必须定义完整的 TypeScript 类型
  • 必须使用 memo() 包裹组件以优化性能
  • 必须设置 displayName 便于调试
  • 事件处理器必须使用 handle 前缀
  • 条件渲染使用三元运算符或逻辑与,避免 if 语句
  • 列表渲染必须提供稳定的 key
  • 禁止在 JSX 中定义对象或数组(会导致重复渲染)

4.4 Custom Hook 模板

import { useState, useEffect, useCallback } from 'react';

/**
 * Hook 名称:useHookName
 * 功能描述:简要描述 Hook 功能
 * 返回值:返回的状态和方法说明
 */

interface UseHookNameReturn {
  /** 状态 1 */
  data: DataType | null;
  
  /** 加载状态 */
  isLoading: boolean;
  
  /** 错误信息 */
  error: string | null;
  
  /** 刷新方法 */
  refresh: () => Promise<void>;
}

export const useHookName = (params: HookParams): UseHookNameReturn => {
  // ========== State 区域 ==========
  const [data, setData] = useState<DataType | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  
  // ========== Logic 区域 ==========
  const fetchData = useCallback(async () => {
    try {
      setIsLoading(true);
      setError(null);
      
      // API 调用逻辑
      const response = await api.getData(params);
      setData(response.data);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error');
    } finally {
      setIsLoading(false);
    }
  }, [params]);
  
  // ========== Effect 区域 ==========
  useEffect(() => {
    fetchData();
  }, [fetchData]);
  
  // ========== Return 区域 ==========
  return {
    data,
    isLoading,
    error,
    refresh: fetchData,
  };
};

第五章:前端 API 接口调用规范与模板

5.1 API 服务层架构

/* src/services/api.ts - Axios 实例配置 */
import axios, { AxiosInstance, AxiosError } from 'axios';
import type { ApiResponse } from '../types/api.types';

// 创建 Axios 实例
export const apiClient: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api/v1',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// 请求拦截器
apiClient.interceptors.request.use(
  (config) => {
    // 添加认证 Token
    const token = localStorage.getItem('access_token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    // 添加请求 ID 用于追踪
    config.headers['X-Request-ID'] = crypto.randomUUID();
    
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器
apiClient.interceptors.response.use(
  (response) => response.data,
  (error: AxiosError<ApiResponse>) => {
    // 统一错误处理
    const status = error.response?.status;
    
    switch (status) {
      case 401:
        // 未授权,跳转登录
        window.location.href = '/login';
        break;
      case 403:
        // 禁止访问
        console.error('Access denied');
        break;
      case 404:
        // 资源不存在
        console.error('Resource not found');
        break;
      case 500:
        // 服务器错误
        console.error('Server error');
        break;
      default:
        console.error('Unknown error');
    }
    
    return Promise.reject(error);
  }
);

5.2 Service 层模板

/* src/features/user/services/userService.ts */
import { apiClient } from '../../../services/api';
import type { User, UserListResponse, CreateUserRequest } from '../types/user.types';

/**
 * 用户服务层
 * 封装所有用户相关的 API 调用
 */
export const userService = {
  /**
   * 获取用户详情
   * @param userId - 用户 ID
   * @returns Promise<User>
   */
  getUserById: async (userId: number): Promise<User> => {
    return apiClient.get<User>(`/users/${userId}`);
  },

  /**
   * 获取用户列表(分页)
   * @param params - 查询参数
   * @returns Promise<UserListResponse>
   */
  getUserList: async (params: {
    page: number;
    pageSize: number;
    keyword?: string;
  }): Promise<UserListResponse> => {
    return apiClient.get<UserListResponse>('/users', { params });
  },

  /**
   * 创建用户
   * @param data - 用户数据
   * @returns Promise<User>
   */
  createUser: async (data: CreateUserRequest): Promise<User> => {
    return apiClient.post<User>('/users', data);
  },

  /**
   * 更新用户
   * @param userId - 用户 ID
   * @param data - 更新数据
   * @returns Promise<User>
   */
  updateUser: async (
    userId: number, 
    data: Partial<CreateUserRequest>
  ): Promise<User> => {
    return apiClient.put<User>(`/users/${userId}`, data);
  },

  /**
   * 删除用户
   * @param userId - 用户 ID
   * @returns Promise<void>
   */
  deleteUser: async (userId: number): Promise<void> => {
    return apiClient.delete(`/users/${userId}`);
  },
};

5.3 API 类型定义

/* src/types/api.types.ts */

/** 通用 API 响应结构 */
export interface ApiResponse<T = any> {
  code: number;
  message: string;
  data: T;
  timestamp: number;
}

/** 分页参数 */
export interface PaginationParams {
  page: number;
  pageSize: number;
  sortBy?: string;
  sortOrder?: 'asc' | 'desc';
}

/** 分页响应 */
export interface PaginatedResponse<T> {
  items: T[];
  total: number;
  page: number;
  pageSize: number;
  totalPages: number;
}

/** 上传文件响应 */
export interface UploadResponse {
  url: string;
  filename: string;
  size: number;
}

5.4 React Query 集成(可选)

/* 使用 React Query 管理服务端状态 */
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { userService } from '../services/userService';

// Query Keys 常量
export const userKeys = {
  all: ['users'] as const,
  lists: () => [...userKeys.all, 'list'] as const,
  list: (params: any) => [...userKeys.lists(), params] as const,
  details: () => [...userKeys.all, 'detail'] as const,
  detail: (id: number) => [...userKeys.details(), id] as const,
};

// 获取用户列表 Hook
export const useUserList = (params: PaginationParams) => {
  return useQuery({
    queryKey: userKeys.list(params),
    queryFn: () => userService.getUserList(params),
    staleTime: 5 * 60 * 1000, // 5 分钟
  });
};

// 获取用户详情 Hook
export const useUser = (userId: number) => {
  return useQuery({
    queryKey: userKeys.detail(userId),
    queryFn: () => userService.getUserById(userId),
    enabled: !!userId,
  });
};

// 创建用户 Mutation
export const useCreateUser = () => {
  const queryClient = useQueryClient();
  
  return useMutation({
    mutationFn: userService.createUser,
    onSuccess: () => {
      // 失效用户列表缓存
      queryClient.invalidateQueries({ queryKey: userKeys.lists() });
    },
  });
};

第六章:前端状态管理规范与模板

6.1 状态管理选型原则

🟢 推荐使用:Zustand

  • 轻量级(<1KB)
  • API 简洁易用
  • 支持 TypeScript
  • 无样板代码
  • 适合中小型项目

🟡 备选:Redux Toolkit

  • 生态成熟
  • DevTools 完善
  • 适合大型复杂项目
  • 学习曲线较陡

🟡 Vue 项目:Pinia

  • Vue 3 官方推荐
  • TypeScript 友好
  • API 简洁
  • 替代 Vuex

6.2 Zustand Store 模板

/* src/features/user/store/userStore.ts */
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import type { User } from '../types/user.types';
import { userService } from '../services/userService';

// State 类型定义
interface UserState {
  // 当前用户
  currentUser: User | null;
  
  // 用户列表
  userList: User[];
  
  // 加载状态
  isLoading: boolean;
  
  // 错误信息
  error: string | null;
  
  // Actions
  setCurrentUser: (user: User | null) => void;
  fetchUser: (userId: number) => Promise<void>;
  fetchUserList: () => Promise<void>;
  updateUser: (userId: number, data: Partial<User>) => Promise<void>;
  clearError: () => void;
}

// 创建 Store
export const useUserStore = create<UserState>()(
  devtools(
    persist(
      (set, get) => ({
        // Initial State
        currentUser: null,
        userList: [],
        isLoading: false,
        error: null,

        // Actions
        setCurrentUser: (user) => set({ currentUser: user }),

        fetchUser: async (userId) => {
          set({ isLoading: true, error: null });
          try {
            const user = await userService.getUserById(userId);
            set({ currentUser: user, isLoading: false });
          } catch (error) {
            set({ 
              error: error instanceof Error ? error.message : 'Failed to fetch user',
              isLoading: false 
            });
          }
        },

        fetchUserList: async () => {
          set({ isLoading: true, error: null });
          try {
            const response = await userService.getUserList({ page: 1, pageSize: 20 });
            set({ userList: response.data, isLoading: false });
          } catch (error) {
            set({ 
              error: error instanceof Error ? error.message : 'Failed to fetch users',
              isLoading: false 
            });
          }
        },

        updateUser: async (userId, data) => {
          set({ isLoading: true, error: null });
          try {
            const updatedUser = await userService.updateUser(userId, data);
            set((state) => ({
              currentUser: state.currentUser?.id === userId ? updatedUser : state.currentUser,
              userList: state.userList.map(u => u.id === userId ? updatedUser : u),
              isLoading: false,
            }));
          } catch (error) {
            set({ 
              error: error instanceof Error ? error.message : 'Failed to update user',
              isLoading: false 
            });
          }
        },

        clearError: () => set({ error: null }),
      }),
      { name: 'user-store' } // persist 配置
    ),
    { name: 'UserStore' } // devtools 配置
  )
);

// Selectors(推荐模式)
export const selectCurrentUser = (state: UserState) => state.currentUser;
export const selectIsLoading = (state: UserState) => state.isLoading;
export const selectError = (state: UserState) => state.error;

6.3 在组件中使用 Store

import React from 'react';
import { useUserStore, selectCurrentUser, selectIsLoading } from '../store/userStore';

export const UserProfile: FC = () => {
  // 使用 selector 模式(避免不必要的重渲染)
  const currentUser = useUserStore(selectCurrentUser);
  const isLoading = useUserStore(selectIsLoading);
  
  // 直接使用整个 store(会订阅所有变化)
  // const { currentUser, isLoading } = useUserStore();
  
  if (isLoading) {
    return <div>Loading...</div>;
  }
  
  if (!currentUser) {
    return <div>No user found</div>;
  }
  
  return (
    <div>
      <h1>{currentUser.name}</h1>
      <p>{currentUser.email}</p>
    </div>
  );
};

第七章:前端样式/CSS 规范与模板

7.1 样式方案选型

方案 适用场景 优点 缺点
TailwindCSS 快速原型、小型项目 开发速度快、无需写 CSS HTML 冗长、学习成本
CSS Modules 中大型项目(推荐) 作用域隔离、易于维护 需要额外文件
Styled Components 主题化需求强的项目 动态样式、组件化 运行时开销
Sass/SCSS 传统项目迁移 功能强大、生态成熟 需要编译

7.2 CSS Modules 模板(推荐)

/* UserProfile.module.css */

/* ========== 变量定义 ========== */
:root {
  /* 颜色变量 */
  --primary-color: #00f5ff;
  --secondary-color: #7b2cbf;
  --text-color: #e0e7ff;
  --bg-color: #0a0e27;
  
  /* 间距变量 */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  
  /* 字体大小 */
  --font-sm: 0.875rem;
  --font-md: 1rem;
  --font-lg: 1.25rem;
  --font-xl: 1.5rem;
}

/* ========== 容器样式 ========== */
.container {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  padding: var(--spacing-lg);
  background-color: var(--bg-color);
  border-radius: 8px;
  border: 1px solid rgba(0, 245, 255, 0.2);
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: var(--spacing-md);
  border-bottom: 2px solid var(--primary-color);
}

.title {
  font-size: var(--font-xl);
  color: var(--primary-color);
  font-weight: 600;
}

.avatar {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--secondary-color);
}

.content {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--spacing-md);
}

.infoItem {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.label {
  font-size: var(--font-sm);
  color: rgba(224, 231, 255, 0.6);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.value {
  font-size: var(--font-md);
  color: var(--text-color);
}

/* ========== 状态修饰符 ========== */
.container--loading {
  opacity: 0.6;
  pointer-events: none;
}

.value--highlighted {
  color: var(--primary-color);
  font-weight: 600;
}

/* ========== 响应式 ========== */
@media (max-width: 768px) {
  .container {
    padding: var(--spacing-sm);
  }
  
  .header {
    flex-direction: column;
    gap: var(--spacing-sm);
  }
  
  .content {
    grid-template-columns: 1fr;
  }
}

7.3 TailwindCSS 使用规范

/* 使用 TailwindCSS 时的组件写法 */
import React from 'react';

interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  children: React.ReactNode;
  onClick?: () => void;
}

export const Button: FC<ButtonProps> = ({ 
  variant = 'primary', 
  size = 'md',
  children, 
  onClick 
}) => {
  // 使用 clsx 或 classnames 合并类名
  const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2';
  
  const variantStyles = {
    primary: 'bg-cyan-400 text-gray-900 hover:bg-cyan-500 focus:ring-cyan-400',
    secondary: 'bg-purple-600 text-white hover:bg-purple-700 focus:ring-purple-600',
    danger: 'bg-pink-600 text-white hover:bg-pink-700 focus:ring-pink-600',
  };
  
  const sizeStyles = {
    sm: 'px-3 py-1.5 text-sm',
    md: 'px-4 py-2 text-base',
    lg: 'px-6 py-3 text-lg',
  };
  
  const classNames = `${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]}`;
  
  return (
    <button 
      className={classNames}
      onClick={onClick}
      type="button"
    >
      {children}
    </button>
  );
};

7.4 全局样式变量

/* src/styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
  /* 品牌色 */
  --color-primary: #00f5ff;
  --color-secondary: #7b2cbf;
  --color-accent: #f72585;
  
  /* 中性色 */
  --color-dark: #0a0e27;
  --color-darker: #050818;
  --color-light: #e0e7ff;
  
  /* 功能色 */
  --color-success: #00ff88;
  --color-warning: #ffb700;
  --color-error: #ff4757;
  --color-info: #00f5ff;
  
  /* 间距系统 */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  
  /* 字体大小 */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;
  
  /* 圆角 */
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-2xl: 1rem;
  --radius-full: 9999px;
  
  /* 阴影 */
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
  --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
  
  /* 过渡 */
  --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-base: 300ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* 全局重置 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background-color: var(--color-darker);
  color: var(--color-light);
  line-height: 1.6;
}

/* 滚动条美化 */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-track {
  background: var(--color-dark);
}

::-webkit-scrollbar-thumb {
  background: var(--color-secondary);
  border-radius: var(--radius-full);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--color-primary);
}

第八章:前端测试规范与模板

8.1 测试金字塔

📊 测试覆盖率要求:
  • 单元测试(Unit Tests):覆盖率 ≥ 80%(语句)、≥ 70%(分支)
  • 集成测试(Integration Tests):关键业务流程 100% 覆盖
  • E2E 测试(End-to-End):核心用户路径 100% 覆盖

8.2 单元测试模板(Vitest + Testing Library)

/* src/components/ui/Button/Button.test.tsx */
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

describe('Button Component', () => {
  // ========== 渲染测试 ==========
  it('should render button with text', () => {
    render(<Button>Click Me</Button>);
    
    const button = screen.getByRole('button', { name: /click me/i });
    expect(button).toBeInTheDocument();
  });

  it('should apply correct variant styles', () => {
    const { container } = render(<Button variant="primary">Primary</Button>);
    
    expect(container.firstChild).toHaveClass('bg-cyan-400');
  });

  // ========== 交互测试 ==========
  it('should call onClick when clicked', () => {
    const handleClick = vi.fn();
    
    render(<Button onClick={handleClick}>Click Me</Button>);
    
    const button = screen.getByRole('button');
    fireEvent.click(button);
    
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('should be disabled when disabled prop is true', () => {
    render(<Button disabled>Disabled</Button>);
    
    const button = screen.getByRole('button');
    expect(button).toBeDisabled();
  });

  // ========== 辅助功能测试 ==========
  it('should support keyboard navigation', () => {
    const handleClick = vi.fn();
    
    render(<Button onClick={handleClick}>Click Me</Button>);
    
    const button = screen.getByRole('button');
    
    // Tab 键聚焦
    button.focus();
    expect(document.activeElement).toBe(button);
    
    // Enter 键触发
    fireEvent.keyDown(button, { key: 'Enter' });
    expect(handleClick).toHaveBeenCalledTimes(1);
    
    // Space 键触发
    fireEvent.keyDown(button, { key: ' ' });
    expect(handleClick).toHaveBeenCalledTimes(2);
  });

  // ========== 快照测试 ==========
  it('should match snapshot', () => {
    const { container } = render(
      <Button variant="primary" size="md">
        Snapshot Test
      </Button>
    );
    
    expect(container).toMatchSnapshot();
  });
});

8.3 Hook 测试模板

/* src/hooks/useAuth.test.ts */
import { describe, it, expect, beforeEach } from 'vitest';
import { renderHook, act, waitFor } from '@testing-library/react';
import { useAuth } from './useAuth';

describe('useAuth Hook', () => {
  beforeEach(() => {
    localStorage.clear();
  });

  it('should return initial auth state', () => {
    const { result } = renderHook(() => useAuth());
    
    expect(result.current.isAuthenticated).toBe(false);
    expect(result.current.user).toBeNull();
  });

  it('should login successfully', async () => {
    const { result } = renderHook(() => useAuth());
    
    await act(async () => {
      await result.current.login({ 
        email: 'test@example.com', 
        password: 'password123' 
      });
    });
    
    await waitFor(() => {
      expect(result.current.isAuthenticated).toBe(true);
      expect(result.current.user).toEqual({
        email: 'test@example.com',
        name: 'Test User',
      });
    });
  });

  it('should handle login error', async () => {
    const { result } = renderHook(() => useAuth());
    
    await act(async () => {
      try {
        await result.current.login({ 
          email: 'invalid@example.com', 
          password: 'wrong' 
        });
      } catch (error) {
        // Expected error
      }
    });
    
    expect(result.current.error).toBe('Invalid credentials');
  });

  it('should logout successfully', async () => {
    const { result } = renderHook(() => useAuth());
    
    // 先登录
    await act(async () => {
      await result.current.login({ 
        email: 'test@example.com', 
        password: 'password123' 
      });
    });
    
    // 再登出
    await act(async () => {
      await result.current.logout();
    });
    
    expect(result.current.isAuthenticated).toBe(false);
    expect(result.current.user).toBeNull();
  });
});

8.4 集成测试模板

/* tests/integration/userFlow.test.tsx */
import { describe, it, expect, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from '../../src/App';
import { server } from '../mocks/server';
import { rest } from 'msw';

// MSW Mock Handler
server.use(
  rest.post('/api/login', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.json({
        token: 'mock-token',
        user: { id: 1, name: 'Test User' },
      })
    );
  })
);

describe('User Flow Integration Test', () => {
  const renderApp = () => {
    const queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
      },
    });
    
    return render(
      <QueryClientProvider client={queryClient}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </QueryClientProvider>
    );
  };

  it('should complete full user flow: login -> view profile -> logout', async () => {
    renderApp();
    
    // Step 1: 登录
    const emailInput = screen.getByLabelText(/email/i);
    const passwordInput = screen.getByLabelText(/password/i);
    const loginButton = screen.getByRole('button', { name: /login/i });
    
    fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
    fireEvent.change(passwordInput, { target: { value: 'password123' } });
    fireEvent.click(loginButton);
    
    // 等待登录成功并跳转
    await waitFor(() => {
      expect(screen.getByText(/welcome/i)).toBeInTheDocument();
    });
    
    // Step 2: 查看个人资料
    const profileLink = screen.getByRole('link', { name: /profile/i });
    fireEvent.click(profileLink);
    
    await waitFor(() => {
      expect(screen.getByText('Test User')).toBeInTheDocument();
    });
    
    // Step 3: 登出
    const logoutButton = screen.getByRole('button', { name: /logout/i });
    fireEvent.click(logoutButton);
    
    await waitFor(() => {
      expect(screen.getByRole('button', { name: /login/i })).toBeInTheDocument();
    });
  });
});

8.5 E2E 测试模板(Playwright)

/* tests/e2e/user-journey.spec.ts */
import { test, expect } from '@playwright/test';

test.describe('User Journey', () => {
  test('should complete registration and login flow', async ({ page }) => {
    // 访问首页
    await page.goto('http://localhost:3000');
    
    // 点击注册按钮
    await page.click('text=Register');
    
    // 填写注册表单
    await page.fill('input[name="name"]', 'Test User');
    await page.fill('input[name="email"]', 'test@example.com');
    await page.fill('input[name="password"]', 'password123');
    
    // 提交注册
    await page.click('button[type="submit"]');
    
    // 验证注册成功
    await expect(page).toHaveURL(/dashboard/);
    await expect(page.locator('text=Welcome, Test User')).toBeVisible();
    
    // 登出
    await page.click('text=Logout');
    
    // 验证登出成功
    await expect(page).toHaveURL(/login/);
    
    // 登录
    await page.fill('input[name="email"]', 'test@example.com');
    await page.fill('input[name="password"]', 'password123');
    await page.click('button[type="submit"]');
    
    // 验证登录成功
    await expect(page).toHaveURL(/dashboard/);
  });

  test('should handle responsive design', async ({ page }) => {
    // 移动端视图
    await page.setViewportSize({ width: 375, height: 667 });
    await page.goto('http://localhost:3000');
    
    // 验证移动端菜单
    const mobileMenu = page.locator('.mobile-menu');
    await expect(mobileMenu).toBeVisible();
    
    // 桌面端视图
    await page.setViewportSize({ width: 1920, height: 1080 });
    
    // 验证桌面端导航
    const desktopNav = page.locator('.desktop-nav');
    await expect(desktopNav).toBeVisible();
  });
});

第九章:前端 CI/CD 部署规范

9.1 GitHub Actions CI 配置

# .github/workflows/ci.yml
name: Frontend CI Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  # ========== 代码质量检查 ==========
  lint:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Run ESLint
        run: pnpm lint
      
      - name: Run Type Check
        run: pnpm type-check

  # ========== 单元测试 ==========
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Run tests with coverage
        run: pnpm test -- --coverage
      
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
          fail_ci_if_error: true

  # ========== 构建验证 ==========
  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Build application
        run: pnpm build
      
      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
          retention-days: 7

  # ========== E2E 测试 ==========
  e2e:
    runs-on: ubuntu-latest
    needs: build
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      
      - name: Install Playwright
        run: pnpm exec playwright install --with-deps
      
      - name: Start preview server
        run: pnpm preview &
      
      - name: Wait for server
        run: sleep 5
      
      - name: Run E2E tests
        run: pnpm test:e2e
      
      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/

9.2 Docker 配置

# Dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder

WORKDIR /app

# 安装 pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate

# 复制依赖文件
COPY package.json pnpm-lock.yaml ./

# 安装依赖
RUN pnpm install --frozen-lockfile

# 复制源代码
COPY . .

# 构建应用
RUN pnpm build

# Stage 2: Production
FROM nginx:alpine AS production

# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html

# 暴露端口
EXPOSE 80

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1

# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]

9.3 K8s 部署配置(KubeSphere)

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-app
  namespace: production
  labels:
    app: frontend-app
    version: v1.0.0
spec:
  replicas: 3
  selector:
    matchLabels:
      app: frontend-app
  template:
    metadata:
      labels:
        app: frontend-app
    spec:
      containers:
        - name: frontend
          image: registry.example.com/frontend-app:latest
          ports:
            - containerPort: 80
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "200m"
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5
          env:
            - name: NODE_ENV
              value: "production"
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  namespace: production
spec:
  selector:
    app: frontend-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: frontend-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: frontend-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 80

9.4 Jenkins Pipeline(可选)

// Jenkinsfile
pipeline {
    agent any
    
    environment {
        DOCKER_REGISTRY = 'registry.example.com'
        IMAGE_NAME = 'frontend-app'
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Install Dependencies') {
            steps {
                sh 'pnpm install --frozen-lockfile'
            }
        }
        
        stage('Code Quality') {
            parallel {
                stage('Lint') {
                    steps {
                        sh 'pnpm lint'
                    }
                }
                stage('Type Check') {
                    steps {
                        sh 'pnpm type-check'
                    }
                }
            }
        }
        
        stage('Test') {
            steps {
                sh 'pnpm test -- --coverage'
            }
            post {
                always {
                    junit 'reports/junit-*.xml'
                    publishCoverage adapters: [coberturaAdapter('coverage/cobertura-coverage.xml')]
                }
            }
        }
        
        stage('Build') {
            steps {
                sh 'pnpm build'
            }
        }
        
        stage('Docker Build & Push') {
            steps {
                script {
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
                        def customImage = docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${BUILD_ID}")
                        customImage.push()
                        customImage.push('latest')
                    }
                }
            }
        }
        
        stage('Deploy to K8s') {
            when {
                branch 'main'
            }
            steps {
                sh '''
                    kubectl set image deployment/frontend-app \
                        frontend=${DOCKER_REGISTRY}/${IMAGE_NAME}:${BUILD_ID} \
                        -n production
                    kubectl rollout status deployment/frontend-app -n production
                '''
            }
        }
    }
    
    post {
        success {
            echo 'Pipeline completed successfully! 🎉'
        }
        failure {
            echo 'Pipeline failed! ❌'
            // 发送通知
            // slackSend channel: '#deployments', message: "Build failed: ${env.BUILD_URL}"
        }
    }
}

第十章:AI Coding Prompt 工程模板 OpenClaw + Claude Code

10.1 Spec Coding 工作流

🤖 Spec Coding(规格驱动编码):通过详细的规格说明书指导 AI 生成符合规范的代码,减少迭代次数,提高代码质量。

10.2 组件生成 Prompt 模板

# Role: 高级前端工程师 Agent
# Task: 根据规格说明生成 React + TypeScript 组件

## 上下文信息
- 项目技术栈:React 18.2 + TypeScript 5.3 + Vite 5.0
- 状态管理:Zustand 4.4
- UI 库:Ant Design 5.12
- 样式方案:CSS Modules
- 测试框架:Vitest + Testing Library

## 任务描述
请创建一个用户资料展示组件(UserProfile),需要满足以下规格:

### 功能需求
1. 展示用户基本信息(头像、姓名、邮箱、角色)
2. 支持编辑模式切换
3. 支持头像上传功能
4. 响应式设计(移动端适配)

### Props 接口
interface UserProfileProps {
  userId: number;
  editable?: boolean;
  onUserUpdate?: (userId: number, data: UserData) => void;
}

### 设计要求
- 使用 CSS Modules 进行样式隔离
- 遵循 BEM 命名规范
- 支持暗色主题
- 加载状态和错误状态处理

### 代码规范
- 必须使用 TypeScript,禁止 any 类型
- 使用 memo() 优化性能
- 完整的 JSDoc 注释
- 包含单元测试

## 输出要求
1. 生成 UserProfile.tsx 组件文件
2. 生成 UserProfile.module.css 样式文件
3. 生成 UserProfile.test.tsx 测试文件
4. 生成 index.ts 统一导出文件

## 约束条件
- 遵循项目 CLAUDE.md 中的所有规范
- 代码必须符合 ESLint 规则
- 测试覆盖率要求:语句>80%, 分支>70%

10.3 API 服务层生成 Prompt 模板

# Role: 后端 API 集成专家 Agent
# Task: 根据 OpenAPI 规范生成前端 API 服务层

## 上下文信息
- API 规范:OpenAPI 3.0 (Swagger)
- HTTP 客户端:Axios 1.6
- 认证方式:JWT Bearer Token
- 错误处理:统一拦截器

## 任务描述
请根据以下 OpenAPI 规范生成用户模块的 API 服务层代码:

### API Endpoints
```yaml
/users:
  get:
    summary: 获取用户列表
    parameters:
      - name: page
        in: query
        schema:
          type: integer
      - name: pageSize
        in: query
        schema:
          type: integer
    responses:
      200:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: array
                  items:
                    $ref: '#/components/schemas/User'
                total:
                  type: integer
  
  /users/{id}:
    get:
      summary: 获取用户详情
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
    responses:
      200:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
```

## 输出要求
1. 生成 user.types.ts 类型定义文件
2. 生成 userService.ts 服务层文件
3. 包含完整的 JSDoc 注释
4. 包含错误处理和重试逻辑

## 约束条件
- 所有 API 函数必须返回 Promise
- 使用 try-catch 处理错误
- 类型定义必须完整且准确
- 遵循项目 API 调用规范

10.4 代码审查 Prompt 模板

# Role: 代码质量审查专家 Agent
# Task: 审查生成的前端代码是否符合规范

## 审查清单

### 1. TypeScript 类型安全
- [ ] 是否使用了 any 类型(禁止)
- [ ] Props 类型是否完整定义
- [ ] 返回值类型是否明确
- [ ] 泛型使用是否恰当

### 2. 代码规范
- [ ] 文件命名是否符合约定
- [ ] 变量命名是否语义化
- [ ] 函数长度是否合理(<50 行)
- [ ] 组件复杂度是否可控

### 3. 性能优化
- [ ] 是否使用 memo() 包裹组件
- [ ] 是否存在不必要的重渲染
- [ ] 列表渲染是否使用稳定 key
- [ ] 是否在 render 中创建对象/数组

### 4. 错误处理
- [ ] 异步操作是否有 try-catch
- [ ] 是否有友好的错误提示
- [ ] 边界情况是否处理

### 5. 测试覆盖
- [ ] 是否有单元测试
- [ ] 测试用例是否充分
- [ ] 是否测试了边界情况
- [ ] 测试代码是否遵循最佳实践

### 6. 可访问性
- [ ] 是否使用语义化 HTML
- [ ] 是否支持键盘导航
- [ ] 是否有适当的 ARIA 属性
- [ ] 颜色对比度是否达标

## 输出格式
请以 JSON 格式输出审查结果:
{
  "passed": boolean,
  "issues": [
    {
      "severity": "error" | "warning" | "info",
      "rule": "规则名称",
      "message": "问题描述",
      "location": "文件:行号",
      "suggestion": "修复建议"
    }
  ],
  "score": 0-100,
  "summary": "总体评价"
}

10.5 重构优化 Prompt 模板

# Role: 代码重构优化专家 Agent
# Task: 重构现有代码以提升质量和性能

## 原始代码
[在此粘贴需要重构的代码]

## 重构目标
1. 提升代码可读性和可维护性
2. 优化性能(减少重渲染、优化计算)
3. 增强类型安全性
4. 改进错误处理
5. 添加必要的注释和文档

## 重构原则
- 保持原有功能不变
- 遵循单一职责原则
- 提取可复用的逻辑到 Hooks
- 使用更精确的 TypeScript 类型
- 添加性能优化(memo、useMemo、useCallback)

## 输出要求
1. 重构后的完整代码
2. 重构说明文档(列出所有改动)
3. 性能对比分析(如果适用)
4. 潜在的风险分析

附录:快速参考手册

A. 常用命令速查

# 开发
pnpm dev                    # 启动开发服务器
pnpm build                  # 生产构建
pnpm preview                # 预览生产构建

# 代码质量
pnpm lint                   # ESLint 检查
pnpm lint:fix               # 自动修复 ESLint 问题
pnpm type-check             # TypeScript 类型检查
pnpm format                 # Prettier 格式化

# 测试
pnpm test                   # 运行单元测试
pnpm test:watch             # 监视模式运行测试
pnpm test:coverage          # 生成测试覆盖率报告
pnpm test:e2e               # 运行 E2E 测试

# Git
git commit -m "feat: add new feature"   # 提交代码
git push origin main                    # 推送代码

B. ESLint 配置要点

// .eslintrc.cjs
module.exports = {
  root: true,
  env: { browser: true, es2020: true },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react-hooks/recommended',
  ],
  ignorePatterns: ['dist', '.eslintrc.cjs'],
  parser: '@typescript-eslint/parser',
  plugins: ['react-refresh'],
  rules: {
    'react-refresh/only-export-components': [
      'warn',
      { allowConstantExport: true },
    ],
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
  },
};

C. 项目检查清单(Checklist)

✅ 提交前检查清单:
  • [ ] 代码通过 ESLint 检查
  • [ ] TypeScript 类型检查通过
  • [ ] 单元测试通过且覆盖率达标
  • [ ] 代码已格式化
  • [ ] 提交了 CLAUDE.md 更新(如有新规范)
  • [ ] Commit Message 符合 Conventional Commits