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

View File

@@ -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()

View File

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

View File

@@ -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()

View File

@@ -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' }),

View File

@@ -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()

View File

@@ -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() {

View File

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

View File

@@ -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'
// 订单接口定义

View File

@@ -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'

View File

@@ -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 {

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'
import { httpClient } from '../lib/httpClient'
import { httpClient } from '../../lib/httpClient'
interface ChartWithOrdersSimpleProps {
symbol: string

View File

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

View File

@@ -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,

View File

@@ -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'
// 支持的交易所列表 (合约格式)

View File

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

View File

@@ -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 {

View File

@@ -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'

View File

@@ -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'

View File

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

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'

View File

@@ -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()

View File

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

View File

@@ -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模型名称

View File

@@ -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()

View File

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

View File

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

View File

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

View File

@@ -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 {

View File

@@ -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 {