Files
vf_react/CLAUDE.md
2025-11-22 16:41:22 +08:00

49 KiB
Raw Blame History

CLAUDE.md

🌐 语言偏好: 请始终使用中文与用户交流,包括所有解释、分析、文档编写和代码注释。

本文件为 Claude Code (claude.ai/code) 提供在此代码库中工作的指导说明。

📖 文档结构导航

本文档分为以下主要章节,建议按需查阅:

基础信息:

架构设计:

开发指南:

技术决策与规范:

技术债务与维护:


项目概览

混合式 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(表格/表单)
    • HeroUI 3.0.0-betaAgentChat 专用2025-11-22 升级)
  • 状态管理: 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

注意: HeroUI v3 文档参考 https://v3.heroui.com/llms.txt详细升级说明见 HEROUI_V3_UPGRADE_GUIDE.md

后端

  • Flask + SQLAlchemy ORM
  • ClickHouse分析型数据库+ MySQL/PostgreSQL事务型数据库
  • Flask-SocketIO 实现 WebSocket 实时更新
  • Celery + Redis 处理后台任务
  • 腾讯云短信 + 微信支付集成

开发命令

前端开发

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

后端开发

python app.py                              # 主 Flask 服务器
python simulation_background_processor.py  # 交易模拟的后台任务处理器
pip install -r requirements.txt            # 安装 Python 依赖

部署

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 嵌套顺序(从外到内):

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 文件结构:

// 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 调用结构:

// 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 = ...)

工具函数特点:

  • 纯函数: 相同输入始终返回相同输出,无副作用
  • 可测试: 易于编写单元测试
  • 可复用: 多处使用的逻辑

示例:

// 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

示例:

// 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

主题配置示例:

// 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/                        # 自定义字体文件(如需要)

使用方式:

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 模式:

# 方式 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.jsEventCard.test.jsutils.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

使用路径别名快速导入:

// ✅ 使用别名(推荐)
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 路由示例:

# 获取股票数据
@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 事件示例:

# 客户端订阅股票行情
@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}')

交易日历加载:

# 全局变量存储交易日
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 - 高性能查询历史股票数据

任务示例:

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 任务:

# 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:

# 启动 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 示例:

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)

前端调用(通过代理):

// 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
  • 支付回调: 接收微信支付结果通知
  • 订单查询: 查询订单支付状态
  • 退款处理: 发起退款请求

示例代码:

# 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(日线数据)
stock_minute(分钟数据)
concept_daily(概念板块数据)
MySQL/PostgreSQL 事务数据存储 OLTPACID 保证、关系型) users(用户表)
orders(订单表)
portfolios(持仓表)
subscriptions(订阅表)
Redis 缓存 + 消息队列 内存数据库(高速读写) 股票行情缓存
用户 Session
Celery 任务队列

ClickHouse 使用场景:

# 查询某只股票的历史数据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 使用场景:

# 创建订单(事务保证)
@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 设计规范:

# ✅ 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. 错误处理:

# 统一错误处理
@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. 数据库连接管理:

# 使用连接池
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 (时序数据)

启动命令:

# 启动 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. Handlerssrc/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 禁用时):/apihttp://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 兼容性:

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. 如果使用 MSWsrc/mocks/handlers/{domain}.js 中添加 handler
  3. src/mocks/handlers/index.js 中导入 handler

Redux 状态管理

现有 slicessrc/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 - 用户设置

使用方式:

// 统一导入
import type { StockQuote, UserInfo, ApiResponse } from '@/types';

// 或从具体文件导入
import type { StockQuote } from '@/types/stock';

TypeScript 命令

# 类型检查(不生成输出文件)
npm run type-check

# 类型检查 + 监听模式
npm run type-check:watch

# ESLint 检查(包含 TS 文件)
npm run lint:check

# ESLint 自动修复
npm run lint:fix

迁移路线图

详细的迁移指南请参考 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/

    • 定义 RootStateAppDispatch 类型
    • 创建类型化的 hooks
  5. 优先级 5: 自定义 Hookssrc/hooks/

    • 添加泛型支持
    • 定义完整返回值类型
  6. 优先级 6: 组件层(src/components/, src/views/

    • Atoms → Molecules → Organisms → Pages
    • 优先迁移复用度高的组件

开发规范

新代码:

  • 必须使用 TypeScript.ts.tsx
  • 所有函数参数和返回值添加类型
  • 组件 Props 使用 interface 定义
  • 避免使用 any(特殊情况需添加注释说明)

旧代码迁移:

  • 按优先级迁移,不强制一次性完成
  • 迁移前先阅读 TYPESCRIPT_MIGRATION.md
  • 迁移后运行 npm run type-check 验证

类型定义:

  • 公共类型定义导出到 src/types/
  • 组件内部类型可定义在组件文件中
  • 使用 type 还是 interface 参考 迁移指南

常见问题

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 说明:

/* eslint-disable @typescript-eslint/no-explicit-any */
// TODO: 待完善类型定义
const legacyFunction = (data: any): any => { ... };

Q: React 组件的 children 类型如何定义? A: 使用 React.ReactNode

interface Props {
  children: React.ReactNode;
}

参考资源


更新本文档

本 CLAUDE.md 文件是一个持续更新的文档。在以下情况下应更新它:

  • 添加新的架构模式或指南
  • 发现新的最佳实践
  • 解决或添加技术债务项
  • 做出重要的技术决策
  • 进行重要的代码清理或重构

所有开发人员应在入职时审查本文档,并在做出架构决策时参考它。