Skip to content

Commit d583237

Browse files
authored
Merge pull request #83 from qinshihu/refactor/module-architecture
Refactor/module architecture
2 parents 44841fa + a87a829 commit d583237

134 files changed

Lines changed: 5112 additions & 3646 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# 导航菜单体检记录(NAV-AUDIT)
2+
3+
> `frontend/src/config/navigation.ts` 顺序**逐组、逐页、逐功能**深体检。
4+
> 每组体检完毕即修复问题 → tsc/test → commit → push → 等用户确认 → 下一组。
5+
> 实时状态写在本总账;过程性记录写在「过程记录」段。
6+
>
7+
> 最后更新:2026-07-23(v6 — 逐页逐功能重检开始)
8+
9+
## 总账
10+
11+
| # | 分组 | 菜单项 | 状态 | 备注 |
12+
|---|------|--------|------|------|
13+
| 1 | nav.home | dashboard, bigScreen || v6 体检+修复:useBigScreenData setTimeout cleanup + 2 空 catch → logger.warn + Dashboard 6 useQuery queryFn 内 try/catch logger.error + dashboardRoutes parseInt NaN 防 + dashboardStats/operationalAnalytics 8 处 parseFloat Number.isFinite + useBigScreenData 6 处 data as Array.isArray 兜底 + callZabbix typeof === 'object' 校验 + BigScreenRecentTasksList/RightColumn Invalid Date → '--' |
14+
| 2 | nav.serverMgmt | servers, networkDevices, networks, snmp, networkDiscovery, dbConnections, sshKeys, terminal, remoteDesktop || 待重检 |
15+
| 3 | nav.containersVirtualization | containers, containerMonitor, containerLogs, images, volumes, virtualMachines, compose, snapshotPolicies, vmMigrations, imageRegistry, kubernetes, costAnalysis, autoScale || 待重检 |
16+
| 4 | nav.dataCenter | dcManage, dataRoom || 待重检 |
17+
| 5 | nav.autoExecution | agents, agents/tools, workflows, workflows/providers, tasks, approvals, scripts, scheduledTasks, configTemplates || 待重检 |
18+
| 6 | nav.alertsAI | alerts, alertMappings, alertNoise, alertCorrelation, rootCauseAnalysis, aiRootCause, topology, aiInsights, alertAutoAnalysis, inspectionCenter, alerts/providers, zabbix, prometheus || 待重检 |
19+
| 7 | nav.mcp | mcpOverview, mcpTools, mcpExternalServers, mcpTester || 待重检 |
20+
| 8 | nav.autoRemediation | remediationPolicies, remediationDashboard, remediationExecutions, remediationWorkbench, aiRemediations || 待重检 |
21+
| 9 | nav.knowledgeReports | knowledge, audit, notifications, reports || 待重检 |
22+
| 10 | nav.systemUsers | users, frontendTests, toolLinks, settings || 待重检 |
23+
24+
> 图例:⏳ 待体检 / 🔄 体检中 / ✅ 体检+修复完成
25+
26+
## 已修复 bug 总账(c01c217 commit 范围)
27+
28+
### P0 后端缺失端点(5 处)
29+
- `tool-links`: GET /categories + DELETE /:id/icon
30+
- `alert-provider-configs`: 完整 CRUD(JSON 持久化)
31+
- `notifications`: POST /:id/retry
32+
- `tasks`: POST /:id/retry(创建新 task 并异步执行)
33+
- `ai-remediations`: POST /:id/approve + /reject
34+
35+
### P0 后端结构(3 处)
36+
- `audit JOIN users`: list 改 LEFT JOIN 取 username
37+
- `configTemplates total`: 嵌入 data.items
38+
- `dc slots/batch`: 新增聚合端点(顺序:/batch 必须在 /:rackId 之前)
39+
40+
### P1 前端 axios 解包统一修复(10+ 处)
41+
批量改 `const { data } = await api.get(...)` 模式,涉及 servers/queries.ts(4)+handlers(2)、alerts/*(7)、monitor/TrendCharts/ZabbixQuery/api.ts/cost-analysis、network/*(8)、notification/api.ts(3)、settings/SecuritySettings
42+
43+
### P1 前端硬编码 fetch 漏 /v1(3 处)
44+
- RemoteDesktop.tsx
45+
- BackupSettings.tsx
46+
47+
### P1 kubernetes 双重 /api 前缀
48+
- useKubernetes.ts scale/restart 4 处
49+
50+
### P1 业务修复
51+
- scripts runScript: 前端 setTimeout mock → 真实 POST /scripts/:id/execute
52+
- Topology handleDiscoverDependencies: catch 吞错 → logger.warn + 失败计数
53+
54+
## 待修复(非阻塞 / 体验问题)
55+
56+
| 优先级 || 位置 | 描述 |
57+
|--------|----|------|------|
58+
| P2 | RemediationExecutions 分页无封顶 | `frontend/src/modules/auto/pages/RemediationExecutions.tsx:309-321` | 下一页按钮无 disabled + 限上界 |
59+
| P2 | Reports type 写死 'inspection' | `backend/src/modules/monitor/services/reportService.ts:227,243` | getTemplates/getTemplate 丢失真实 type |
60+
| P3 | lint-staged Windows 路径 bug | `scripts/lint-staged.cjs:31-39` | Windows 上 path.join 把绝对路径当相对路径处理 → ENOENT |
61+
| P3 | ComposeEditor 归属错配 | `frontend/src/modules/containers/...` | compose 实际属 config-management,不影响功能 |
62+
63+
### 2026-07-23 v5+ 完结:遗留 P2/P3 全部解决
64+
- ✅ ssh-keys consumer 5 处 `?? 0/?? ''` fallback
65+
- ✅ useNetworkDevices `_deviceName` 改用 `SnmpInspectionData` 显式断言(消除污染)
66+
- ✅ ComposeEditor PaginatedResult 类型统一为 `{items, total}`(5 个 list 方法对齐)
67+
- ✅ containerRoutes `/containers` / volumeRoutes `/volvolumes` 改为 `{items, total}` 嵌套格式
68+
- ✅ Approvals 评论 modal(已在 v5 完成)
69+
- ✅ 3 个真死路由删除:agents/:id/test-input、agents/:id/executions、scheduled-tasks/:id/run
70+
- ✅ presetTestInputs.ts 删除(只被 test-input 引用)
71+
72+
## 体检方法
73+
74+
每组并行启动 1 个 `general-purpose-task` 子代理,做"路由可达 → 后端模块健康 → 已知 bug 信号"快速体检。子代理只回报高置信度问题。问题修复后 commit + push,再进入下一组。

backend/src/modules/ai/README.md

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
> **DDD 限界上下文**:AI 能力编排(LLM、Agent、RCA、知识库、自动修复)
44
> **聚合根**`Agent``LLM Provider``Knowledge`
5-
> **最后刷新**:2026-07-22(基于 12,943 行实测
5+
> **最后刷新**:2026-07-23(nav.autoExecution 第 5 轮 RBAC + logger 补全
66
77
## 职责
8+
89
AI 能力编排:大语言模型调用、Agent 管理、根因分析、知识库、自动修复建议。
910

1011
## 内部结构(2026-07-22 核对代码现状)
12+
1113
```
1214
ai/
1315
├── routes.ts # 模块路由聚合入口(挂 9 个 mount,含 /mcp 代理)
@@ -44,25 +46,27 @@ ai/
4446

4547
## 路由端点(受保护,路径前缀 `/api/v1/*`
4648

47-
| 前缀 | 来源 routes 文件 | 说明 |
48-
|------|------------------|------|
49-
| `/agents/*` | `agentRoutes.ts``agent/` 子目录 | Agent CRUD + 执行 + 工具 + 导入导出(详见子目录 README) |
50-
| `/knowledge/*` | `knowledgeRoutes.ts` | 知识库 CRUD |
51-
| `/knowledge/qanything/*` | `knowledgeQAnythingRoutes.ts` | QAnything 知识库集成 |
52-
| `/copilot/*` | `copilotRoutes.ts` | AI Copilot 对话 |
53-
| `/root-cause-analysis/*` | `rootCauseAnalysisRoutes.ts` | 根因分析 |
54-
| `/multi-agent/*` | `multiAgentRoutes.ts` | 多 Agent 协作 |
55-
| `/ai-models/*` | `aiModelRoutes.ts` | AI 模型 CRUD |
56-
| `/ai-remediations/*` | `aiRemediationRoutes.ts` | AI 修复建议 |
57-
| `/mcp/*` | `routes.ts` 第 22 行 `router.use('/mcp', mcpGateway)` | **AI 内部使用的 MCP 网关代理**(与 `mcp/` 模块的 `/api/v1/mcp/*` 是不同路径) |
49+
| 前缀 | 来源 routes 文件 | 说明 |
50+
| ------------------------ | ----------------------------------------------------- | ----------------------------------------------------------------------------- |
51+
| `/agents/*` | `agentRoutes.ts``agent/` 子目录 | Agent CRUD + 执行 + 工具 + 导入导出(详见子目录 README) |
52+
| `/knowledge/*` | `knowledgeRoutes.ts` | 知识库 CRUD |
53+
| `/knowledge/qanything/*` | `knowledgeQAnythingRoutes.ts` | QAnything 知识库集成 |
54+
| `/copilot/*` | `copilotRoutes.ts` | AI Copilot 对话 |
55+
| `/root-cause-analysis/*` | `rootCauseAnalysisRoutes.ts` | 根因分析 |
56+
| `/multi-agent/*` | `multiAgentRoutes.ts` | 多 Agent 协作 |
57+
| `/ai-models/*` | `aiModelRoutes.ts` | AI 模型 CRUD |
58+
| `/ai-remediations/*` | `aiRemediationRoutes.ts` | AI 修复建议 |
59+
| `/mcp/*` | `routes.ts` 第 22 行 `router.use('/mcp', mcpGateway)` | **AI 内部使用的 MCP 网关代理**(与 `mcp/` 模块的 `/api/v1/mcp/*` 是不同路径) |
5860

5961
> **路径前缀说明**`ai/routes.ts` 第 22 行的 `router.use('/mcp', mcpGateway)``_registry.ts``/api/v1` 组合后实际是 `/api/v1/mcp/*`**`mcp/` 模块独立路由 `/api/v1/mcp/*` 形成两条等价路径**(均指向同一 `services/mcp/gateway.ts`)。前端 mcp 模块通过 `/api/v1/mcp/*` 调用,AI 模块内部 agent 通过 `agentMcpAdapter` 调用相同服务。
6062
6163
## 依赖关系
64+
6265
- 依赖 `auth/`(鉴权)、`alerts/`(告警数据源)、`mcp/`(AI 内部 tool 调用)
6366
-`workflow/``auto/` 调用
6467

6568
## 关键说明
69+
6670
- `ai/`**全项目最大模块**(12,943 行 / 83 个 .ts,其中非测试 66 个 .ts / 11,220 行),是所有 AI 能力的聚合点
6771
- `llm/llmService/` 集成了多模型(Doubao/OpenAI/LocalAI 三个内置 providerAdapters)、熔断器、重试逻辑
6872
- 单一入口:`llm/llmService/index.ts` 是 barrel,统一导出 `generateCompletion` / `executeAgentWithLLM`

backend/src/modules/ai/routes/agent/crudRoutes.ts

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -64,48 +64,7 @@ router.get('/:id', validateParams(agentSchemas.agentId), (req: Request, res: Res
6464
}
6565
});
6666

67-
// GET /:id/executions - 执行历史列表
68-
router.get(
69-
'/:id/executions',
70-
validateParams(agentSchemas.agentId),
71-
validateQuery(agentSchemas.listExecutions),
72-
(req: Request, res: Response) => {
73-
try {
74-
const { limit = 20, offset = 0, status } = req.query;
75-
const limitNum = parseInt(limit as string);
76-
const offsetNum = parseInt(offset as string);
77-
78-
const executions = agentCrudService.listExecutionsByAgent(req.params.id, {
79-
status: status as string | undefined,
80-
limit: limitNum,
81-
offset: offsetNum,
82-
});
83-
84-
const totalCount = agentCrudService.countExecutionsByAgent(
85-
req.params.id,
86-
status as string | undefined,
87-
);
88-
89-
res.json({
90-
success: true,
91-
data: {
92-
executions,
93-
pagination: {
94-
total: totalCount,
95-
limit: limitNum,
96-
offset: offsetNum,
97-
},
98-
},
99-
});
100-
} catch (error) {
101-
logger.error('Failed to fetch agent executions:', error);
102-
res.status(500).json({
103-
success: false,
104-
error: (error as Error).message || 'Failed to fetch agent executions',
105-
});
106-
}
107-
},
108-
);
67+
// 注:2026-07-23 删除 GET /:id/executions(前端无消费者)
10968

11069
// POST / - 创建
11170
router.post(

backend/src/modules/ai/routes/agent/executionRoutes.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { Request, Response } from 'express';
1212
import { Router } from 'express';
1313
import { randomUUID } from 'crypto';
1414
import { logger } from '../../../../utils/logger';
15+
import { requireRole } from '../../../../middleware/auth';
1516
import { validateBody, validateParams } from '../../../../middleware/validation';
1617
import { agentSchemas } from '../../../../shared/schemas/apiValidation';
1718
import { agentCrudService } from '../../services/agentCrudService';
@@ -20,9 +21,10 @@ import { executeAgentNode } from '../../services/agents/agentExecutor';
2021

2122
const router = Router();
2223

23-
// POST /:id/test - 测试 Agent 执行
24+
// POST /:id/test - 测试 Agent 执行(高风险:实际执行 LLM/工具链)
2425
router.post(
2526
'/:id/test',
27+
requireRole('admin', 'operator'),
2628
validateParams(agentSchemas.agentId),
2729
validateBody(agentSchemas.testAgent),
2830
async (req: Request, res: Response) => {
@@ -62,10 +64,11 @@ router.post(
6264
// 其他Agent用LLM执行
6365
output = await executeAgentWithLLM(agent.id, input);
6466
}
65-
} catch (error) {
67+
} catch (error: unknown) {
6668
status = 'error';
67-
errorMessage = (error as Error).message;
69+
errorMessage = error instanceof Error ? error.message : String(error);
6870
output = `Agent "${agentName}" 执行失败: ${errorMessage}`;
71+
logger.error(`Agent execution failed for ${agentName}:`, error);
6972
}
7073

7174
const executionTime = Date.now() - startTime;

backend/src/modules/ai/routes/agent/importExportRoutes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ import type { Request, Response } from 'express';
1010
import { Router } from 'express';
1111
import { randomUUID } from 'crypto';
1212
import { logger } from '../../../../utils/logger';
13+
import { requireRole } from '../../../../middleware/auth';
1314
import { validateBody, validateParams } from '../../../../middleware/validation';
1415
import { agentSchemas } from '../../../../shared/schemas/apiValidation';
1516
import { agentCrudService } from '../../services/agentCrudService';
1617

1718
const router = Router();
1819

19-
router.post('/import', validateBody(agentSchemas.importAgents), (req: Request, res: Response) => {
20+
router.post('/import', requireRole('admin'), validateBody(agentSchemas.importAgents), (req: Request, res: Response) => {
2021
try {
2122
const agents = req.body.agents;
2223
if (!Array.isArray(agents)) {

backend/src/modules/ai/routes/agent/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
/**
22
* =============================================================================
3-
* Agent 路由聚合入口(2026-07-21 拆分)
3+
* Agent 路由聚合入口(2026-07-21 拆分,2026-07-23 清理死路由
44
* =============================================================================
55
*
6-
* 从原 agentRoutes.ts 单文件拆分为 6 个子路由文件:
6+
* 从原 agentRoutes.ts 单文件拆分为 5 个子路由文件:
77
* - crudRoutes (list / get / create / update / delete + executions list)
8-
* - statsRoutes (stats summary + test-input)
8+
* 注:2026-07-23 删除 GET /:id/executions(前端无消费者),executions list 路径已废
9+
* - statsRoutes (stats summary)
10+
* 注:2026-07-23 删除 GET /:id/test-input(前端无消费者)+ 删除 presetTestInputs.ts
911
* - executionRoutes (POST /:id/test - 测试执行)
1012
* - importExportRoutes (import + export)
1113
* - toolRoutes (tools/list + tools/test + tools/descriptions)
12-
* - presetTestInputs (共享常量)
1314
*
1415
* 全部通过 router.use() 聚合到主 router:
1516
* - routes.ts 调用方:import agentRoutes from './agent' 仍兼容(agentRoutes.ts 是 re-export)

backend/src/modules/ai/routes/agent/presetTestInputs.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
/**
2-
* Agent 统计 / 测试输入 routes(2026-07-21 拆分)
2+
* Agent 统计 routes(2026-07-21 拆分,2026-07-23 清理死路由
33
*
4-
* 从原 agentRoutes.ts L40-65 + L279-312 抽出:
5-
* - GET /stats/summary (汇总统计)
6-
* - GET /:id/test-input (推荐测试输入)
4+
* 仅保留 GET /stats/summary(前端 Agents.tsx 调用);
5+
* GET /:id/test-input 已删除(前端无消费者)。
76
*/
87

