refactor: 前后端目录结构模块化 + v2 优化移植与缺陷修复

前端:
- src/srv/api → src/api,按域分文件夹(auth/cluster/host/storage/deployment/collector)
- 新增 http.ts 引擎(http.get/post/put/delete),域模块改用语义化调用
- index.html 增加 favicon(匹配应用 logo 的 emerald + Activity 脉冲)

后端分层增强(保留包名):
- 新增 repository/:从 models 拆出 JsonDB 持久化层(InitDB/GetDB/Shutdown/RequestSave)
- 新增 dto/:从 controllers 抽出各域请求契约(带 binding 校验)
- 新增 pkg/crypto、pkg/jwt:从 utils 拆出安全原语(外部 jwt 别名 jwtv5 避免冲突)
- models 只留领域实体 + sanitizer;utils 只留 gin/应用相关(response/errors)

v2 优化移植与缺陷修复:
- 移植密钥分离/SSH TOFU/并发写安全/Loki 生产级配置/Docker 加固
- 修复 deployment.go 并发丢更新、Helm values 重复键、EncryptField 哨兵、loki-gateway 端点等审计缺陷
- 实现真正的优雅关停(main.go http.Server + signal + repository.Shutdown)
- 修复登录契约:后端返回 accessToken,前端 auth.ts/Login.tsx 对齐
- 补 crypto/jwt/repository 单元测试(含并发写回归)

验证: go build/vet/test 全绿;npm run build 通过;登录→鉴权→优雅关停冒烟通过

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Logan.LiandClaude committed 2026-06-30 10:46:26 +08:00
1 parent fb8d10231a
commit 327e282356
93 files changed
+8433 -3089

No files matched your search

+88 -73
View File
@@ -1,83 +1,98 @@
import { lazy, Suspense, memo } from 'react'
import { Routes, Route, Navigate } from 'react-router'
import Layout from '@/components/Layout'
import Login from '@/pages/Login'
import Dashboard from '@/pages/Dashboard'
import Clusters from '@/pages/Clusters'
import Hosts from '@/pages/Hosts'
import Storage from '@/pages/Storage'
import Deployments from '@/pages/Deployments'
import Collectors from '@/pages/Collectors'
import Settings from '@/pages/Settings'
import { Toaster } from '@/components/ui/sonner'
import { LoadingSpinner } from '@/components/LoadingSpinner'
function RequireAuth({ children }: { children: React.ReactNode }) {
// 路由守卫组件 - 独立定义,便于复用
const RequireAuth = memo(function RequireAuth({ children }: { children: React.ReactNode }) {
const token = localStorage.getItem('token')
if (!token) {
return <Navigate to="/login" replace />
}
return <Layout>{children}</Layout>
}
// 动态导入Layout以避免在登录页面加载它
return <LazyLayout>{children}</LazyLayout>
})
export default function App() {
// 懒加载页面组件 - 实现代码分割
const Login = lazy(() => import('@/pages/Login'))
const Dashboard = lazy(() => import('@/pages/Dashboard'))
const Clusters = lazy(() => import('@/pages/Clusters'))
const Hosts = lazy(() => import('@/pages/Hosts'))
const Storage = lazy(() => import('@/pages/Storage'))
const Deployments = lazy(() => import('@/pages/Deployments'))
const Collectors = lazy(() => import('@/pages/Collectors'))
const Settings = lazy(() => import('@/pages/Settings'))
const Layout = lazy(() => import('@/components/Layout'))
// 懒加载布局包装器
function LazyLayout({ children }: { children: React.ReactNode }) {
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/"
element={
<RequireAuth>
<Dashboard />
</RequireAuth>
}
/>
<Route
path="/clusters"
element={
<RequireAuth>
<Clusters />
</RequireAuth>
}
/>
<Route
path="/hosts"
element={
<RequireAuth>
<Hosts />
</RequireAuth>
}
/>
<Route
path="/storage"
element={
<RequireAuth>
<Storage />
</RequireAuth>
}
/>
<Route
path="/deployments"
element={
<RequireAuth>
<Deployments />
</RequireAuth>
}
/>
<Route
path="/collectors"
element={
<RequireAuth>
<Collectors />
</RequireAuth>
}
/>
<Route
path="/settings"
element={
<RequireAuth>
<Settings />
</RequireAuth>
}
/>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
<Suspense fallback={<PageLoadingFallback />}>
<Layout>{children}</Layout>
</Suspense>
)
}
// 页面加载中占位
function PageLoadingFallback() {
return (
<div className="h-screen w-screen flex items-center justify-center bg-slate-50 dark:bg-slate-950">
<LoadingSpinner size="lg" text="页面加载中..." />
</div>
)
}
// 路由配置 - 集中管理路由定义
interface RouteConfig {
path: string
element: React.ReactNode
auth?: boolean
}
const routes: RouteConfig[] = [
{ path: '/login', element: <Login />, auth: false },
{ path: '/', element: <Dashboard />, auth: true },
{ path: '/clusters', element: <Clusters />, auth: true },
{ path: '/hosts', element: <Hosts />, auth: true },
{ path: '/storage', element: <Storage />, auth: true },
{ path: '/deployments', element: <Deployments />, auth: true },
{ path: '/collectors', element: <Collectors />, auth: true },
{ path: '/settings', element: <Settings />, auth: true },
]
/**
* App 根组件
*
* 优化点:
* 1. 所有页面使用 React.lazy 懒加载,实现代码分割
* 2. 路由守卫独立为 memo 组件
* 3. Suspense 统一处理加载状态
* 4. 路由配置集中管理
*/
const App = memo(function App() {
return (
<>
<Routes>
{routes.map((route) => (
<Route
key={route.path}
path={route.path}
element={
route.auth ? (
<RequireAuth>{route.element}</RequireAuth>
) : (
<Suspense fallback={<PageLoadingFallback />}>
{route.element}
</Suspense>
)
}
/>
))}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
<Toaster />
</>
)
})
export default App