- 新增 admin/CLAUDE.md - 管理后台开发指导文档 - 修正技术栈为 React + TypeScript + shadcn/ui - 提供完整的管理后台架构设计 - 包含照片管理、分类管理、日志管理等核心功能 - 详细的开发环境配置和部署指南 - 新增 backend/CLAUDE.md - 后端开发指导文档 - 基于 Golang + Gin + GORM 技术栈 - 完整的 API 接口设计和数据库架构 - 包含认证、权限、文件存储等核心功能 - 详细的部署和监控配置 - 新增 ui/CLAUDE.md - UI 备份模块管理文档 - 支持组件备份和 A/B 测试功能 - 详细的同步策略和实验环境配置 - 完整的版本管理和协作流程 - 更新 CLAUDE.md 根目录文档 - 完善模块选择指南和协调机制 - 新增模块间通信和依赖关系说明 - 优化文档维护和使用建议 - 建立完整的模块化开发规范 通过模块化设计最大限度减少 AI 幻觉,提高开发效率。
604 lines
16 KiB
Markdown
604 lines
16 KiB
Markdown
# UI 备份模块 - CLAUDE.md
|
|
|
|
此文件为 Claude Code 在 UI 备份模块工作时提供指导。
|
|
|
|
## 🎯 模块概览
|
|
|
|
UI 备份模块是主前端模块 (`frontend/`) 的备份和实验环境,用于保存稳定版本、测试新功能和组件开发。
|
|
|
|
### 模块用途
|
|
- 🔄 主前端代码的备份版本
|
|
- 🧪 新功能和组件的实验环境
|
|
- 📦 组件库的独立维护
|
|
- 🔧 A/B 测试和版本对比
|
|
- 🛠️ 紧急回滚的备用版本
|
|
|
|
### 技术栈
|
|
- **前端**: Next.js 15 + React 19 + TypeScript
|
|
- **组件**: shadcn/ui + Radix UI
|
|
- **样式**: Tailwind CSS
|
|
- **构建**: Next.js 内置构建系统
|
|
- **包管理**: pnpm (与主前端区分)
|
|
|
|
## 📁 目录结构
|
|
|
|
```
|
|
ui/
|
|
├── CLAUDE.md # 🔍 当前文件 - UI 备份模块指导
|
|
├── app/ # Next.js 应用目录
|
|
│ ├── globals.css # 全局样式
|
|
│ ├── layout.tsx # 根布局
|
|
│ └── page.tsx # 主页
|
|
├── components/ # 组件目录
|
|
│ ├── ui/ # shadcn/ui 组件
|
|
│ │ ├── button.tsx # 按钮组件
|
|
│ │ ├── card.tsx # 卡片组件
|
|
│ │ ├── dialog.tsx # 对话框组件
|
|
│ │ └── ... # 其他 UI 组件
|
|
│ ├── about-view.tsx # 关于页面组件
|
|
│ ├── contact-view.tsx # 联系页面组件
|
|
│ ├── filter-bar.tsx # 过滤栏组件
|
|
│ ├── loading-spinner.tsx # 加载组件
|
|
│ ├── navigation.tsx # 导航组件
|
|
│ ├── photo-gallery.tsx # 照片画廊组件
|
|
│ ├── photo-modal.tsx # 照片弹窗组件
|
|
│ ├── theme-provider.tsx # 主题提供器
|
|
│ ├── timeline-stats.tsx # 时间线统计
|
|
│ └── timeline-view.tsx # 时间线视图
|
|
├── hooks/ # 自定义 Hook
|
|
│ ├── use-mobile.tsx # 移动端检测
|
|
│ └── use-toast.ts # 提示信息
|
|
├── lib/ # 工具库
|
|
│ └── utils.ts # 工具函数
|
|
├── public/ # 静态资源
|
|
│ ├── placeholder-logo.png # 占位图标
|
|
│ ├── placeholder-user.jpg # 占位头像
|
|
│ └── placeholder.jpg # 占位图片
|
|
├── styles/ # 样式文件
|
|
│ └── globals.css # 全局样式
|
|
├── components.json # shadcn/ui 配置
|
|
├── next.config.mjs # Next.js 配置
|
|
├── package.json # 依赖配置
|
|
├── pnpm-lock.yaml # pnpm 锁文件
|
|
├── postcss.config.mjs # PostCSS 配置
|
|
├── tailwind.config.ts # Tailwind 配置
|
|
├── tsconfig.json # TypeScript 配置
|
|
└── README.md # 模块说明
|
|
```
|
|
|
|
## 🔄 与主前端的关系
|
|
|
|
### 同步策略
|
|
```bash
|
|
# 从主前端同步到 UI 备份
|
|
# 1. 同步核心组件
|
|
cp -r frontend/components/ui/* ui/components/ui/
|
|
|
|
# 2. 同步配置文件
|
|
cp frontend/tailwind.config.ts ui/
|
|
cp frontend/components.json ui/
|
|
|
|
# 3. 同步样式文件
|
|
cp frontend/app/globals.css ui/app/
|
|
cp frontend/styles/globals.css ui/styles/
|
|
|
|
# 4. 同步工具函数
|
|
cp frontend/lib/utils.ts ui/lib/
|
|
```
|
|
|
|
### 版本控制
|
|
```bash
|
|
# 创建备份分支
|
|
git checkout -b ui-backup-v1.0.0
|
|
|
|
# 标记稳定版本
|
|
git tag ui-v1.0.0
|
|
|
|
# 推送备份版本
|
|
git push origin ui-backup-v1.0.0
|
|
git push origin ui-v1.0.0
|
|
```
|
|
|
|
## 🧪 实验环境配置
|
|
|
|
### 开发环境设置
|
|
```bash
|
|
# 进入 UI 备份目录
|
|
cd ui/
|
|
|
|
# 安装依赖 (使用 pnpm)
|
|
pnpm install
|
|
|
|
# 启动开发服务器
|
|
pnpm dev
|
|
|
|
# 构建项目
|
|
pnpm build
|
|
|
|
# 启动生产预览
|
|
pnpm start
|
|
```
|
|
|
|
### 环境变量配置
|
|
```bash
|
|
# .env.local
|
|
NEXT_PUBLIC_API_URL=http://localhost:3001
|
|
NEXT_PUBLIC_MOCK_API=true
|
|
NEXT_PUBLIC_EXPERIMENTAL_FEATURES=true
|
|
```
|
|
|
|
### 实验性功能开关
|
|
```typescript
|
|
// lib/experimental.ts
|
|
export const experimentalFeatures = {
|
|
// 新组件测试
|
|
newPhotoGallery: process.env.NEXT_PUBLIC_EXPERIMENTAL_FEATURES === 'true',
|
|
|
|
// A/B 测试
|
|
alternativeNavigation: false,
|
|
|
|
// 性能优化
|
|
optimizedImages: true,
|
|
|
|
// 新主题
|
|
darkModeV2: false,
|
|
} as const
|
|
|
|
// 使用示例
|
|
import { experimentalFeatures } from '@/lib/experimental'
|
|
|
|
export default function PhotoGallery() {
|
|
if (experimentalFeatures.newPhotoGallery) {
|
|
return <NewPhotoGallery />
|
|
}
|
|
|
|
return <OriginalPhotoGallery />
|
|
}
|
|
```
|
|
|
|
## 🎨 组件库管理
|
|
|
|
### 组件分类
|
|
```
|
|
components/
|
|
├── ui/ # 基础 UI 组件
|
|
│ ├── button.tsx # 按钮 - 基础交互
|
|
│ ├── input.tsx # 输入框 - 表单控件
|
|
│ ├── card.tsx # 卡片 - 内容容器
|
|
│ ├── dialog.tsx # 对话框 - 模态框
|
|
│ ├── dropdown-menu.tsx # 下拉菜单 - 菜单控件
|
|
│ ├── navigation-menu.tsx # 导航菜单 - 导航控件
|
|
│ ├── tabs.tsx # 标签页 - 切换控件
|
|
│ ├── toast.tsx # 提示信息 - 反馈组件
|
|
│ └── ... # 其他基础组件
|
|
├── business/ # 业务组件
|
|
│ ├── photo-gallery.tsx # 照片画廊
|
|
│ ├── photo-modal.tsx # 照片弹窗
|
|
│ ├── timeline-view.tsx # 时间线视图
|
|
│ ├── filter-bar.tsx # 过滤栏
|
|
│ └── navigation.tsx # 站点导航
|
|
├── layout/ # 布局组件
|
|
│ ├── header.tsx # 页头
|
|
│ ├── footer.tsx # 页脚
|
|
│ └── sidebar.tsx # 侧边栏
|
|
└── experimental/ # 实验性组件
|
|
├── new-photo-gallery.tsx # 新照片画廊
|
|
├── advanced-filter.tsx # 高级过滤器
|
|
└── ai-search.tsx # AI 搜索
|
|
```
|
|
|
|
### 组件开发规范
|
|
```typescript
|
|
// components/experimental/new-photo-gallery.tsx
|
|
import { useState, useCallback } from 'react'
|
|
import { Card, CardContent } from '@/components/ui/card'
|
|
import { Button } from '@/components/ui/button'
|
|
|
|
interface Photo {
|
|
id: string
|
|
src: string
|
|
alt: string
|
|
title: string
|
|
description?: string
|
|
}
|
|
|
|
interface NewPhotoGalleryProps {
|
|
photos: Photo[]
|
|
onPhotoClick?: (photo: Photo) => void
|
|
className?: string
|
|
}
|
|
|
|
export function NewPhotoGallery({
|
|
photos,
|
|
onPhotoClick,
|
|
className
|
|
}: NewPhotoGalleryProps) {
|
|
const [selectedPhoto, setSelectedPhoto] = useState<Photo | null>(null)
|
|
|
|
const handlePhotoClick = useCallback((photo: Photo) => {
|
|
setSelectedPhoto(photo)
|
|
onPhotoClick?.(photo)
|
|
}, [onPhotoClick])
|
|
|
|
return (
|
|
<div className={`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ${className}`}>
|
|
{photos.map((photo) => (
|
|
<Card key={photo.id} className="overflow-hidden hover:shadow-lg transition-shadow">
|
|
<CardContent className="p-0">
|
|
<div
|
|
className="relative aspect-square cursor-pointer"
|
|
onClick={() => handlePhotoClick(photo)}
|
|
>
|
|
<img
|
|
src={photo.src}
|
|
alt={photo.alt}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
<div className="absolute inset-0 bg-black/0 hover:bg-black/20 transition-colors" />
|
|
</div>
|
|
{photo.title && (
|
|
<div className="p-3">
|
|
<h3 className="font-semibold text-sm">{photo.title}</h3>
|
|
{photo.description && (
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
{photo.description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
## 🔧 版本管理和同步
|
|
|
|
### 版本管理策略
|
|
```bash
|
|
# 1. 创建功能分支
|
|
git checkout -b feature/new-component
|
|
|
|
# 2. 开发和测试
|
|
# ... 组件开发 ...
|
|
|
|
# 3. 合并到 UI 备份主分支
|
|
git checkout main
|
|
git merge feature/new-component
|
|
|
|
# 4. 测试稳定后,同步到主前端
|
|
cp ui/components/experimental/new-component.tsx frontend/components/
|
|
```
|
|
|
|
### 自动同步脚本
|
|
```bash
|
|
#!/bin/bash
|
|
# scripts/sync-ui-to-frontend.sh
|
|
|
|
set -e
|
|
|
|
UI_DIR="ui"
|
|
FRONTEND_DIR="frontend"
|
|
|
|
echo "🔄 开始同步 UI 备份到主前端..."
|
|
|
|
# 同步基础组件
|
|
echo "📦 同步基础组件..."
|
|
rsync -av --exclude='experimental' $UI_DIR/components/ui/ $FRONTEND_DIR/components/ui/
|
|
|
|
# 同步配置文件
|
|
echo "⚙️ 同步配置文件..."
|
|
cp $UI_DIR/tailwind.config.ts $FRONTEND_DIR/
|
|
cp $UI_DIR/components.json $FRONTEND_DIR/
|
|
|
|
# 同步样式文件
|
|
echo "🎨 同步样式文件..."
|
|
cp $UI_DIR/app/globals.css $FRONTEND_DIR/app/
|
|
cp $UI_DIR/styles/globals.css $FRONTEND_DIR/styles/
|
|
|
|
# 同步工具函数
|
|
echo "🛠️ 同步工具函数..."
|
|
cp $UI_DIR/lib/utils.ts $FRONTEND_DIR/lib/
|
|
|
|
echo "✅ 同步完成!"
|
|
```
|
|
|
|
### 反向同步脚本
|
|
```bash
|
|
#!/bin/bash
|
|
# scripts/sync-frontend-to-ui.sh
|
|
|
|
set -e
|
|
|
|
FRONTEND_DIR="frontend"
|
|
UI_DIR="ui"
|
|
|
|
echo "🔄 开始同步主前端到 UI 备份..."
|
|
|
|
# 创建备份
|
|
echo "💾 创建备份..."
|
|
timestamp=$(date +%Y%m%d_%H%M%S)
|
|
cp -r $UI_DIR $UI_DIR.backup.$timestamp
|
|
|
|
# 同步核心文件
|
|
echo "📦 同步核心文件..."
|
|
rsync -av --exclude='experimental' --exclude='backup.*' $FRONTEND_DIR/ $UI_DIR/
|
|
|
|
# 保留实验性功能
|
|
echo "🧪 保留实验性功能..."
|
|
if [ -d "$UI_DIR.backup.$timestamp/components/experimental" ]; then
|
|
cp -r $UI_DIR.backup.$timestamp/components/experimental $UI_DIR/components/
|
|
fi
|
|
|
|
echo "✅ 同步完成!"
|
|
```
|
|
|
|
## 🧪 A/B 测试和实验
|
|
|
|
### A/B 测试框架
|
|
```typescript
|
|
// lib/ab-testing.ts
|
|
interface ABTest {
|
|
name: string
|
|
variants: {
|
|
control: React.ComponentType<any>
|
|
treatment: React.ComponentType<any>
|
|
}
|
|
percentage: number // 0-100
|
|
enabled: boolean
|
|
}
|
|
|
|
class ABTestManager {
|
|
private tests: Map<string, ABTest> = new Map()
|
|
|
|
registerTest(test: ABTest) {
|
|
this.tests.set(test.name, test)
|
|
}
|
|
|
|
getVariant(testName: string): 'control' | 'treatment' | null {
|
|
const test = this.tests.get(testName)
|
|
if (!test || !test.enabled) return null
|
|
|
|
// 基于用户 ID 或 session 的一致性分组
|
|
const hash = this.hashString(testName + this.getUserId())
|
|
const percentage = hash % 100
|
|
|
|
return percentage < test.percentage ? 'treatment' : 'control'
|
|
}
|
|
|
|
renderComponent(testName: string, props: any) {
|
|
const test = this.tests.get(testName)
|
|
if (!test) return null
|
|
|
|
const variant = this.getVariant(testName)
|
|
if (variant === 'treatment') {
|
|
return <test.variants.treatment {...props} />
|
|
}
|
|
return <test.variants.control {...props} />
|
|
}
|
|
|
|
private hashString(str: string): number {
|
|
let hash = 0
|
|
for (let i = 0; i < str.length; i++) {
|
|
const char = str.charCodeAt(i)
|
|
hash = ((hash << 5) - hash) + char
|
|
hash = hash & hash // Convert to 32-bit integer
|
|
}
|
|
return Math.abs(hash)
|
|
}
|
|
|
|
private getUserId(): string {
|
|
// 实现用户 ID 获取逻辑
|
|
return sessionStorage.getItem('userId') || 'anonymous'
|
|
}
|
|
}
|
|
|
|
export const abTestManager = new ABTestManager()
|
|
|
|
// 使用示例
|
|
abTestManager.registerTest({
|
|
name: 'photo-gallery-layout',
|
|
variants: {
|
|
control: OriginalPhotoGallery,
|
|
treatment: NewPhotoGallery
|
|
},
|
|
percentage: 50,
|
|
enabled: true
|
|
})
|
|
```
|
|
|
|
### 实验性功能管理
|
|
```typescript
|
|
// components/experimental/feature-flag.tsx
|
|
import { experimentalFeatures } from '@/lib/experimental'
|
|
|
|
interface FeatureFlagProps {
|
|
feature: keyof typeof experimentalFeatures
|
|
children: React.ReactNode
|
|
fallback?: React.ReactNode
|
|
}
|
|
|
|
export function FeatureFlag({ feature, children, fallback = null }: FeatureFlagProps) {
|
|
if (experimentalFeatures[feature]) {
|
|
return <>{children}</>
|
|
}
|
|
|
|
return <>{fallback}</>
|
|
}
|
|
|
|
// 使用示例
|
|
<FeatureFlag feature="newPhotoGallery" fallback={<OriginalPhotoGallery />}>
|
|
<NewPhotoGallery />
|
|
</FeatureFlag>
|
|
```
|
|
|
|
## 🚀 构建和部署
|
|
|
|
### 构建配置
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"dev": "next dev -p 3002",
|
|
"build": "next build",
|
|
"start": "next start -p 3002",
|
|
"lint": "next lint",
|
|
"type-check": "tsc --noEmit",
|
|
"export": "next build && next export",
|
|
"sync-from-frontend": "./scripts/sync-frontend-to-ui.sh",
|
|
"sync-to-frontend": "./scripts/sync-ui-to-frontend.sh"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Next.js 配置
|
|
```typescript
|
|
// next.config.mjs
|
|
/** @type {import('next').NextConfig} */
|
|
const nextConfig = {
|
|
// 输出静态文件
|
|
output: 'export',
|
|
|
|
// 基础路径 (用于部署到子路径)
|
|
basePath: '/ui',
|
|
|
|
// 禁用图片优化 (静态导出)
|
|
images: {
|
|
unoptimized: true
|
|
},
|
|
|
|
// 实验性功能
|
|
experimental: {
|
|
appDir: true,
|
|
serverComponentsExternalPackages: []
|
|
},
|
|
|
|
// 环境变量
|
|
env: {
|
|
NEXT_PUBLIC_UI_VERSION: process.env.npm_package_version || '1.0.0'
|
|
}
|
|
}
|
|
|
|
export default nextConfig
|
|
```
|
|
|
|
### 部署配置
|
|
```bash
|
|
# 构建并部署到 UI 预览环境
|
|
npm run build
|
|
npm run export
|
|
|
|
# 部署到独立的 UI 预览域名
|
|
rsync -av out/ user@server:/var/www/ui-preview/
|
|
```
|
|
|
|
## 🔄 与其他模块的集成
|
|
|
|
### 与主前端的协作
|
|
- 新功能在 UI 备份中实验和测试
|
|
- 稳定后同步到主前端
|
|
- 主前端的 bug 修复反向同步到 UI 备份
|
|
|
|
### 与管理后台的关系
|
|
- 共享基础组件库
|
|
- 管理后台可以复用 UI 备份中的组件
|
|
- 保持设计系统的一致性
|
|
|
|
### 与后端的集成
|
|
- 使用相同的 API 接口
|
|
- 支持 Mock API 进行独立开发
|
|
- 与后端版本保持兼容
|
|
|
|
## 🐛 问题排查
|
|
|
|
### 常见问题
|
|
1. **组件不同步**: 检查同步脚本和版本控制
|
|
2. **样式冲突**: 检查 Tailwind 配置和全局样式
|
|
3. **依赖版本不一致**: 检查 package.json 和锁文件
|
|
4. **构建失败**: 检查 TypeScript 配置和依赖
|
|
|
|
### 调试技巧
|
|
```bash
|
|
# 比较两个版本的差异
|
|
diff -r frontend/components ui/components
|
|
|
|
# 检查依赖差异
|
|
diff frontend/package.json ui/package.json
|
|
|
|
# 清理缓存
|
|
rm -rf ui/.next ui/node_modules
|
|
cd ui && pnpm install
|
|
```
|
|
|
|
## 📊 监控和分析
|
|
|
|
### 性能监控
|
|
```typescript
|
|
// lib/performance.ts
|
|
export function measurePerformance(name: string, fn: () => void) {
|
|
const start = performance.now()
|
|
fn()
|
|
const end = performance.now()
|
|
|
|
console.log(`${name} took ${end - start} milliseconds`)
|
|
|
|
// 发送到分析服务
|
|
if (typeof window !== 'undefined' && (window as any).gtag) {
|
|
(window as any).gtag('event', 'timing_complete', {
|
|
name: name,
|
|
value: Math.round(end - start)
|
|
})
|
|
}
|
|
}
|
|
```
|
|
|
|
### 实验数据收集
|
|
```typescript
|
|
// lib/analytics.ts
|
|
export function trackExperiment(testName: string, variant: string) {
|
|
if (typeof window !== 'undefined' && (window as any).gtag) {
|
|
(window as any).gtag('event', 'experiment_view', {
|
|
experiment_id: testName,
|
|
variant_id: variant
|
|
})
|
|
}
|
|
}
|
|
|
|
export function trackConversion(testName: string, variant: string, action: string) {
|
|
if (typeof window !== 'undefined' && (window as any).gtag) {
|
|
(window as any).gtag('event', 'experiment_conversion', {
|
|
experiment_id: testName,
|
|
variant_id: variant,
|
|
action: action
|
|
})
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🔮 未来规划
|
|
|
|
### 功能扩展
|
|
- 🔧 可视化组件编辑器
|
|
- 📊 实验结果分析面板
|
|
- 🎨 设计系统自动化
|
|
- 🤖 AI 辅助组件生成
|
|
- 📱 响应式设计测试工具
|
|
|
|
### 工作流优化
|
|
- 自动化同步流程
|
|
- 持续集成测试
|
|
- 可视化差异对比
|
|
- 自动化 A/B 测试报告
|
|
|
|
## 📚 参考资料
|
|
|
|
- [Next.js 文档](https://nextjs.org/docs)
|
|
- [React 19 新特性](https://react.dev/blog/2024/04/25/react-19)
|
|
- [shadcn/ui 文档](https://ui.shadcn.com/)
|
|
- [Tailwind CSS 文档](https://tailwindcss.com/docs)
|
|
- [A/B 测试最佳实践](https://www.optimizely.com/optimization-glossary/ab-testing/)
|
|
|
|
---
|
|
|
|
💡 **使用提示**: UI 备份模块主要用于实验和备份,不建议在生产环境中直接使用。所有稳定的功能都应该同步到主前端模块。在进行实验时,请确保做好数据备份,避免影响主前端的稳定性。 |