98
import type { Request, Response } from 'express';
109
import { Router } from 'express';
1110
import { logger } from '../../../../utils/logger';
12-
import { validateParams } from '../../../../middleware/validation';
13-
import { agentSchemas } from '../../../../shared/schemas/apiValidation';
1411
import { agentCrudService } from '../../services/agentCrudService';
15-
import { PRESET_TEST_INPUTS } from './presetTestInputs';
1612

1713
const router = Router();
1814

@@ -43,39 +39,4 @@ router.get('/stats/summary', (_req: Request, res: Response) => {
4339
}
4440
});
4541

46-
router.get(
47-
'/:id/test-input',
48-
validateParams(agentSchemas.agentId),
49-
(req: Request, res: Response) => {
50-
try {
51-
const agent = agentCrudService.getAgentNameRoleCategory(req.params.id);
52-
if (!agent) {
53-
return res.status(404).json({ success: false, error: 'Agent not found' });
54-
}
55-
56-
const agentName = agent.name;
57-
let testInput = PRESET_TEST_INPUTS[agentName];
58-
59-
// 如果没有预设的测试输入,生成一个通用的
60-
if (!testInput) {
61-
const role = agent.role || '运维助手';
62-
testInput = `你好,我是${role},请帮我处理一个运维相关的问题`;
63-
}
64-
65-
res.json({
66-
success: true,
67-
data: {
68-
testInput,
69-
agentName,
70-
},
71-
});
72-
} catch (error) {
73-
logger.error('Failed to get test input:', error);
74-
res
75-
.status(500)
76-
.json({ success: false, error: (error as Error).message || 'Failed to get test input' });
77-
}
78-
},
79-
);
80-
8142
export default router;

0 commit comments

Comments
 (0)