refactor: restructure project directories for better modularity

- Delete llm/ dead code (3 files, zero references)
- Split mcp/ into sub-packages: mcp/provider/ (8 providers) and
  mcp/payment/ (4 payment clients) with registry pattern
- Export Client internal fields and ClientHooks interface for
  sub-package access
- Split api/server.go (3892 lines) into 8 domain-specific handler files
- Split trader/auto_trader.go (2296 lines) into 5 focused files
- Reorganize web/src/components/ flat files into auth/, charts/,
  trader/, common/, modals/, backtest/ subdirectories
- Update all consumer imports to use registry-based provider creation
This commit is contained in:
tinkle-community
2026-03-11 23:58:13 +08:00
parent 6a30e11ee5
commit 8e294a5eed
103 changed files with 6391 additions and 8984 deletions
+9 -9
View File
@@ -4,27 +4,27 @@ import useSWR from 'swr'
import { api } from './lib/api'
import { TraderDashboardPage } from './pages/TraderDashboardPage'
import { AITradersPage } from './components/AITradersPage'
import { LoginPage } from './components/LoginPage'
import { SetupPage } from './components/SetupPage'
import { AITradersPage } from './components/trader/AITradersPage'
import { LoginPage } from './components/auth/LoginPage'
import { SetupPage } from './components/modals/SetupPage'
import { SettingsPage } from './pages/SettingsPage'
import { ResetPasswordPage } from './components/ResetPasswordPage'
import { CompetitionPage } from './components/CompetitionPage'
import { ResetPasswordPage } from './components/auth/ResetPasswordPage'
import { CompetitionPage } from './components/trader/CompetitionPage'
import { LandingPage } from './pages/LandingPage'
import { FAQPage } from './pages/FAQPage'
import { StrategyStudioPage } from './pages/StrategyStudioPage'
import { StrategyMarketPage } from './pages/StrategyMarketPage'
import { DataPage } from './pages/DataPage'
import { LoginRequiredOverlay } from './components/LoginRequiredOverlay'
import HeaderBar from './components/HeaderBar'
import { LoginRequiredOverlay } from './components/auth/LoginRequiredOverlay'
import HeaderBar from './components/common/HeaderBar'
import { LanguageProvider, useLanguage } from './contexts/LanguageContext'
import { AuthProvider, useAuth } from './contexts/AuthContext'
import { ConfirmDialogProvider } from './components/ConfirmDialog'
import { ConfirmDialogProvider } from './components/common/ConfirmDialog'
import { t } from './i18n/translations'
import { useSystemConfig } from './hooks/useSystemConfig'
import { OFFICIAL_LINKS } from './constants/branding'
import { BacktestPage } from './components/BacktestPage'
import { BacktestPage } from './components/backtest/BacktestPage'
import type {
SystemStatus,
AccountInfo,
@@ -1,10 +1,10 @@
import React, { useState, useEffect } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { toast } from 'sonner'
import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { DeepVoidBackground } from './DeepVoidBackground'
import { useAuth } from '../../contexts/AuthContext'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
export function LoginPage() {
const { language } = useLanguage()
@@ -1,7 +1,7 @@
import { motion, AnimatePresence } from 'framer-motion'
import { LogIn, UserPlus, X, AlertTriangle, Terminal } from 'lucide-react'
import { DeepVoidBackground } from './DeepVoidBackground'
import { useLanguage } from '../contexts/LanguageContext'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
import { useLanguage } from '../../contexts/LanguageContext'
interface LoginRequiredOverlayProps {
isOpen: boolean
@@ -2,13 +2,13 @@ import React, { useEffect, useState } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import PasswordChecklist from 'react-password-checklist'
import { toast } from 'sonner'
import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { getSystemConfig } from '../lib/config'
import { DeepVoidBackground } from './DeepVoidBackground'
import { useAuth } from '../../contexts/AuthContext'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { getSystemConfig } from '../../lib/config'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
import { RegistrationDisabled } from './RegistrationDisabled'
import { WhitelistFullPage } from './WhitelistFullPage'
import { WhitelistFullPage } from '../common/WhitelistFullPage'
export function RegisterPage() {
const { language } = useLanguage()
@@ -1,11 +1,11 @@
import { describe, it, expect, vi } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { RegistrationDisabled } from './RegistrationDisabled'
import { LanguageProvider } from '../contexts/LanguageContext'
import { LanguageProvider } from '../../contexts/LanguageContext'
// Mock useLanguage hook
vi.mock('../contexts/LanguageContext', async () => {
const actual = await vi.importActual('../contexts/LanguageContext')
vi.mock('../../contexts/LanguageContext', async () => {
const actual = await vi.importActual('../../contexts/LanguageContext')
return {
...actual,
useLanguage: () => ({ language: 'en' }),
@@ -1,5 +1,5 @@
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
export function RegistrationDisabled() {
const { language } = useLanguage()
@@ -1,11 +1,11 @@
import React, { useState } from 'react'
import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { Header } from './Header'
import { useAuth } from '../../contexts/AuthContext'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { Header } from '../common/Header'
import { ArrowLeft, KeyRound, Eye, EyeOff } from 'lucide-react'
import PasswordChecklist from 'react-password-checklist'
import { Input } from './ui/input'
import { Input } from '../ui/input'
import { toast } from 'sonner'
export function ResetPasswordPage() {
@@ -28,7 +28,7 @@ import {
ArrowDownRight,
CandlestickChart as CandlestickIcon,
} from 'lucide-react'
import { DeepVoidBackground } from './DeepVoidBackground'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
import {
ResponsiveContainer,
AreaChart,
@@ -39,12 +39,12 @@ import {
Tooltip,
ReferenceDot,
} from 'recharts'
import { api } from '../lib/api'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { confirmToast } from '../lib/notify'
import { DecisionCard } from './DecisionCard'
import { MetricTooltip } from './MetricTooltip'
import { api } from '../../lib/api'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { confirmToast } from '../../lib/notify'
import { DecisionCard } from '../trader/DecisionCard'
import { MetricTooltip } from '../common/MetricTooltip'
import type {
BacktestStatusPayload,
BacktestPositionStatus,
@@ -55,7 +55,7 @@ import type {
DecisionRecord,
AIModel,
Strategy,
} from '../types'
} from '../../types'
// ============ Types ============
type WizardStep = 1 | 2 | 3
@@ -10,14 +10,14 @@ import {
HistogramSeries,
createSeriesMarkers,
} from 'lightweight-charts'
import { useLanguage } from '../contexts/LanguageContext'
import { httpClient } from '../lib/httpClient'
import { useLanguage } from '../../contexts/LanguageContext'
import { httpClient } from '../../lib/httpClient'
import {
calculateSMA,
calculateEMA,
calculateBollingerBands,
type Kline,
} from '../utils/indicators'
} from '../../utils/indicators'
import { Settings, BarChart2 } from 'lucide-react'
// 订单接口定义
@@ -1,8 +1,8 @@
import { useState, useEffect, useRef } from 'react'
import { EquityChart } from './EquityChart'
import { AdvancedChart } from './AdvancedChart'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { BarChart3, CandlestickChart, ChevronDown, Search } from 'lucide-react'
import { motion, AnimatePresence } from 'framer-motion'
@@ -8,8 +8,8 @@ import {
CandlestickSeries,
createSeriesMarkers,
} from 'lightweight-charts'
import { useLanguage } from '../contexts/LanguageContext'
import { httpClient } from '../lib/httpClient'
import { useLanguage } from '../../contexts/LanguageContext'
import { httpClient } from '../../lib/httpClient'
// 订单接口定义
interface OrderMarker {
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'
import { httpClient } from '../lib/httpClient'
import { httpClient } from '../../lib/httpClient'
interface ChartWithOrdersSimpleProps {
symbol: string
@@ -12,11 +12,11 @@ import {
ComposedChart,
} from 'recharts'
import useSWR from 'swr'
import { api } from '../lib/api'
import type { CompetitionTraderData } from '../types'
import { getTraderColor } from '../utils/traderColors'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { api } from '../../lib/api'
import type { CompetitionTraderData } from '../../types'
import { getTraderColor } from '../../utils/traderColors'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { BarChart3, TrendingUp, TrendingDown, Zap } from 'lucide-react'
// Time period options: 1D, 3D, 7D, 30D, All
@@ -10,10 +10,10 @@ import {
ReferenceLine,
} from 'recharts'
import useSWR from 'swr'
import { api } from '../lib/api'
import { useLanguage } from '../contexts/LanguageContext'
import { useAuth } from '../contexts/AuthContext'
import { t } from '../i18n/translations'
import { api } from '../../lib/api'
import { useLanguage } from '../../contexts/LanguageContext'
import { useAuth } from '../../contexts/AuthContext'
import { t } from '../../i18n/translations'
import {
AlertTriangle,
BarChart3,
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState, memo } from 'react'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { ChevronDown, TrendingUp, X } from 'lucide-react'
// 支持的交易所列表 (合约格式)
@@ -13,8 +13,8 @@ import {
AlertDialogDescription,
AlertDialogFooter,
AlertDialogTitle,
} from './ui/alert-dialog'
import { setGlobalConfirm } from '../lib/notify'
} from '../ui/alert-dialog'
import { setGlobalConfirm } from '../../lib/notify'
interface ConfirmOptions {
title?: string
@@ -1,5 +1,5 @@
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { Container } from './Container'
interface HeaderProps {
@@ -2,8 +2,8 @@ import { useState, useEffect, useRef } from 'react'
import { useNavigate } from 'react-router-dom'
import { motion, AnimatePresence } from 'framer-motion'
import { Menu, X, ChevronDown, Settings } from 'lucide-react'
import { t, type Language } from '../i18n/translations'
import { OFFICIAL_LINKS } from '../constants/branding'
import { t, type Language } from '../../i18n/translations'
import { OFFICIAL_LINKS } from '../../constants/branding'
type Page =
| 'competition'
@@ -1,7 +1,7 @@
import { useCallback, useEffect, useState, type ReactNode } from 'react'
import { Loader2, ShieldAlert, ShieldCheck, ShieldMinus } from 'lucide-react'
import { CryptoService, diagnoseWebCryptoEnvironment } from '../lib/crypto'
import { t, type Language } from '../i18n/translations'
import { CryptoService, diagnoseWebCryptoEnvironment } from '../../lib/crypto'
import { t, type Language } from '../../i18n/translations'
export type WebCryptoCheckStatus =
| 'idle'
@@ -1,6 +1,6 @@
import { motion } from 'framer-motion'
import { ShieldAlert, ArrowLeft, Twitter, Send, Lock } from 'lucide-react'
import { OFFICIAL_LINKS } from '../constants/branding'
import { OFFICIAL_LINKS } from '../../constants/branding'
interface WhitelistFullPageProps {
onBack?: () => void
+1 -1
View File
@@ -1,6 +1,6 @@
import { useState, useMemo } from 'react'
import { HelpCircle } from 'lucide-react'
import { DeepVoidBackground } from '../DeepVoidBackground'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
import { t, type Language } from '../../i18n/translations'
import { FAQSearchBar } from './FAQSearchBar'
import { FAQSidebar } from './FAQSidebar'
@@ -1,8 +1,8 @@
import React, { useState } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { useAuth } from '../contexts/AuthContext'
import { DeepVoidBackground } from './DeepVoidBackground'
import { invalidateSystemConfig } from '../lib/config'
import { useAuth } from '../../contexts/AuthContext'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
import { invalidateSystemConfig } from '../../lib/config'
export function SetupPage() {
const { register } = useAuth()
@@ -1,8 +1,8 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { t, type Language } from '../i18n/translations'
import { t, type Language } from '../../i18n/translations'
import { toast } from 'sonner'
import { WebCryptoEnvironmentCheck } from './WebCryptoEnvironmentCheck'
import { WebCryptoEnvironmentCheck } from '../common/WebCryptoEnvironmentCheck'
const DEFAULT_LENGTH = 64
@@ -1,23 +1,23 @@
import React, { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import useSWR from 'swr'
import { api } from '../lib/api'
import { api } from '../../lib/api'
import type {
TraderInfo,
CreateTraderRequest,
AIModel,
Exchange,
} from '../types'
import { useLanguage } from '../contexts/LanguageContext'
import { t, type Language } from '../i18n/translations'
import { useAuth } from '../contexts/AuthContext'
import { getExchangeIcon } from './ExchangeIcons'
import { getModelIcon } from './ModelIcons'
} from '../../types'
import { useLanguage } from '../../contexts/LanguageContext'
import { t, type Language } from '../../i18n/translations'
import { useAuth } from '../../contexts/AuthContext'
import { getExchangeIcon } from '../common/ExchangeIcons'
import { getModelIcon } from '../common/ModelIcons'
import { TraderConfigModal } from './TraderConfigModal'
import { DeepVoidBackground } from './DeepVoidBackground'
import { ExchangeConfigModal } from './traders/ExchangeConfigModal'
import { TelegramConfigModal } from './traders/TelegramConfigModal'
import { PunkAvatar, getTraderAvatar } from './PunkAvatar'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
import { ExchangeConfigModal } from './ExchangeConfigModal'
import { TelegramConfigModal } from './TelegramConfigModal'
import { PunkAvatar, getTraderAvatar } from '../common/PunkAvatar'
import {
Bot,
Brain,
@@ -34,7 +34,7 @@ import {
Check,
MessageCircle,
} from 'lucide-react'
import { confirmToast } from '../lib/notify'
import { confirmToast } from '../../lib/notify'
import { toast } from 'sonner'
// 获取友好的AI模型名称
@@ -1,15 +1,15 @@
import { useState } from 'react'
import { Trophy } from 'lucide-react'
import useSWR from 'swr'
import { api } from '../lib/api'
import type { CompetitionData } from '../types'
import { ComparisonChart } from './ComparisonChart'
import { api } from '../../lib/api'
import type { CompetitionData } from '../../types'
import { ComparisonChart } from '../charts/ComparisonChart'
import { TraderConfigViewModal } from './TraderConfigViewModal'
import { getTraderColor } from '../utils/traderColors'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import { PunkAvatar, getTraderAvatar } from './PunkAvatar'
import { DeepVoidBackground } from './DeepVoidBackground'
import { getTraderColor } from '../../utils/traderColors'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { PunkAvatar, getTraderAvatar } from '../common/PunkAvatar'
import { DeepVoidBackground } from '../common/DeepVoidBackground'
export function CompetitionPage() {
const { language } = useLanguage()
@@ -1,6 +1,6 @@
import { useState } from 'react'
import type { DecisionRecord, DecisionAction } from '../types'
import { t, type Language } from '../i18n/translations'
import type { DecisionRecord, DecisionAction } from '../../types'
import { t, type Language } from '../../i18n/translations'
interface DecisionCardProps {
decision: DecisionRecord
@@ -2,15 +2,15 @@ import React, { useState, useEffect } from 'react'
import type { Exchange } from '../../types'
import { t, type Language } from '../../i18n/translations'
import { api } from '../../lib/api'
import { getExchangeIcon } from '../ExchangeIcons'
import { getExchangeIcon } from '../common/ExchangeIcons'
import {
TwoStageKeyModal,
type TwoStageKeyModalResult,
} from '../TwoStageKeyModal'
} from '../modals/TwoStageKeyModal'
import {
WebCryptoEnvironmentCheck,
type WebCryptoCheckStatus,
} from '../WebCryptoEnvironmentCheck'
} from '../common/WebCryptoEnvironmentCheck'
import {
BookOpen, Trash2, HelpCircle, ExternalLink, UserPlus,
Key, Shield, ChevronLeft, Check, Copy, ArrowRight
@@ -1,15 +1,15 @@
import { useState, useEffect, useMemo } from 'react'
import { api } from '../lib/api'
import { useLanguage } from '../contexts/LanguageContext'
import { t, type Language } from '../i18n/translations'
import { MetricTooltip } from './MetricTooltip'
import { formatPrice, formatQuantity } from '../utils/format'
import { api } from '../../lib/api'
import { useLanguage } from '../../contexts/LanguageContext'
import { t, type Language } from '../../i18n/translations'
import { MetricTooltip } from '../common/MetricTooltip'
import { formatPrice, formatQuantity } from '../../utils/format'
import type {
HistoricalPosition,
TraderStats,
SymbolStats,
DirectionStats,
} from '../types'
} from '../../types'
interface PositionHistoryProps {
traderId: string
@@ -1,10 +1,10 @@
import { useState, useEffect } from 'react'
import type { AIModel, Exchange, CreateTraderRequest, Strategy } from '../types'
import { useLanguage } from '../contexts/LanguageContext'
import { t } from '../i18n/translations'
import type { AIModel, Exchange, CreateTraderRequest, Strategy } from '../../types'
import { useLanguage } from '../../contexts/LanguageContext'
import { t } from '../../i18n/translations'
import { toast } from 'sonner'
import { Pencil, Plus, X as IconX, Sparkles, ExternalLink, UserPlus } from 'lucide-react'
import { httpClient } from '../lib/httpClient'
import { httpClient } from '../../lib/httpClient'
// 提取下划线后面的名称部分
function getShortName(fullName: string): string {
@@ -22,7 +22,7 @@ const EXCHANGE_REGISTRATION_LINKS: Record<string, { url: string; hasReferral?: b
lighter: { url: 'https://app.lighter.xyz/?referral=68151432', hasReferral: true },
}
import type { TraderConfigData } from '../types'
import type { TraderConfigData } from '../../types'
// 表单内部状态类型
interface FormState {
@@ -1,5 +1,5 @@
import type { TraderConfigData } from '../types'
import { PunkAvatar, getTraderAvatar } from './PunkAvatar'
import type { TraderConfigData } from '../../types'
import { PunkAvatar, getTraderAvatar } from '../common/PunkAvatar'
// 提取下划线后面的名称部分
function getShortName(fullName: string): string {
+2 -2
View File
@@ -1,7 +1,7 @@
import { useState } from 'react'
import HeaderBar from '../components/HeaderBar'
import HeaderBar from '../components/common/HeaderBar'
import LoginModal from '../components/landing/LoginModal'
import { LoginRequiredOverlay } from '../components/LoginRequiredOverlay'
import { LoginRequiredOverlay } from '../components/auth/LoginRequiredOverlay'
import FooterSection from '../components/landing/FooterSection'
import TerminalHero from '../components/landing/core/TerminalHero'
import LiveFeed from '../components/landing/core/LiveFeed'
+1 -1
View File
@@ -1,4 +1,4 @@
import { DeepVoidBackground } from '../components/DeepVoidBackground'
import { DeepVoidBackground } from '../components/common/DeepVoidBackground'
import { AlertCircle, Home } from 'lucide-react'
export function PageNotFound() {
+3 -3
View File
@@ -4,9 +4,9 @@ import { User, Cpu, Building2, MessageCircle, Eye, EyeOff, ChevronRight, Plus, P
import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../contexts/LanguageContext'
import { api } from '../lib/api'
import { ExchangeConfigModal } from '../components/traders/ExchangeConfigModal'
import { TelegramConfigModal } from '../components/traders/TelegramConfigModal'
import { ModelConfigModal } from '../components/AITradersPage'
import { ExchangeConfigModal } from '../components/trader/ExchangeConfigModal'
import { TelegramConfigModal } from '../components/trader/TelegramConfigModal'
import { ModelConfigModal } from '../components/trader/AITradersPage'
import type { Exchange, AIModel } from '../types'
type Tab = 'account' | 'models' | 'exchanges' | 'telegram'
+1 -1
View File
@@ -20,7 +20,7 @@ import {
import { useLanguage } from '../contexts/LanguageContext'
import { useAuth } from '../contexts/AuthContext'
import { toast } from 'sonner'
import { DeepVoidBackground } from '../components/DeepVoidBackground'
import { DeepVoidBackground } from '../components/common/DeepVoidBackground'
interface PublicStrategy {
id: string
+1 -1
View File
@@ -38,7 +38,7 @@ import { RiskControlEditor } from '../components/strategy/RiskControlEditor'
import { PromptSectionsEditor } from '../components/strategy/PromptSectionsEditor'
import { PublishSettingsEditor } from '../components/strategy/PublishSettingsEditor'
import { GridConfigEditor, defaultGridConfig } from '../components/strategy/GridConfigEditor'
import { DeepVoidBackground } from '../components/DeepVoidBackground'
import { DeepVoidBackground } from '../components/common/DeepVoidBackground'
const API_BASE = import.meta.env.VITE_API_BASE || ''
+5 -5
View File
@@ -1,15 +1,15 @@
import { useEffect, useState, useRef } from 'react'
import { mutate } from 'swr'
import { api } from '../lib/api'
import { ChartTabs } from '../components/ChartTabs'
import { DecisionCard } from '../components/DecisionCard'
import { PositionHistory } from '../components/PositionHistory'
import { PunkAvatar, getTraderAvatar } from '../components/PunkAvatar'
import { ChartTabs } from '../components/charts/ChartTabs'
import { DecisionCard } from '../components/trader/DecisionCard'
import { PositionHistory } from '../components/trader/PositionHistory'
import { PunkAvatar, getTraderAvatar } from '../components/common/PunkAvatar'
import { confirmToast, notify } from '../lib/notify'
import { formatPrice, formatQuantity } from '../utils/format'
import { t, type Language } from '../i18n/translations'
import { LogOut, Loader2, Eye, EyeOff, Copy, Check } from 'lucide-react'
import { DeepVoidBackground } from '../components/DeepVoidBackground'
import { DeepVoidBackground } from '../components/common/DeepVoidBackground'
import { GridRiskPanel } from '../components/strategy/GridRiskPanel'
import type {
SystemStatus,