Files
vf_react/CLAUDE.md
2025-11-22 15:34:18 +08:00

1559 lines
49 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
> **🌐 语言偏好**: 请始终使用中文与用户交流,包括所有解释、分析、文档编写和代码注释。
本文件为 Claude Code (claude.ai/code) 提供在此代码库中工作的指导说明。
## 📖 文档结构导航
本文档分为以下主要章节,建议按需查阅:
**基础信息**:
- [项目概览](#项目概览) - 技术栈、项目定位
- [开发命令](#开发命令) - 常用命令速查
- [配置](#配置) - 环境变量、MSW、路径别名、Webpack
**架构设计**:
- [架构](#架构) - 应用入口流程、路由架构
- [前端目录结构详解](#前端目录结构详解) - 完整的目录说明与使用指南
- [后端架构详解](#后端架构详解) - Flask、Celery、数据库架构
**开发指南**:
- [开发工作流](#开发工作流) - 路由、组件、API、Redux 开发指南
- [TypeScript 接入](#typescript-接入) - TypeScript 渐进式迁移方案与指南
- [常见开发任务](#常见开发任务) - 5 个详细的开发任务教程
- [技术路径与开发指南](#技术路径与开发指南) - UI 框架选型、技术栈演进、最佳实践
**技术决策与规范**:
- [UI 框架选型与使用指南](#ui-框架选型与使用指南) - Ant Design + Chakra UI 混合策略
- [架构设计原则](#架构设计原则) - 组件设计、状态管理、代码分割、API 层
- [开发规范与最佳实践](#开发规范与最佳实践) - 命名规范、Git 工作流、代码审查
**技术债务与维护**:
- [技术债务与已知问题](#技术债务与已知问题) - 技术债务跟踪、优化机会
- [更新本文档](#更新本文档) - 文档维护指南
---
## 项目概览
混合式 React 仪表板,用于金融/交易分析,采用 Flask 后端。基于 Argon Dashboard Chakra PRO 模板构建。
### 技术栈
**前端**
- **核心框架**: React 18.3.1
- **类型系统**: TypeScript 5.9.3(渐进式接入中,支持 JS/TS 混合开发)
- **UI 组件库**: Chakra UI 2.10.9(主要) + Ant Design 5.27.4(表格/表单)
- **状态管理**: Redux Toolkit 2.9.2
- **路由**: React Router v6.30.1 配合 React.lazy() 实现代码分割
- **构建系统**: CRACO 7.1.0 + 激进的 webpack 5 优化
- **图表库**: ECharts 5.6.0、ApexCharts 3.27.3、Recharts 3.1.2、D3 7.9.0、Visx 3.12.0
- **动画**: Framer Motion 4.1.17
- **日历**: FullCalendar 5.9.0、React Big Calendar 0.33.2
- **图标**: Lucide React 0.540.0推荐、React Icons 4.12.0、@ant-design/icons 6.0.0
- **网络请求**: Axios 1.10.0
- **实时通信**: Socket.IO Client 4.7.4
- **数据分析**: PostHog 1.281.0
- **开发工具**: MSW (Mock Service Worker) 用于 API mocking
- **虚拟化**: @tanstack/react-virtual 3.13.12(性能优化)
- **其他**: Draft.js富文本编辑、React Markdown、React Quill
- Use HeroUI v3 documentation from https://v3.heroui.com/llms.txt
**后端**
- Flask + SQLAlchemy ORM
- ClickHouse分析型数据库+ MySQL/PostgreSQL事务型数据库
- Flask-SocketIO 实现 WebSocket 实时更新
- Celery + Redis 处理后台任务
- 腾讯云短信 + 微信支付集成
## 开发命令
### 前端开发
```bash
npm start # 使用 mock 数据启动(.env.mock代理到 localhost:5001
npm run start:real # 使用真实后端启动(.env.local
npm run start:dev # 使用开发配置启动(.env.development
npm run start:test # 同时启动后端app.py和前端.env.test
npm run dev # 'npm start' 的别名
npm run backend # 仅启动 Flask 服务器python app.py
npm run build # 生产环境构建,包含 Gulp 许可证头
npm run build:analyze # 使用 webpack bundle analyzer 构建
npm test # 运行 React 测试套件CRACO
npm run lint:check # 检查 ESLint 规则(退出码 0
npm run lint:fix # 自动修复 ESLint 问题
npm run type-check # TypeScript 类型检查(不生成输出)
npm run type-check:watch # TypeScript 类型检查监听模式
npm run clean # 删除 node_modules 和 package-lock.json
npm run reinstall # 清洁安装(运行 clean + install
```
### 后端开发
```bash
python app.py # 主 Flask 服务器
python simulation_background_processor.py # 交易模拟的后台任务处理器
pip install -r requirements.txt # 安装 Python 依赖
```
### 部署
```bash
npm run deploy # 从本地部署scripts/deploy-from-local.sh
npm run rollback # 回滚到上一个版本
```
## 架构
### 应用入口流程
```
src/index.js
└── src/App.js根组件
├── AppProviders (src/providers/AppProviders.js)
│ ├── ReduxProviderstore 来自 src/store/
│ ├── ChakraProvider主题来自 src/theme/
│ ├── NotificationProvider (src/contexts/NotificationContext.js)
│ └── AuthProvider (src/contexts/AuthContext.js)
├── AppRoutes (src/routes/index.js)
│ ├── MainLayout 路由(带导航栏/页脚)
│ └── 独立路由(认证页面、全屏视图)
└── GlobalComponents模态框覆盖层、全局 UI
```
### 路由架构(模块化设计)
路由采用**声明式**设计,并拆分到 `src/routes/` 中的多个文件:
- **index.js** - 主路由器(组合配置 + 渲染路由)
- **routeConfig.js** - 路由定义(路径、组件、保护模式、布局、子路由)
- **lazy-components.js** - React.lazy() 导入,用于代码分割
- **homeRoutes.js** - 嵌套的首页路由
- **constants/** - 保护模式、布局映射
- **utils/** - 路由渲染逻辑wrapWithProtection、renderRoute
路由保护模式PROTECTION_MODES
- `PUBLIC` - 无需认证
- `MODAL` - 未登录时显示认证模态框
- `REDIRECT` - 未登录时重定向到 /auth/sign-in
### 前端目录结构详解
本项目采用**功能驱动的目录结构**,按职责将代码组织到不同目录中。以下是完整的目录结构及详细说明:
#### 核心目录概览
```
src/
├── index.js # 应用入口文件
├── App.js # 根组件(组合 Providers + Routes
├── providers/ # Provider 组合层
├── routes/ # 路由配置与管理
├── layouts/ # 页面布局模板
├── views/ # 页面级组件
├── components/ # 可复用 UI 组件
├── contexts/ # React Context 状态管理
├── store/ # Redux 全局状态管理
├── hooks/ # 自定义 React Hooks
├── services/ # API 服务层
├── utils/ # 工具函数库
├── constants/ # 全局常量定义
├── theme/ # UI 主题配置
├── assets/ # 静态资源
├── styles/ # 全局样式
├── mocks/ # 开发环境 Mock 数据
├── lib/ # 第三方库配置
└── variables/ # 可配置变量
```
---
#### 详细目录说明
##### 📁 `src/providers/` - Provider 组合层
**用途**: 集中管理应用的所有 Context Providers避免在 App.js 中嵌套过深。
**核心文件**:
- `AppProviders.js` - 所有 Provider 的组合容器
**Provider 嵌套顺序**(从外到内):
```javascript
ReduxProvider // 1. Redux 状态管理(最外层)
└─ ChakraProvider // 2. Chakra UI 主题系统
└─ ConfigProvider // 3. Ant Design 主题配置
└─ NotificationProvider // 4. 通知系统
└─ AuthProvider // 5. 认证系统(最内层)
```
**何时修改**:
- 添加新的全局 Provider如 i18n、Analytics
- 调整 Provider 顺序(注意依赖关系)
---
##### 📁 `src/routes/` - 路由系统
**用途**: 模块化路由配置,采用声明式设计,支持懒加载和路由保护。
**核心文件**:
- `index.js` - 主路由器(渲染所有路由)
- `routeConfig.js` - **路由配置中心**(所有路由定义)
- `lazy-components.js` - React.lazy() 懒加载组件导入
- `homeRoutes.js` - 首页嵌套路由
- `constants/protectionModes.js` - 路由保护模式定义
- `utils/wrapWithProtection.js` - 路由保护逻辑
- `utils/renderRoute.js` - 路由渲染工具
**路由保护模式**:
- `PUBLIC` - 公开访问,无需登录
- `MODAL` - 未登录时显示登录模态框(不跳转)
- `REDIRECT` - 未登录时重定向到 /auth/sign-in
**添加新路由的步骤**: 参见"常见开发任务 → 如何添加新的页面路由"
**命名约定**:
- 路由路径使用 kebab-case: `portfolio`, `trading-simulation`
- 组件名使用 PascalCase: `Portfolio`, `TradingSimulation`
---
##### 📁 `src/layouts/` - 页面布局
**用途**: 定义页面的通用布局结构(导航栏、侧边栏、页脚等),复用于多个页面。
**核心文件**:
- `MainLayout.js` - 主布局(带顶部导航栏 + 侧边栏 + 页脚)
- `Auth.js` - 认证页面布局(无导航栏,纯净背景)
**布局特性**:
- 每个布局包含独立的 ErrorBoundary错误隔离
- 通过 `<Outlet />` 渲染子路由内容
- 布局内可访问认证状态AuthContext
**何时创建新布局**:
- 需要完全不同的页面结构(如打印页、全屏图表)
- 特定页面需要自定义导航栏/侧边栏
---
##### 📁 `src/views/` - 页面级组件
**用途**: 存放路由对应的页面组件,每个文件对应一个路由页面。
**组织结构**:
```
views/
├── Community/ # 社区页面(大型功能模块)
│ ├── index.js # 页面入口
│ ├── components/ # 页面专属组件
│ │ ├── EventList/
│ │ ├── EventCard/
│ │ └── StockDetailPanel/
│ ├── hooks/ # 页面专属 Hooks
│ │ └── useCommunityData.js
│ └── utils/ # 页面专属工具函数
├── TradingSimulation/ # 交易模拟页面
│ ├── index.js
│ ├── components/
│ └── ...
├── Dashboard/ # 仪表板页面
│ └── index.js
└── Portfolio/ # 投资组合页面(简单页面)
└── index.js
```
**命名约定**:
- 目录名使用 PascalCase: `Community`, `TradingSimulation`
- 主文件始终为 `index.js`(方便导入)
**原则**:
- 页面组件主要负责**数据获取和布局组合**,不应包含复杂的 UI 逻辑
- 复杂 UI 逻辑应拆分到 `components/` 子目录
- 页面超过 500 行时考虑拆分(参见"组件组织模式"
---
##### 📁 `src/components/` - 可复用 UI 组件
**用途**: 存放跨页面复用的通用 UI 组件(按钮、卡片、表格、模态框等)。
**组织结构**(推荐采用原子设计模式):
```
components/
├── Atoms/ # 原子组件1-50 行)
│ ├── Button/
│ ├── Badge/
│ └── Icon/
├── Molecules/ # 分子组件50-150 行)
│ ├── Card/
│ ├── StatCard/
│ └── SearchBar/
├── Organisms/ # 有机体组件150-500 行)
│ ├── Navbar/
│ ├── Sidebar/
│ ├── DataTable/
│ └── FilterPanel/
└── Templates/ # 模板组件(可选)
└── PageTemplate/
```
**何时添加新组件**:
- 组件在 2+ 个页面中使用
- 组件具有明确的职责和边界
- 组件可独立测试
**命名约定**:
- 组件目录使用 PascalCase: `EventCard`, `StockTable`
- 每个组件目录包含:
- `index.js` - 主导出文件
- `ComponentName.js` - 实现代码(可选,简单组件直接在 index.js
- `ComponentName.test.js` - 测试文件(可选)
**避免**:
- 将页面特定组件放在这里(应放在 `views/{PageName}/components/`
- 过度拆分(不要为了拆分而拆分)
---
##### 📁 `src/contexts/` - React Context 状态管理
**用途**: 存放使用 React Context API 管理的跨组件状态。
**核心 Contexts**:
- `AuthContext.js` - 认证状态(用户信息、登录状态、登录/登出方法)
- `NotificationContext.js` - 通知系统(显示 Toast/Alert
- `SidebarContext.js` - 侧边栏状态(展开/收起)
**何时使用 Context**:
- 跨层级传递数据(避免 props drilling
- 不频繁变化的数据(主题、语言、认证状态)
- 依赖注入场景
**何时不使用 Context**:
- 频繁变化的数据 → 使用 Redux
- 服务端数据 → 使用 React Query计划中
- 本地 UI 状态 → 使用 useState
**Context 文件结构**:
```javascript
// AuthContext.js
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
// ...
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext); // 自定义 Hook
```
---
##### 📁 `src/store/` - Redux 全局状态管理
**用途**: 使用 Redux Toolkit 管理全局状态UI 状态、跨页面共享数据)。
**目录结构**:
```
store/
├── index.js # Store 配置combineReducers
└── slices/ # Redux Slices
├── authModalSlice.js # 认证模态框状态
├── posthogSlice.js # PostHog 分析配置
├── stockSlice.js # 股票数据
├── industrySlice.js # 行业/概念数据
├── subscriptionSlice.js # 用户订阅状态
└── communityDataSlice.js # 社区数据
```
**何时使用 Redux**:
- 全局 UI 状态(模态框开关、侧边栏状态)
- 需要在多个不相关组件间共享的数据
- 需要持久化的状态(与 redux-persist 结合)
- 需要中间件处理的复杂逻辑
**Slice 命名约定**:
- 文件名: `{feature}Slice.js` (如 `authModalSlice.js`)
- Slice 名称: `{feature}` (如 `name: 'authModal'`)
- Actions: 动词开头 (如 `openModal`, `closeModal`, `setUser`)
**添加新 Slice**: 参见"常见开发任务 → 如何添加新的 Redux Slice"
---
##### 📁 `src/hooks/` - 自定义 React Hooks
**用途**: 存放可复用的自定义 Hooks封装常见逻辑模式。
**Hook 类型示例**:
```
hooks/
├── useAuth.js # 认证相关(实际导出自 AuthContext
├── useStockData.js # 数据获取 Hook
├── useDebounce.js # 防抖 Hook
├── useIntersectionObserver.js # 懒加载/无限滚动
├── useLocalStorage.js # 本地存储持久化
├── useMediaQuery.js # 响应式查询
└── usePrevious.js # 获取前一个值
```
**命名约定**:
- 文件名: `use{PascalCase}.js` (如 `useStockData.js`)
- 必须以 `use` 开头React Hooks 规则)
- 一个文件导出一个 Hook
**Hook 设计原则**:
- 职责单一(只做一件事)
- 返回对象或数组(不返回原始值)
- 包含完整的状态管理loading, error, data
**何时创建新 Hook**:
- 逻辑在 2+ 个组件中重复
- 组件逻辑可以独立测试
- 需要封装浏览器 APIlocalStorage, IntersectionObserver
---
##### 📁 `src/services/` - API 服务层
**用途**: 封装所有后端 API 调用,提供统一的接口供组件调用。
**组织结构**(按业务领域划分):
```
services/
├── authService.js # 认证相关 API登录、注册、登出
├── stockService.js # 股票数据 API
├── portfolioService.js # 投资组合 API
├── communityService.js # 社区内容 API
├── tradingService.js # 交易模拟 API
└── userService.js # 用户信息 API
```
**服务函数命名约定**:
- `fetch{Entity}` - 获取数据 (如 `fetchStockData`)
- `create{Entity}` - 创建记录 (如 `createOrder`)
- `update{Entity}` - 更新记录 (如 `updateProfile`)
- `delete{Entity}` - 删除记录 (如 `deletePost`)
**标准 API 调用结构**:
```javascript
// stockService.js
import axios from 'axios';
import { getApiBase } from '@utils/apiConfig';
const api = axios.create({
baseURL: getApiBase(),
timeout: 10000,
});
export const fetchStockData = async (stockCode) => {
try {
const response = await api.get(`/api/stocks/${stockCode}`);
return response.data;
} catch (error) {
console.error('fetchStockData error:', error);
throw error;
}
};
```
**原则**:
- 组件不应直接调用 axios通过 service 层)
- 每个 service 函数应包含错误处理
- 使用 `getApiBase()` 获取 API 基础 URL支持 Mock 模式)
---
##### 📁 `src/utils/` - 工具函数库
**用途**: 存放纯函数工具、格式化工具、计算逻辑等不依赖 React 的通用代码。
**核心工具文件**:
```
utils/
├── apiConfig.js # API 配置getApiBase, isMockMode
├── priceFormatters.js # 价格/数字格式化函数
├── dateFormatters.js # 日期格式化函数
├── logger.js # 统一日志工具
├── validators.js # 表单验证函数
├── calculations.js # 金融计算函数
└── string.js # 字符串处理函数
```
**命名约定**:
- 文件名: `camelCase.js` (如 `priceFormatters.js`)
- 函数名: `camelCase` (如 `formatPrice`, `calculateProfit`)
- 导出方式: 命名导出 (如 `export const formatPrice = ...`)
**工具函数特点**:
- **纯函数**: 相同输入始终返回相同输出,无副作用
- **可测试**: 易于编写单元测试
- **可复用**: 多处使用的逻辑
**示例**:
```javascript
// priceFormatters.js
export const formatPrice = (price, currency = '¥') => {
return `${currency}${price.toFixed(2)}`;
};
export const formatPercent = (value, decimals = 2) => {
return `${(value * 100).toFixed(decimals)}%`;
};
```
---
##### 📁 `src/constants/` - 全局常量定义
**用途**: 存放全局常量、枚举值、配置对象等不可变数据。
**常见常量文件**:
```
constants/
├── animations.js # 动画配置duration、easing
├── routes.js # 路由路径常量
├── apiEndpoints.js # API 端点常量
├── colors.js # 颜色常量(补充主题)
├── tradingConfig.js # 交易相关配置
└── errorMessages.js # 错误消息常量
```
**命名约定**:
- 常量名使用 SCREAMING_SNAKE_CASE: `API_BASE_URL`, `MAX_RETRY_COUNT`
- 配置对象使用 camelCase: `animationConfig`, `chartColors`
**示例**:
```javascript
// animations.js
export const ANIMATION_DURATION = {
FAST: 150,
NORMAL: 300,
SLOW: 500,
};
export const EASING = {
EASE_IN_OUT: 'cubic-bezier(0.4, 0, 0.2, 1)',
EASE_OUT: 'cubic-bezier(0, 0, 0.2, 1)',
};
```
**原则**:
- 避免魔法数字/字符串(在代码中硬编码)
- 方便统一修改(单一数据源)
- 提高代码可读性
---
##### 📁 `src/theme/` - UI 主题配置
**用途**: 定义 Chakra UI 主题配置(颜色、字体、间距、组件样式等)。
**核心文件**:
```
theme/
├── theme.js # 主题主文件(导出完整主题)
├── foundations/ # 基础样式(颜色、字体、间距)
│ ├── colors.js
│ ├── typography.js
│ └── spacing.js
└── components/ # 组件级主题覆盖
├── button.js
├── card.js
└── modal.js
```
**主题配置示例**:
```javascript
// theme.js
import { extendTheme } from '@chakra-ui/react';
import { colors } from './foundations/colors';
import { ButtonStyles as Button } from './components/button';
const theme = extendTheme({
colors,
fonts: {
heading: `'Open Sans', sans-serif`,
body: `'Raleway', sans-serif`,
},
components: {
Button,
},
});
export default theme;
```
**何时修改主题**:
- 添加自定义颜色/渐变
- 统一修改所有 Button/Card 的默认样式
- 配置深色模式
---
##### 📁 `src/assets/` - 静态资源
**用途**: 存放图片、字体、图标等静态文件。
**组织结构**:
```
assets/
├── img/ # 图片资源
│ ├── logo.png
│ ├── backgrounds/
│ └── illustrations/
├── icons/ # SVG 图标
└── fonts/ # 自定义字体文件(如需要)
```
**使用方式**:
```javascript
import logo from '@assets/img/logo.png';
<img src={logo} alt="Logo" />
```
---
##### 📁 `src/mocks/` - 开发环境 Mock 数据
**用途**: 使用 MSW (Mock Service Worker) 拦截 API 请求,返回 mock 数据,实现前后端分离开发。
**目录结构**:
```
mocks/
├── browser.js # MSW 初始化(浏览器环境)
├── handlers/ # API Mock Handlers按领域划分
│ ├── index.js # 汇总所有 handlers
│ ├── auth.js # 认证相关 API mock
│ ├── stock.js # 股票数据 API mock
│ ├── portfolio.js # 投资组合 API mock
│ └── community.js # 社区内容 API mock
└── data/ # Mock 数据文件
├── stocks.json
├── users.json
└── events.json
```
**启用 Mock 模式**:
```bash
# 方式 1: 使用 .env.mock 配置(默认)
npm start
# 方式 2: 手动设置环境变量
REACT_APP_ENABLE_MOCK=true npm start
```
**添加新 Mock Handler**: 参见"常见开发任务 → 如何添加新的 MSW Mock Handler"
**原则**:
- Mock 数据应尽量模拟真实数据结构
- 使用 MSW 的 `http.get/post/put/delete` 定义 handlers
- Handler 中可模拟延迟、错误响应(测试加载/错误状态)
---
##### 📁 其他目录
**`src/lib/`** - 第三方库配置
- 存放第三方库的自定义配置(如 PostHog、Analytics
**`src/styles/`** - 全局样式
- 存放全局 CSS/SCSS 文件(如 reset.css、global.scss
**`src/variables/`** - 可配置变量
- 存放可通过环境变量覆盖的配置(如 API URLs、Feature Flags
---
#### 目录结构最佳实践
**1. 就近原则Co-location**
- 将相关文件放在一起(组件、样式、测试、工具函数)
- 示例: `EventCard/` 目录包含 `EventCard.js``EventCard.test.js``utils.js`
**2. 单一职责**
- 每个目录只负责一个领域(不要混合业务逻辑和 UI 组件)
- 示例: `services/` 只包含 API 调用,不包含 UI 组件
**3. 避免深层嵌套**
- 目录层级不超过 4 层(超过则考虑重构)
- 示例: `src/views/Community/components/EventCard/` 已经是 4 层
**4. 命名一致性**
- 组件: PascalCase (`EventCard`)
- 文件: camelCase (`priceFormatters.js`)
- 常量: SCREAMING_SNAKE_CASE (`API_BASE_URL`)
**5. 导出规范**
- 每个目录包含 `index.js` 作为主导出文件
- 使用命名导出 (`export const ...`) 而非默认导出(除组件外)
---
#### 查找文件指南
**如何快速找到想要修改的文件?**
| 需求 | 目录 | 示例 |
|------|------|------|
| 修改页面布局 | `src/layouts/` | `MainLayout.js` |
| 修改某个页面 | `src/views/{PageName}/` | `Community/index.js` |
| 修改可复用组件 | `src/components/` | `DataTable/index.js` |
| 修改 API 调用 | `src/services/` | `stockService.js` |
| 修改工具函数 | `src/utils/` | `priceFormatters.js` |
| 修改全局状态 | `src/store/slices/` | `stockSlice.js` |
| 添加新路由 | `src/routes/routeConfig.js` | - |
| 修改主题颜色 | `src/theme/foundations/colors.js` | - |
| 添加 Mock API | `src/mocks/handlers/` | `stock.js` |
**使用路径别名快速导入**:
```javascript
// ✅ 使用别名(推荐)
import { EventCard } from '@components/EventCard';
import { formatPrice } from '@utils/priceFormatters';
import { fetchStockData } from '@services/stockService';
// ❌ 使用相对路径(不推荐)
import { EventCard } from '../../../components/EventCard';
import { formatPrice } from '../../utils/priceFormatters';
```
### 后端架构详解
本项目后端采用 **Flask 微服务架构**,结合多种数据库和消息队列,实现高性能金融数据处理和实时通信。
#### 后端目录结构
```
项目根目录/
├── app.py # 主 Flask 应用Web 服务器 + API 路由)
├── simulation_background_processor.py # Celery 后台处理器(交易模拟任务)
├── concept_api.py # 概念/行业分析独立 API 服务
├── wechat_pay.py # 微信支付业务逻辑
├── wechat_pay_config.py # 微信支付配置(商户号、密钥等)
├── tdays.csv # 交易日历数据A 股交易日)
├── requirements.txt # Python 依赖包清单
├── models/ # 数据库模型定义SQLAlchemy
│ ├── user.py
│ ├── stock.py
│ └── transaction.py
├── services/ # 业务逻辑服务层
│ ├── stock_service.py
│ ├── trading_service.py
│ └── notification_service.py
├── utils/ # 后端工具函数
│ ├── db_utils.py # 数据库连接工具
│ ├── clickhouse_client.py # ClickHouse 客户端封装
│ └── date_utils.py # 日期处理工具
└── config/ # 配置文件
├── development.py
├── production.py
└── test.py
```
---
#### 核心组件详解
##### 1⃣ `app.py` - 主 Flask 应用
**职责**: Web 服务器、API 路由、认证、会话管理、WebSocket 通信
**核心功能**:
- **Flask 应用初始化**: 配置 CORS、Session、Logging
- **API 路由定义**: RESTful API 端点(`/api/stocks`, `/api/portfolio`, `/api/community`
- **认证系统**: Flask-Login 集成(登录、登出、权限校验)
- **WebSocket 服务**: Flask-SocketIO 实现实时推送(股票行情、事件通知)
- **数据库连接**: SQLAlchemy ORM + ClickHouse Client
- **交易日历加载**: 启动时从 `tdays.csv` 加载 A 股交易日数据到全局变量
**技术栈**:
- **Flask** - 轻量级 Web 框架
- **Flask-Login** - 用户会话管理
- **Flask-SocketIO** - WebSocket 实时通信
- **Flask-CORS** - 跨域资源共享配置
- **SQLAlchemy** - ORM对象关系映射
**API 路由示例**:
```python
# 获取股票数据
@app.route('/api/stocks/<stock_code>', methods=['GET'])
@login_required
def get_stock_data(stock_code):
# 从 ClickHouse 查询历史数据
data = clickhouse_client.query(f"SELECT * FROM stocks WHERE code = '{stock_code}'")
return jsonify(data)
# 创建交易订单
@app.route('/api/orders', methods=['POST'])
@login_required
def create_order():
data = request.json
order = Order(user_id=current_user.id, stock_code=data['stock_code'], ...)
db.session.add(order)
db.session.commit()
return jsonify({'order_id': order.id})
```
**WebSocket 事件示例**:
```python
# 客户端订阅股票行情
@socketio.on('subscribe_stock')
def handle_subscribe(data):
stock_code = data['stock_code']
join_room(f'stock_{stock_code}')
emit('subscribed', {'stock_code': stock_code})
# 服务端推送行情更新
def push_quote_update(stock_code, quote_data):
socketio.emit('stock_quote', quote_data, room=f'stock_{stock_code}')
```
**交易日历加载**:
```python
# 全局变量存储交易日
trading_days = []
# 启动时加载 tdays.csv
def load_trading_days():
global trading_days
with open('tdays.csv', 'r') as f:
trading_days = [line.strip() for line in f.readlines()]
# 判断是否为交易日
def is_trading_day(date_str):
return date_str in trading_days
```
---
##### 2⃣ `simulation_background_processor.py` - Celery 后台处理器
**职责**: 处理长时间运行的后台任务(交易模拟、报表生成、数据同步)
**为什么需要后台处理器?**
- 交易模拟需要执行数百次历史回测计算(耗时 10-60 秒)
- 避免阻塞 Flask 主线程(影响其他 API 响应)
- 支持任务队列、重试、失败处理
**技术栈**:
- **Celery** - 分布式任务队列
- **Redis** - 消息代理Broker和结果存储Backend
- **ClickHouse** - 高性能查询历史股票数据
**任务示例**:
```python
from celery import Celery
# Celery 实例
celery_app = Celery('tasks', broker='redis://localhost:6379/0')
# 交易模拟任务
@celery_app.task(bind=True)
def run_simulation(self, user_id, strategy_config):
"""
执行交易模拟任务
:param user_id: 用户 ID
:param strategy_config: 策略配置(买入条件、卖出条件、资金管理)
:return: 模拟结果(收益率、最大回撤、交易明细)
"""
try:
# 1. 从 ClickHouse 获取历史数据
stock_data = clickhouse_client.query(...)
# 2. 执行回测计算
for i in range(len(stock_data)):
# 模拟交易逻辑
if should_buy(stock_data[i]):
buy(stock_data[i])
if should_sell(stock_data[i]):
sell(stock_data[i])
# 3. 计算绩效指标
result = {
'total_return': calculate_return(),
'max_drawdown': calculate_drawdown(),
'trades': get_trade_history(),
}
# 4. 保存结果到 MySQL
save_simulation_result(user_id, result)
return result
except Exception as e:
# 失败重试(最多 3 次)
self.retry(exc=e, countdown=60, max_retries=3)
```
**从 Flask 调用 Celery 任务**:
```python
# app.py
@app.route('/api/simulations', methods=['POST'])
@login_required
def start_simulation():
strategy = request.json
# 异步提交任务到 Celery
task = run_simulation.delay(current_user.id, strategy)
return jsonify({
'task_id': task.id,
'status': 'pending',
'message': '模拟任务已提交,请稍后查看结果'
})
# 查询任务状态
@app.route('/api/simulations/<task_id>', methods=['GET'])
def get_simulation_status(task_id):
task = run_simulation.AsyncResult(task_id)
if task.state == 'PENDING':
response = {'status': 'pending', 'progress': 0}
elif task.state == 'SUCCESS':
response = {'status': 'completed', 'result': task.result}
elif task.state == 'FAILURE':
response = {'status': 'failed', 'error': str(task.info)}
return jsonify(response)
```
**启动 Celery Worker**:
```bash
# 启动 worker监听任务队列
celery -A simulation_background_processor worker --loglevel=info
# 启动 FlowerCelery 监控工具)
celery -A simulation_background_processor flower
```
---
##### 3⃣ `concept_api.py` - 概念/行业分析 API
**职责**: 独立的概念板块分析服务(涨停分析、热点行业、资金流向)
**为什么独立部署?**
- 概念分析计算密集(需要遍历数千只股票)
- 独立扩展性(可部署到多台服务器)
- 服务隔离(不影响主应用性能)
**部署架构**:
```
前端请求 → Nginx 反向代理
├─ /api → Flask 主应用 (端口 5001)
└─ /concept-api → Concept API (端口 6801)
```
**API 示例**:
```python
from flask import Flask, jsonify
import clickhouse_driver
app = Flask(__name__)
# 获取涨停股票列表
@app.route('/limit_up', methods=['GET'])
def get_limit_up_stocks():
"""
获取当日涨停股票列表,按概念板块分组
"""
query = """
SELECT
stock_code,
stock_name,
concept,
close_price,
change_percent
FROM stock_daily
WHERE trade_date = today()
AND change_percent >= 9.9
ORDER BY concept, change_percent DESC
"""
data = clickhouse_client.query(query)
# 按概念分组
result = {}
for row in data:
concept = row['concept']
if concept not in result:
result[concept] = []
result[concept].append(row)
return jsonify(result)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=6801)
```
**前端调用**(通过代理):
```javascript
// craco.config.js 配置代理
proxy: {
'/concept-api': {
target: 'http://49.232.185.254:6801',
pathRewrite: { '^/concept-api': '' },
}
}
// 前端调用
fetch('/concept-api/limit_up')
.then(res => res.json())
.then(data => console.log(data));
```
---
##### 4⃣ 微信支付集成
**文件**:
- `wechat_pay.py` - 微信支付业务逻辑(下单、查询、退款)
- `wechat_pay_config.py` - 配置商户号、API 密钥、证书路径)
**核心功能**:
- **统一下单**: 创建支付订单JSAPI、Native、H5
- **支付回调**: 接收微信支付结果通知
- **订单查询**: 查询订单支付状态
- **退款处理**: 发起退款请求
**示例代码**:
```python
# wechat_pay.py
from wechatpy.pay import WeChatPay
from wechat_pay_config import MCHID, API_KEY, CERT_PATH
# 初始化微信支付客户端
wechat_pay = WeChatPay(
appid='your_appid',
api_key=API_KEY,
mch_id=MCHID,
mch_cert=CERT_PATH,
)
# 创建订单
def create_order(user_id, amount, description):
result = wechat_pay.order.create(
trade_type='JSAPI',
body=description,
total_fee=int(amount * 100), # 单位:分
notify_url='https://yourdomain.com/api/wechat/callback',
user_id=user_id,
)
return result
# 支付回调处理
@app.route('/api/wechat/callback', methods=['POST'])
def wechat_callback():
xml_data = request.data
data = wechat_pay.parse_payment_result(xml_data)
if data['return_code'] == 'SUCCESS':
# 更新订单状态
order_id = data['out_trade_no']
update_order_status(order_id, 'paid')
return wechat_pay.reply('OK', True)
```
---
##### 5⃣ 数据库架构
**多数据库策略**:
| 数据库 | 用途 | 特点 | 示例表 |
|--------|------|------|--------|
| **ClickHouse** | 时序数据存储 | OLAP列式存储、查询速度快 | `stock_daily`(日线数据)<br>`stock_minute`(分钟数据)<br>`concept_daily`(概念板块数据) |
| **MySQL/PostgreSQL** | 事务数据存储 | OLTPACID 保证、关系型) | `users`(用户表)<br>`orders`(订单表)<br>`portfolios`(持仓表)<br>`subscriptions`(订阅表) |
| **Redis** | 缓存 + 消息队列 | 内存数据库(高速读写) | 股票行情缓存<br>用户 Session<br>Celery 任务队列 |
**ClickHouse 使用场景**:
```python
# 查询某只股票的历史数据100 万行数据,查询耗时 < 100ms
query = """
SELECT
trade_date,
open, high, low, close, volume
FROM stock_daily
WHERE stock_code = '600000.SH'
AND trade_date >= '2020-01-01'
ORDER BY trade_date
"""
data = clickhouse_client.query(query)
```
**MySQL 使用场景**:
```python
# 创建订单(事务保证)
@app.route('/api/orders', methods=['POST'])
def create_order():
try:
# 开启事务
order = Order(user_id=user_id, stock_code=stock_code, ...)
db.session.add(order)
# 扣减账户余额
account = Account.query.get(user_id)
account.balance -= order.total_amount
# 提交事务
db.session.commit()
return jsonify({'success': True})
except Exception as e:
# 回滚事务
db.session.rollback()
return jsonify({'error': str(e)}), 500
```
---
#### 后端技术栈详解
**核心框架**:
- **Flask 2.x** - 轻量级 Web 框架,易于扩展
- **Flask-Login** - 用户认证与会话管理
- **Flask-SocketIO** - WebSocket 实时通信(基于 Socket.IO 协议)
- **Flask-CORS** - 跨域资源共享配置
**数据库与 ORM**:
- **SQLAlchemy** - Python ORM支持 MySQL/PostgreSQL
- **ClickHouse Driver** - ClickHouse Python 客户端
- **Redis-py** - Redis Python 客户端
**后台任务处理**:
- **Celery** - 分布式任务队列
- **Redis** - Celery 消息代理Broker
**第三方服务**:
- **微信支付 SDK** - `wechatpy`
- **腾讯云短信 SDK** - 发送验证码、通知
---
#### 后端开发最佳实践
**1. API 设计规范**:
```python
# ✅ RESTful 风格
GET /api/stocks # 获取股票列表
GET /api/stocks/:id # 获取单个股票
POST /api/stocks # 创建股票
PUT /api/stocks/:id # 更新股票
DELETE /api/stocks/:id # 删除股票
# ✅ 统一响应格式
{
"code": 200,
"message": "success",
"data": { ... }
}
# ❌ 避免使用动词命名
POST /api/getStockData # 不推荐
POST /api/createNewOrder # 不推荐
```
**2. 错误处理**:
```python
# 统一错误处理
@app.errorhandler(Exception)
def handle_error(e):
if isinstance(e, ValidationError):
return jsonify({'error': str(e)}), 400
elif isinstance(e, Unauthorized):
return jsonify({'error': 'Unauthorized'}), 401
else:
logger.error(f'Unhandled exception: {e}')
return jsonify({'error': 'Internal server error'}), 500
```
**3. 数据库连接管理**:
```python
# 使用连接池
engine = create_engine(
'mysql://user:pass@localhost/db',
pool_size=10,
max_overflow=20,
pool_recycle=3600,
)
# 请求结束后自动关闭连接
@app.teardown_appcontext
def shutdown_session(exception=None):
db.session.remove()
```
**4. 性能优化**:
- **数据库索引**: 为常用查询字段添加索引
- **查询优化**: 避免 N+1 查询,使用 `joinedload`
- **缓存策略**: 使用 Redis 缓存热点数据(股票行情、用户信息)
- **异步任务**: 耗时操作使用 Celery 异步处理
---
#### 后端部署架构
**生产环境部署**:
```
Nginx (反向代理 + 负载均衡)
├─ Gunicorn (WSGI 服务器) × 4 进程
│ └─ Flask 应用 (app.py)
├─ Celery Worker × 2 进程
│ └─ 后台任务处理
├─ Redis (缓存 + 消息队列)
├─ MySQL (事务数据)
└─ ClickHouse (时序数据)
```
**启动命令**:
```bash
# 启动 Flask 应用Gunicorn
gunicorn -w 4 -b 0.0.0.0:5001 app:app
# 启动 Celery Worker
celery -A simulation_background_processor worker --loglevel=info
# 启动 Concept API
python concept_api.py
```
**监控与日志**:
- **日志**: 使用 Python `logging` 模块记录日志
- **监控**: Celery Flower 监控任务状态
- **性能**: 使用 APM 工具(如 New Relic、Datadog
---
## 配置
### 环境文件
```
.env.mock - Mock 模式默认MSW 拦截所有 API 调用,无需后端
.env.development - 开发模式:连接到开发后端
.env.test - 测试模式:用于 'npm run start:test'(后端 + 前端一起)
.env.production - 生产环境构建配置
```
**关键环境变量:**
- `REACT_APP_ENABLE_MOCK=true` - 启用 MSW mocking
- `REACT_APP_API_URL` - 后端 URL空字符串 = 使用相对路径或 MSW
### MSW (Mock Service Worker) 设置
MSW 用于开发期间的 API mocking
1. **激活方式**:在 env 文件中设置 `REACT_APP_ENABLE_MOCK=true`
2. **Worker 文件**`public/mockServiceWorker.js`(自动生成)
3. **Handlers**`src/mocks/handlers/`按领域组织auth、stock、company 等)
4. **模式**`onUnhandledRequest: 'warn'` - 未处理的请求会传递到后端
当 MSW 激活时开发服务器代理被禁用MSW 优先拦截)。
### 路径别名 (craco.config.js)
所有别名解析到 `src/` 子目录:
```
@/ → src/
@assets/ → src/assets/
@components/ → src/components/
@constants/ → src/constants/
@contexts/ → src/contexts/
@data/ → src/data/
@hooks/ → src/hooks/
@layouts/ → src/layouts/
@lib/ → src/lib/
@mocks/ → src/mocks/
@providers/ → src/providers/
@routes/ → src/routes/
@services/ → src/services/
@store/ → src/store/
@styles/ → src/styles/
@theme/ → src/theme/
@utils/ → src/utils/
@variables/ → src/variables/
@views/ → src/views/
```
### Webpack 优化 (craco.config.js)
**性能特性:**
- 文件系统缓存(重新构建速度提升 50-80%
- 按库激进的代码分割:
- `react-vendor` - React 核心(优先级 30
- `charts-lib` - echarts、d3、apexcharts、recharts优先级 25
- `chakra-ui` - Chakra UI + Emotion优先级 23
- `antd-lib` - Ant Design优先级 22
- `three-lib` - Three.js优先级 20
- `calendar-lib` - moment、date-fns、FullCalendar优先级 18
- 从构建中移除 ESLint 插件(速度提升 20-30%
- 启用 Babel 缓存
- moment locale 剥离IgnorePlugin
- Source maps生产环境禁用开发环境使用 `eval-cheap-module-source-map`
**开发服务器:**
- 端口 3000prestart 时杀死现有进程)
- 代理(当 MSW 禁用时):`/api``http://49.232.185.254:5001`
- Bundle 分析器:`ANALYZE=true npm run build:analyze`
### 构建流程
1. `npm run build` 使用 CRACO + webpack 优化编译
2. Gulp 任务(`gulp licenses`)为 JS/HTML 添加 Creative Tim 许可证头
3. 输出:`build/` 目录
**Node 兼容性:**
```bash
NODE_OPTIONS='--openssl-legacy-provider --max_old_space_size=4096'
```
## 开发工作流
### 路由开发
添加新路由的步骤:
1.`src/routes/lazy-components.js` 中添加 lazy import
2.`src/routes/routeConfig.js` 中添加路由配置:
- `path` - URL 路径
- `component` - 来自 lazyComponents
- `protection` - MODAL/REDIRECT/PUBLIC
- `layout` - 'main'(带导航栏)或 'none'(全屏)
3. 路由自动使用 Suspense + ErrorBoundary 渲染(由 PageTransitionWrapper 处理)
### 组件组织模式
基于最近的重构(详见 README.md
**原子设计模式:**
- **Atoms原子** - 基础 UI 元素(按钮、徽章、输入框)
- **Molecules分子** - 原子的组合(卡片、表单)
- **Organisms有机体** - 复杂组件(列表、面板)
**大型组件示例结构1000+ 行):**
```
src/views/Community/components/
├── EventCard/
│ ├── index.js - 智能包装器(路由紧凑 vs 详细视图)
│ ├── CompactEventCard.js - 紧凑视图
│ ├── DetailedEventCard.js - 详细视图
│ ├── EventTimeline.js - 原子组件
│ ├── EventImportanceBadge.js - 原子组件
│ └── ...
```
**工具提取:**
- 将可复用逻辑提取到 `src/utils/`(如 `priceFormatters.js`
- 将共享常量提取到 `src/constants/`(如 `animations.js`
### API 集成
**服务层**`src/services/`
- 使用 `src/utils/apiConfig.js` 中的 `getApiBase()` 获取基础 URL
- 示例:`${getApiBase()}/api/endpoint`
- 在 mock 模式下MSW 拦截;在开发/生产环境下,请求后端
**添加新的 API 端点:**
1.`src/services/` 中添加服务函数(或在组件中内联)
2. 如果使用 MSW`src/mocks/handlers/{domain}.js` 中添加 handler
3.`src/mocks/handlers/index.js` 中导入 handler
### Redux 状态管理
**现有 slices**`src/store/slices/`
- `authModalSlice` - 认证模态框状态
- `posthogSlice` - PostHog 分析
- `stockSlice` - 股票数据
- `industrySlice` - 行业/概念数据
- `subscriptionSlice` - 用户订阅
- `communityDataSlice` - 社区内容
**添加新 slice**
1. 创建 `src/store/slices/yourSlice.js`
2.`src/store/index.js` 中导入并添加
3. 通过 `useSelector` 访问,通过 `useDispatch` 派发
---
## TypeScript 接入
### 概述
项目已于 **2025-11-13** 完成 TypeScript 环境配置,采用**渐进式迁移策略**,支持 JavaScript 和 TypeScript 混合开发。
**当前状态**: 环境配置完成,准备开始代码迁移
**迁移策略**: 新代码使用 TypeScript旧代码按优先级逐步迁移
**类型严格度**: 推荐模式(`noImplicitAny: true`,其他严格检查待后续开启)
### 已完成的环境配置
**TypeScript 编译器**: v5.9.3
**tsconfig.json**: 推荐模式配置,支持 JS/TS 混合开发
**CRACO 配置**: 支持 `.ts``.tsx` 文件编译
**ESLint 配置**: 支持 TypeScript 语法检查
**路径别名**: 与现有 `@/` 别名保持一致
**全局类型定义**: 基础类型文件已创建在 `src/types/`
### 可用类型定义
项目已创建以下基础类型定义文件:
**`src/types/api.ts`** - API 相关类型
- `ApiResponse<T>` - 通用 API 响应结构
- `PaginatedResponse<T>` - 分页响应
- `ApiError` - API 错误类型
- `ListQueryParams` - 列表查询参数
**`src/types/stock.ts`** - 股票相关类型
- `StockInfo` - 股票基础信息
- `StockQuote` - 股票行情数据
- `KLineData` - K 线数据
- `StockFinancials` - 财务指标
- `StockPosition` - 股票持仓
- `Sector` - 概念/行业板块
**`src/types/user.ts`** - 用户相关类型
- `UserInfo` - 用户基础信息
- `AuthInfo` - 认证信息
- `LoginParams` / `RegisterParams` - 登录/注册参数
- `UserSubscription` - 订阅信息
- `UserAccount` - 资金账户
- `UserSettings` - 用户设置
**使用方式**:
```typescript
// 统一导入
import type { StockQuote, UserInfo, ApiResponse } from '@/types';
// 或从具体文件导入
import type { StockQuote } from '@/types/stock';
```
### TypeScript 命令
```bash
# 类型检查(不生成输出文件)
npm run type-check
# 类型检查 + 监听模式
npm run type-check:watch
# ESLint 检查(包含 TS 文件)
npm run lint:check
# ESLint 自动修复
npm run lint:fix
```
### 迁移路线图
详细的迁移指南请参考 **[TYPESCRIPT_MIGRATION.md](./TYPESCRIPT_MIGRATION.md)** 文档。
**简要路线图**:
1. **优先级 1⃣**: 工具层(`src/utils/`, `src/constants/`
- 纯函数,迁移成本低,收益高
- 提供类型定义给其他模块使用
2. **优先级 2⃣**: 类型定义层(扩展 `src/types/`
- 添加 `trading.ts`, `community.ts`, `chart.ts`
3. **优先级 3⃣**: 服务层(`src/services/`
- 定义 API 请求/响应类型
- 使用 `ApiResponse<T>` 包装响应
4. **优先级 4⃣**: Redux 状态层(`src/store/slices/`
- 定义 `RootState``AppDispatch` 类型
- 创建类型化的 hooks
5. **优先级 5⃣**: 自定义 Hooks`src/hooks/`
- 添加泛型支持
- 定义完整返回值类型
6. **优先级 6⃣**: 组件层(`src/components/`, `src/views/`
- Atoms → Molecules → Organisms → Pages
- 优先迁移复用度高的组件
### 开发规范
**新代码**:
-**必须使用 TypeScript**`.ts``.tsx`
- ✅ 所有函数参数和返回值添加类型
- ✅ 组件 Props 使用 `interface` 定义
- ✅ 避免使用 `any`(特殊情况需添加注释说明)
**旧代码迁移**:
- 按优先级迁移,不强制一次性完成
- 迁移前先阅读 [TYPESCRIPT_MIGRATION.md](./TYPESCRIPT_MIGRATION.md)
- 迁移后运行 `npm run type-check` 验证
**类型定义**:
- 公共类型定义导出到 `src/types/`
- 组件内部类型可定义在组件文件中
- 使用 `type` 还是 `interface` 参考 [迁移指南](./TYPESCRIPT_MIGRATION.md)
### 常见问题
**Q: 路径别名 `@/types` 无法识别?**
A: 确保在 `tsconfig.json` 中配置了 `paths`,并重启 IDE。使用 `npm run type-check` 而非命令行 `tsc`
**Q: 如何处理第三方库没有类型定义?**
A:
1. 尝试安装 `@types/library-name`
2. 创建自定义类型声明文件 `src/types/library-name.d.ts`
3. 临时使用 `as any`(需添加 TODO 注释)
**Q: 迁移期间如何处理 any 类型?**
A: 添加 ESLint 禁用注释和 TODO 说明:
```typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
// TODO: 待完善类型定义
const legacyFunction = (data: any): any => { ... };
```
**Q: React 组件的 children 类型如何定义?**
A: 使用 `React.ReactNode`
```typescript
interface Props {
children: React.ReactNode;
}
```
### 参考资源
- [TYPESCRIPT_MIGRATION.md](./TYPESCRIPT_MIGRATION.md) - 完整迁移指南
- [TypeScript 官方文档](https://www.typescriptlang.org/docs/)
- [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/)
- [Redux Toolkit TypeScript 指南](https://redux-toolkit.js.org/usage/usage-with-typescript)
---
## 更新本文档
本 CLAUDE.md 文件是一个持续更新的文档。在以下情况下应更新它:
- 添加新的架构模式或指南
- 发现新的最佳实践
- 解决或添加技术债务项
- 做出重要的技术决策
- 进行重要的代码清理或重构
所有开发人员应在入职时审查本文档,并在做出架构决策时参考它。