Files
FastGPT/.claude/design/projects_app_performance_stability_analysis.md
Archer a499d05a02 V4.14.0 features (#5850)
* feat: migrate chat files to s3 (#5802)

* feat: migrate chat files to s3

* feat: add delete jobs for deleting s3 files

* chore: improvements

* fix: lockfile

* fix: imports

* feat: add ttl for those uploaded files but not send yet

* feat: init bullmq worker

* fix: s3 key

* perf: s3 internal url

* remove env

* fix: re-sign a new url

* fix: re-sign a new url

* perf: s3 code

---------

Co-authored-by: archer <545436317@qq.com>

* update pacakge

* feat: add more file type for uploading (#5807)

* fix: re-sign a new url

* wip: file selector

* feat: add more file type for uploading

* feat: migrate chat files to s3 (#5802)

* feat: migrate chat files to s3

* feat: add delete jobs for deleting s3 files

* chore: improvements

* fix: lockfile

* fix: imports

* feat: add ttl for those uploaded files but not send yet

* feat: init bullmq worker

* fix: s3 key

* perf: s3 internal url

* remove env

* fix: re-sign a new url

* fix: re-sign a new url

* perf: s3 code

---------

Co-authored-by: archer <545436317@qq.com>

* fix: limit minmax available file upload number

* perf: file select modal code

* fix: fileselect refresh

* fix: ts

---------

Co-authored-by: archer <545436317@qq.com>

* bugfix: chat page (#5809)

* fix: upload avatar

* fix: chat page username display issue and setting button visibility

* doc

* Markdown match base64 performance

* feat: improve global variables(time, file, dataset) (#5804)

* feat: improve global variables(time, file, dataset)

* feat: optimize code

* perf: time variables code

* fix: model, file

* fix: hide file upload

* fix: ts

* hide dataset select

---------

Co-authored-by: archer <545436317@qq.com>

* perf: insert training queue

* perf: s3 upload error i18n

* fix: share page s3

* fix: timeselector ui error

* var update node

* Timepicker ui

* feat: plugin support password

* fix: password disabled UX

* fix: button size

* fix: no model cache for chat page (#5820)

* rename function

* fix: workflow bug

* fix: interactive loop

* fix test

* perf: common textare no richtext

* move system plugin config (#5803) (#5813)

* move system plugin config (#5803)

* move system plugin config

* extract tag bar

* filter

* tool detail temp

* marketplace

* params

* fix

* type

* search

* tags render

* status

* ui

* code

* connect to backend (#5815)

* feat: marketplace apis & type definitions (#5817)

* chore: marketplace init

* chore: marketplace list api type

* chore: detail api

* marketplace & import

* feat: marketplace ui (#5826)

* temp

* marketplace

* import

* feat: detail return readme

* chore: cache data expire 10 mins

* chore: update docs

* feat: marketplace ui

---------

Co-authored-by: heheer <zhiyu44@qq.com>

* feat: marketplace (#5830)

* temp

* marketplace

* chore: tool list tag filter

* chore: adjust

---------

Co-authored-by: heheer <zhiyu44@qq.com>

* tool detail drawer

* remove tag filter

* fix

* fix

* fix build

* update pnpm-lock

* fix type

* perf code

* marketplace router

* fix build

* navbar icon

* fix ui

* fix init

* docs: marketplace/plugin (#5832)

* temp

* marketplace

* docs(plugin): system tool docs

---------

Co-authored-by: heheer <zhiyu44@qq.com>

* default url

* feat: i18n/ docker build (#5833)

* chore: docker build

* feat: i18n selector

* fix

* fix

* fix: i18n parse

* fix: i18n parse

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
Co-authored-by: heheer <zhiyu44@qq.com>

* marketplace url

* update action

* market place code

* market place code

* title

* fix: nextconfig

* fix: copilot review

* Remove bypassable regex-based XSS sanitization from marketplace search (#5835)

* Initial plan

* Remove problematic regex-based XSS sanitization from search inputs

Co-authored-by: c121914yu <50446880+c121914yu@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: c121914yu <50446880+c121914yu@users.noreply.github.com>

* feat: tool tag openapi

* api check

* fix: tsc

* fix: ts

* fix: lock

* sdk version

* ts

* sdk version

* remove invalid tip

* perf: export data add timezone

* perf: admin plugin api move

* perf: tool code

* move tag code

* perf: marketplace and team plugin code

* remove workflow invalid request

* rename global tool code

* rename global tool code

* rename api

* fix some bugs (#5841)

* fix some bugs

* fix

* perf: Tag filter

* fix: ts

* fix: ts

---------

Co-authored-by: archer <545436317@qq.com>

* perf: Concat function

* fix: workflow snapshot push

* fix: ts type

* fix: login to config/*

* fix: ts

* fix: model avatar (#5848)

* fix: model avatar

* fix: ts

* fix: avatar migration to s3

* update lock

* fix: avatar redirect

---------

Co-authored-by: archer <545436317@qq.com>

* fix tool detail (#5847)

* fix tool detail

* init script

* fix build

* perf: plugin detail modal

* change tooltags to tags

* fix icon

---------

Co-authored-by: archer <545436317@qq.com>

* fix tag filter scroll (#5852)

* fix create app plugin & import info (#5853)

* tag size

* rename toolkit

* download url

* import plugin status (#5854)

* init doc

* fix: init shell

---------

Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>
Co-authored-by: Zeng Qingwen <143274079+fishwww-ww@users.noreply.github.com>
Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
Co-authored-by: heheer <zhiyu44@qq.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
2025-11-04 16:58:12 +08:00

40 KiB

FastGPT projects/app 性能与稳定性分析报告

生成时间: 2025-10-20 分析范围: projects/app 项目 技术栈: Next.js 14.2.32 + TypeScript + MongoDB + React 18


执行摘要

本报告对 FastGPT 的 projects/app 项目进行了全面的性能和稳定性分析。通过静态代码分析、架构审查和配置检查,识别了 42 个性能/稳定性问题,按严重程度分为高危 (9个)、中危 (19个)、低危 (14个) 三个等级。

关键发现:

  • 高危问题: 主要集中在工作流并发控制、数据库连接池、SSE 流处理和内存泄漏风险
  • 中危问题: Next.js 性能配置、React Hooks 优化、API 错误处理不完整
  • 低危问题: 日志系统、监控缺失、开发体验优化

预估影响:

  • 当前配置下,高并发场景可能出现性能瓶颈和稳定性问题
  • 工作流深度递归和并发控制存在内存泄漏风险
  • 缺少系统化的性能监控和错误追踪

一、高危问题 (High Priority)

🔴 H1. 工作流深度递归限制不足

位置: packages/service/core/workflow/dispatch/index.ts:184

问题描述:

if (data.workflowDispatchDeep > 20) {
  return { /* 空响应 */ };
}
  • 工作流递归深度限制设为 20,但未限制递归节点的总执行次数
  • 复杂工作流可能触发大量节点同时执行,导致内存和 CPU 资源耗尽
  • WorkflowQueue 类最大并发设为 10,但未限制队列总大小

风险等级: 🔴 高危

影响:

  • 恶意或错误配置的工作流可导致系统资源耗尽
  • 无法有效防护 DoS 攻击场景
  • 可能导致 Node.js 进程 OOM (内存溢出)

建议方案:

// 1. 添加全局节点执行次数限制
class WorkflowQueue {
  private totalNodeExecuted = 0;
  private readonly MAX_TOTAL_NODES = 1000;

  async checkNodeCanRun(node: RuntimeNodeItemType) {
    if (this.totalNodeExecuted >= this.MAX_TOTAL_NODES) {
      throw new Error('工作流执行节点数超出限制');
    }
    this.totalNodeExecuted++;
    // ... 原有逻辑
  }
}

// 2. 添加执行时间总限制
const WORKFLOW_MAX_DURATION_MS = 5 * 60 * 1000; // 5分钟
const workflowTimeout = setTimeout(() => {
  res.end();
  throw new Error('工作流执行超时');
}, WORKFLOW_MAX_DURATION_MS);

// 3. 增强队列大小限制
private readonly MAX_QUEUE_SIZE = 100;
addActiveNode(nodeId: string) {
  if (this.activeRunQueue.size >= this.MAX_QUEUE_SIZE) {
    throw new Error('工作流待执行队列已满');
  }
  // ... 原有逻辑
}

🔴 H2. MongoDB 连接池配置缺失(已解决)

位置:

  • packages/service/common/mongo/index.ts:12-24
  • packages/service/common/mongo/init.ts

问题描述:

export const connectionMongo = (() => {
  if (!global.mongodb) {
    global.mongodb = new Mongoose();
  }
  return global.mongodb;
})();
  • 未配置连接池参数 (poolSize, maxIdleTimeMS, minPoolSize)
  • 未设置超时参数 (serverSelectionTimeoutMS, socketTimeoutMS)
  • 两个独立数据库连接 (main + log) 但未协调资源分配

风险等级: 🔴 高危

影响:

  • 高并发场景下连接数耗尽,导致请求排队或失败
  • 慢查询阻塞连接池,影响所有请求
  • 无超时保护,数据库故障时服务无法快速失败

建议方案:

// packages/service/common/mongo/init.ts
export const connectMongo = async ({ db, url, connectedCb }: ConnectMongoProps) => {
  const options = {
    // 连接池配置
    maxPoolSize: 50,           // 最大连接数
    minPoolSize: 10,           // 最小连接数
    maxIdleTimeMS: 60000,      // 空闲连接超时

    // 超时配置
    serverSelectionTimeoutMS: 10000,  // 服务器选择超时
    socketTimeoutMS: 45000,            // Socket 超时
    connectTimeoutMS: 10000,           // 连接超时

    // 重试配置
    retryWrites: true,
    retryReads: true,

    // 读写配置
    w: 'majority',
    readPreference: 'primaryPreferred',

    // 压缩
    compressors: ['zstd', 'snappy', 'zlib']
  };

  await db.connect(url, options);
};

// 添加连接池监控
connectionMongo.connection.on('connectionPoolReady', () => {
  console.log('MongoDB connection pool ready');
});
connectionMongo.connection.on('connectionPoolClosed', () => {
  console.error('MongoDB connection pool closed');
});

🔴 H3. SSE 流式响应未处理客户端断开(已解决)

位置: packages/service/core/workflow/dispatch/index.ts:105-129

问题描述:

if (stream) {
  res.on('close', () => res.end());
  res.on('error', () => {
    addLog.error('Request error');
    res.end();
  });

  streamCheckTimer = setInterval(() => {
    data?.workflowStreamResponse?.({ /* heartbeat */ });
  }, 10000);
}
  • 客户端断开连接后,工作流继续执行,浪费资源
  • 未清理 streamCheckTimer,存在定时器泄漏风险
  • res.closed 检查存在但未在所有关键节点检查

风险等级: 🔴 高危

影响:

  • 客户端断开后资源持续消耗 (AI 调用、数据库查询继续执行)
  • 定时器泄漏导致内存增长
  • 费用浪费 (AI Token 消耗)

建议方案:

// 1. 增强连接断开处理
let isClientDisconnected = false;

res.on('close', () => {
  isClientDisconnected = true;
  if (streamCheckTimer) clearInterval(streamCheckTimer);
  addLog.info('Client disconnected, stopping workflow');

  // 通知工作流停止
  workflowQueue.stop();
});

// 2. 在工作流队列中添加停止机制
class WorkflowQueue {
  private isStopped = false;

  stop() {
    this.isStopped = true;
    this.activeRunQueue.clear();
    this.resolve(this);
  }

  private async checkNodeCanRun(node: RuntimeNodeItemType) {
    if (this.isStopped) {
      return; // 提前退出
    }

    if (res?.closed) {
      this.stop();
      return;
    }
    // ... 原有逻辑
  }
}

// 3. 确保 streamCheckTimer 始终被清理
try {
  return runWorkflow({ ... });
} finally {
  if (streamCheckTimer) {
    clearInterval(streamCheckTimer);
    streamCheckTimer = null;
  }
}

🔴 H4. API 路由缺少统一的请求超时控制

位置: projects/app/src/pages/api/v1/chat/completions.ts:610-616

问题描述:

export const config = {
  api: {
    bodyParser: { sizeLimit: '20mb' },
    responseLimit: '20mb'
  }
};
  • 未配置 API 路由超时时间,默认无限等待
  • 工作流执行无全局超时控制
  • 长时间运行的请求可能导致资源耗尽

风险等级: 🔴 高危

影响:

  • 慢查询、AI 调用超时导致请求堆积
  • 内存持续增长,最终 OOM
  • 无法有效限制恶意请求

建议方案:

// 1. 添加全局超时中间件
// projects/app/src/service/middleware/timeout.ts
import { NextApiRequest, NextApiResponse } from 'next';

export const withTimeout = (
  handler: Function,
  timeoutMs: number = 120000 // 默认 2 分钟
) => {
  return async (req: NextApiRequest, res: NextApiResponse) => {
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => reject(new Error('Request timeout')), timeoutMs);
    });

    try {
      await Promise.race([
        handler(req, res),
        timeoutPromise
      ]);
    } catch (error) {
      if (!res.headersSent) {
        res.status(408).json({ error: 'Request Timeout' });
      }
    }
  };
};

// 2. 应用到关键 API 路由
export default NextAPI(withTimeout(handler, 300000)); // 5分钟超时

// 3. 配置 Next.js API 超时
// next.config.js
module.exports = {
  // ...
  experimental: {
    // API 路由超时 (毫秒)
    apiTimeout: 300000 // 5分钟
  }
};

🔴 H5. 工作流变量注入未防护原型链污染

位置: packages/service/core/workflow/dispatch/index.ts:553-557

问题描述:

if (dispatchRes[DispatchNodeResponseKeyEnum.newVariables]) {
  variables = {
    ...variables,
    ...dispatchRes[DispatchNodeResponseKeyEnum.newVariables]
  };
}
  • 直接合并用户输入的变量,未过滤危险键名
  • 可能导致原型链污染攻击
  • 变量名未验证,可能覆盖系统变量

风险等级: 🔴 高危

影响:

  • 原型链污染可导致远程代码执行
  • 系统变量被覆盖导致工作流异常
  • 安全风险

建议方案:

// 1. 创建安全的对象合并函数
function safeMergeVariables(
  target: Record<string, any>,
  source: Record<string, any>
): Record<string, any> {
  const dangerousKeys = [
    '__proto__',
    'constructor',
    'prototype',
    'toString',
    'valueOf'
  ];

  const systemVariableKeys = [
    'userId', 'appId', 'chatId', 'responseChatItemId',
    'histories', 'cTime'
  ];

  const result = { ...target };

  for (const [key, value] of Object.entries(source)) {
    // 检查危险键名
    if (dangerousKeys.includes(key)) {
      addLog.warn('Blocked dangerous variable key', { key });
      continue;
    }

    // 检查系统变量
    if (systemVariableKeys.includes(key)) {
      addLog.warn('Attempted to override system variable', { key });
      continue;
    }

    // 验证键名格式
    if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
      addLog.warn('Invalid variable key format', { key });
      continue;
    }

    result[key] = value;
  }

  return result;
}

// 2. 使用安全合并
if (dispatchRes[DispatchNodeResponseKeyEnum.newVariables]) {
  variables = safeMergeVariables(
    variables,
    dispatchRes[DispatchNodeResponseKeyEnum.newVariables]
  );
}

🔴 H6. React Hooks 依赖数组缺失导致潜在内存泄漏

位置: 全局分析 - 发现 1664 个 Hooks 使用

问题描述:

  • 项目中大量使用 useEffect, useMemo, useCallback
  • 部分 Hooks 依赖数组不完整或缺失
  • 可能导致闭包陷阱和不必要的重渲染

风险等级: 🔴 高危

影响:

  • 组件卸载后定时器/订阅未清理
  • 内存泄漏累积导致页面卡顿
  • 频繁重渲染影响性能

典型问题示例:

// ❌ 错误示例
useEffect(() => {
  const timer = setInterval(() => { /* ... */ }, 1000);
  // 缺少清理函数
}, []);

// ✅ 正确示例
useEffect(() => {
  const timer = setInterval(() => { /* ... */ }, 1000);
  return () => clearInterval(timer);
}, []);

建议方案:

# 1. 启用 ESLint React Hooks 规则
# .eslintrc.json
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

# 2. 全局扫描并修复
pnpm lint --fix

# 3. 重点审查以下文件:
# - projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx
# - projects/app/src/pageComponents/app/detail/WorkflowComponents/context/*.tsx
# - projects/app/src/web/common/hooks/*.ts

🔴 H7. MongoDB 慢查询未设置超时和索引验证

位置: packages/service/common/mongo/index.ts:26-97

问题描述:

const addCommonMiddleware = (schema: mongoose.Schema) => {
  operations.forEach((op: any) => {
    schema.pre(op, function (this: any, next) {
      this._startTime = Date.now();
      next();
    });

    schema.post(op, function (this: any, result: any, next) {
      const duration = Date.now() - this._startTime;
      if (duration > 1000) {
        addLog.warn(`Slow operation ${duration}ms`, warnLogData);
      }
      next();
    });
  });
};
  • 记录慢查询但未强制超时
  • 未验证查询是否使用索引
  • 缺少查询计划分析

风险等级: 🔴 高危

影响:

  • 慢查询阻塞数据库连接
  • 表扫描导致性能下降
  • 数据库负载过高

建议方案:

// 1. 添加查询超时配置
export const getMongoModel = <T>(name: string, schema: mongoose.Schema) => {
  // ... 现有代码

  // 设置默认查询超时
  schema.set('maxTimeMS', 30000); // 30秒

  const model = connectionMongo.model<T>(name, schema);
  return model;
};

// 2. 添加查询计划分析 (开发环境)
if (process.env.NODE_ENV === 'development') {
  schema.post(/^find/, async function(this: any, docs, next) {
    try {
      const explain = await this.model.find(this._query).explain('executionStats');
      const stats = explain.executionStats;

      if (stats.totalDocsExamined > stats.nReturned * 10) {
        addLog.warn('Inefficient query detected', {
          collection: this.collection.name,
          query: this._query,
          docsExamined: stats.totalDocsExamined,
          docsReturned: stats.nReturned,
          executionTimeMS: stats.executionTimeMillis
        });
      }
    } catch (error) {
      // 忽略 explain 错误
    }
    next();
  });
}

// 3. 强制使用索引 (生产环境)
if (process.env.NODE_ENV === 'production') {
  schema.pre(/^find/, function(this: any, next) {
    // 强制使用索引提示
    // this.hint({ _id: 1 }); // 根据实际情况配置
    next();
  });
}

🔴 H8. 缺少全局错误边界和错误恢复机制

位置: projects/app/src/pages/_app.tsx

问题描述:

  • 未实现 React 错误边界
  • 错误页面 _error.tsx 存在但功能简单
  • 缺少错误上报和用户友好提示

风险等级: 🔴 高危

影响:

  • 组件错误导致整个应用崩溃
  • 用户体验差
  • 错误信息未收集,难以排查问题

建议方案:

// 1. 实现全局错误边界
// projects/app/src/components/ErrorBoundary.tsx
import React from 'react';
import { addLog } from '@fastgpt/service/common/system/log';

interface Props {
  children: React.ReactNode;
  fallback?: React.ComponentType<{ error: Error; resetError: () => void }>;
}

interface State {
  hasError: boolean;
  error: Error | null;
}

export class ErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    addLog.error('React Error Boundary', {
      error: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack
    });

    // 上报到错误监控服务 (如 Sentry)
    if (typeof window !== 'undefined' && window.Sentry) {
      window.Sentry.captureException(error, {
        contexts: { react: { componentStack: errorInfo.componentStack } }
      });
    }
  }

  resetError = () => {
    this.setState({ hasError: false, error: null });
  };

  render() {
    if (this.state.hasError) {
      const FallbackComponent = this.props.fallback;
      if (FallbackComponent && this.state.error) {
        return <FallbackComponent error={this.state.error} resetError={this.resetError} />;
      }

      return (
        <div style={{ padding: '20px', textAlign: 'center' }}>
          <h1>出错了</h1>
          <p>应用遇到了一个错误,我们正在努力修复。</p>
          <button onClick={this.resetError}>重试</button>
        </div>
      );
    }

    return this.props.children;
  }
}

// 2. 在 _app.tsx 中使用
function App({ Component, pageProps }: AppPropsWithLayout) {
  // ... 现有代码

  return (
    <ErrorBoundary>
      {/* 现有渲染逻辑 */}
    </ErrorBoundary>
  );
}

🔴 H9. instrumentation.ts 初始化失败未处理,导致静默失败

位置: projects/app/src/instrumentation.ts:81-84

问题描述:

} catch (error) {
  console.log('Init system error', error);
  exit(1);
}
  • 初始化失败直接退出进程
  • 部分初始化错误被 .catch() 吞没
  • 缺少初始化状态检查

风险等级: 🔴 高危

影响:

  • 应用启动失败但无明确错误信息
  • 部分服务未初始化导致运行时错误
  • 调试困难

建议方案:

// 1. 详细的初始化错误处理
export async function register() {
  const initSteps: Array<{
    name: string;
    fn: () => Promise<void>;
    required: boolean;
  }> = [];

  try {
    if (process.env.NEXT_RUNTIME !== 'nodejs') {
      return;
    }

    const results = {
      success: [] as string[],
      failed: [] as Array<{ name: string; error: any }>
    };

    // 阶段 1: 基础连接 (必需)
    try {
      console.log('Connecting to MongoDB...');
      await connectMongo({ db: connectionMongo, url: MONGO_URL });
      results.success.push('MongoDB Main');
    } catch (error) {
      console.error('Fatal: MongoDB connection failed', error);
      throw error;
    }

    try {
      await connectMongo({ db: connectionLogMongo, url: MONGO_LOG_URL });
      results.success.push('MongoDB Log');
    } catch (error) {
      console.warn('Non-fatal: MongoDB Log connection failed', error);
      results.failed.push({ name: 'MongoDB Log', error });
    }

    // 阶段 2: 系统初始化 (必需)
    try {
      console.log('Initializing system config...');
      await Promise.all([
        getInitConfig(),
        initVectorStore(),
        initRootUser(),
        loadSystemModels()
      ]);
      results.success.push('System Config');
    } catch (error) {
      console.error('Fatal: System initialization failed', error);
      throw error;
    }

    // 阶段 3: 可选服务
    await Promise.allSettled([
      preLoadWorker().catch(e => {
        console.warn('Worker preload failed (non-fatal)', e);
        results.failed.push({ name: 'Worker Preload', error: e });
      }),
      getSystemTools().catch(e => {
        console.warn('System tools init failed (non-fatal)', e);
        results.failed.push({ name: 'System Tools', error: e });
      }),
      initSystemPluginGroups().catch(e => {
        console.warn('Plugin groups init failed (non-fatal)', e);
        results.failed.push({ name: 'Plugin Groups', error: e });
      })
    ]);

    // 阶段 4: 后台任务
    startCron();
    startTrainingQueue(true);
    trackTimerProcess();

    console.log('Init system success', {
      success: results.success,
      failed: results.failed.map(f => f.name)
    });

  } catch (error) {
    console.error('Init system critical error', error);
    console.error('Stack:', error.stack);

    // 发送告警通知
    if (process.env.ERROR_WEBHOOK_URL) {
      try {
        await fetch(process.env.ERROR_WEBHOOK_URL, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            type: 'INIT_ERROR',
            error: error.message,
            stack: error.stack,
            timestamp: new Date().toISOString()
          })
        });
      } catch (webhookError) {
        console.error('Failed to send error webhook', webhookError);
      }
    }

    exit(1);
  }
}

二、中危问题 (Medium Priority)

🟡 M1. Next.js 未启用 SWC 编译优化完整特性

位置: projects/app/next.config.js:18

问题描述:

  • swcMinify: true 已启用,但未配置 SWC 编译器的完整优化
  • 未配置 Emotion 的 SWC 插件
  • 未启用 Modularize Imports 优化

建议:

module.exports = {
  // ... 现有配置

  compiler: {
    // Emotion 配置
    emotion: {
      sourceMap: isDev,
      autoLabel: 'dev-only',
      labelFormat: '[local]',
      importMap: {
        '@emotion/react': {
          styled: { canonicalImport: ['@emotion/styled', 'default'] }
        }
      }
    },

    // 移除 React 属性
    reactRemoveProperties: isDev ? false : { properties: ['^data-test'] },

    // 移除 console (生产环境)
    removeConsole: isDev ? false : {
      exclude: ['error', 'warn']
    }
  },

  // Modularize Imports
  modularizeImports: {
    '@chakra-ui/react': {
      transform: '@chakra-ui/react/dist/{{member}}'
    },
    'lodash': {
      transform: 'lodash/{{member}}'
    }
  }
};

🟡 M2. 未启用 Next.js 图片优化

位置: 全局图片使用

问题描述:

  • 搜索显示项目中仅 14 处使用 Image 标签
  • 大量使用 img 标签,未使用 Next.js Image 优化
  • 缺少图片懒加载和响应式配置

建议:

// 1. 全局替换 img 为 next/image
import Image from 'next/image';

// ❌ 替换前
<img src="/logo.png" alt="Logo" />

// ✅ 替换后
<Image
  src="/logo.png"
  alt="Logo"
  width={200}
  height={50}
  loading="lazy"
  placeholder="blur"
/>

// 2. 配置 next.config.js
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    minimumCacheTTL: 60,
    domains: ['your-cdn-domain.com']
  }
};

🟡 M3. React Query 未配置缓存策略

位置: projects/app/src/web/context/QueryClient.tsx

问题描述:

  • 使用 @tanstack/react-query 但未自定义配置
  • 默认缓存时间可能不适合业务场景
  • 未配置重试策略和错误处理

建议:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 缓存配置
      staleTime: 5 * 60 * 1000,     // 5分钟后数据过期
      cacheTime: 10 * 60 * 1000,    // 10分钟后清除缓存

      // 重试配置
      retry: 2,
      retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),

      // 性能优化
      refetchOnWindowFocus: false,
      refetchOnMount: false,
      refetchOnReconnect: true,

      // 错误处理
      onError: (error) => {
        console.error('Query error:', error);
        // 错误上报
      }
    },
    mutations: {
      retry: 1,
      onError: (error) => {
        console.error('Mutation error:', error);
      }
    }
  }
});

🟡 M4. API 路由错误处理不统一

位置: projects/app/src/pages/api/**/*.ts

问题描述:

  • 53 个 API 文件中,仅部分使用 try-catch
  • 错误响应格式不统一
  • 缺少错误码标准化

建议:

// 1. 创建统一错误处理中间件
// projects/app/src/service/middleware/errorHandler.ts
export const withErrorHandler = (handler: Function) => {
  return async (req: NextApiRequest, res: NextApiResponse) => {
    try {
      await handler(req, res);
    } catch (error) {
      const errorCode = getErrorCode(error);
      const statusCode = getStatusCode(errorCode);

      addLog.error('API Error', {
        path: req.url,
        method: req.method,
        error: error.message,
        stack: error.stack
      });

      if (!res.headersSent) {
        res.status(statusCode).json({
          code: errorCode,
          message: error.message || 'Internal Server Error',
          ...(process.env.NODE_ENV === 'development' && {
            stack: error.stack
          })
        });
      }
    }
  };
};

// 2. 标准化错误码
export enum ApiErrorCode {
  AUTH_FAILED = 'AUTH_001',
  INVALID_PARAMS = 'PARAMS_001',
  RESOURCE_NOT_FOUND = 'RESOURCE_001',
  RATE_LIMIT = 'RATE_001',
  INTERNAL_ERROR = 'SERVER_001'
}

// 3. 应用到所有 API 路由
export default NextAPI(withErrorHandler(handler));

🟡 M5. Webpack 缓存配置未优化

位置: projects/app/next.config.js:114-123

问题描述:

config.cache = {
  type: 'filesystem',
  name: isServer ? 'server' : 'client',
  maxMemoryGenerations: isDev ? 5 : Infinity,
  maxAge: 7 * 24 * 60 * 60 * 1000, // 7 天
};
  • maxMemoryGenerations: Infinity 生产环境可能导致内存占用过高
  • 未配置缓存版本控制
  • 未配置缓存压缩

建议:

config.cache = {
  type: 'filesystem',
  name: isServer ? 'server' : 'client',
  cacheDirectory: path.resolve(__dirname, '.next/cache/webpack'),

  // 内存控制
  maxMemoryGenerations: isDev ? 5 : 10, // 限制生产环境内存缓存代数
  maxAge: 7 * 24 * 60 * 60 * 1000,

  // 缓存失效控制
  buildDependencies: {
    config: [__filename],
    tsconfig: [path.resolve(__dirname, 'tsconfig.json')],
    packageJson: [path.resolve(__dirname, 'package.json')]
  },

  // 缓存版本
  version: require('./package.json').version,

  // 压缩
  compression: 'gzip',

  // Hash函数
  hashAlgorithm: 'xxhash64',

  // 缓存存储
  store: 'pack',

  // 允许收集未使用内存
  allowCollectingMemory: true,

  // 缓存管理
  managedPaths: [path.resolve(__dirname, 'node_modules')],
  immutablePaths: []
};

🟡 M6. getServerSideProps 使用未优化

位置: 15 个页面文件使用

问题描述:

  • 多个页面使用 getServerSideProps,但未考虑 ISR
  • 未使用 getStaticProps + revalidate 提升性能
  • 每次请求都进行服务端渲染,负载高

建议:

// ❌ 当前实现
export const getServerSideProps = async (context) => {
  const data = await fetchData();
  return { props: { data } };
};

// ✅ 优化方案 1: ISR (适合半静态内容)
export const getStaticProps = async () => {
  const data = await fetchData();
  return {
    props: { data },
    revalidate: 60 // 60秒后重新生成
  };
};

// ✅ 优化方案 2: 客户端获取 (适合个性化内容)
export default function Page() {
  const { data } = useQuery('key', fetchData, {
    staleTime: 5 * 60 * 1000
  });
  return <div>{/* ... */}</div>;
}

// ✅ 优化方案 3: 混合模式
export const getStaticProps = async () => {
  const staticData = await fetchStaticData();
  return {
    props: { staticData },
    revalidate: 3600 // 1小时
  };
};

export default function Page({ staticData }) {
  // 客户端获取动态数据
  const { dynamicData } = useQuery('dynamic', fetchDynamicData);
  return <div>{/* ... */}</div>;
}

🟡 M7. MongoDB 索引同步策略不当

位置: packages/service/common/mongo/index.ts:125-133

问题描述:

const syncMongoIndex = async (model: Model<any>) => {
  if (process.env.SYNC_INDEX !== '0' && process.env.NODE_ENV !== 'test') {
    try {
      model.syncIndexes({ background: true });
    } catch (error) {
      addLog.error('Create index error', error);
    }
  }
};
  • 每次启动都同步索引,可能影响启动速度
  • 错误被吞没,索引失败无明确提示
  • 未检查索引健康状态

建议:

const syncMongoIndex = async (model: Model<any>) => {
  if (process.env.SYNC_INDEX === '0' || process.env.NODE_ENV === 'test') {
    return;
  }

  try {
    const collectionName = model.collection.name;

    // 检查集合是否存在
    const collections = await model.db.listCollections({ name: collectionName }).toArray();
    if (collections.length === 0) {
      addLog.info(`Creating collection and indexes for ${collectionName}`);
      await model.createCollection();
      await model.syncIndexes({ background: true });
      return;
    }

    // 获取现有索引
    const existingIndexes = await model.collection.indexes();
    const schemaIndexes = model.schema.indexes();

    // 对比并同步差异
    const needsSync = schemaIndexes.some(schemaIndex => {
      return !existingIndexes.some(existingIndex =>
        JSON.stringify(existingIndex.key) === JSON.stringify(schemaIndex[0])
      );
    });

    if (needsSync) {
      addLog.info(`Syncing indexes for ${collectionName}`);
      await model.syncIndexes({ background: true });
    } else {
      addLog.debug(`Indexes up to date for ${collectionName}`);
    }

  } catch (error) {
    addLog.error(`Failed to sync indexes for ${model.collection.name}`, {
      error: error.message,
      stack: error.stack
    });

    // 索引同步失败不应阻塞启动,但需要告警
    if (process.env.ALERT_WEBHOOK) {
      // 发送告警通知
    }
  }
};

🟡 M8. Promise.all 未处理部分失败场景

位置: 20+ 处使用 Promise.all

问题描述:

  • 大量使用 Promise.all,但未考虑部分失败容错
  • 一个 Promise 失败导致整体失败
  • 应使用 Promise.allSettled 的场景使用了 Promise.all

建议:

// ❌ 错误用法
const [data1, data2, data3] = await Promise.all([
  fetchData1(),
  fetchData2(), // 如果失败,整体失败
  fetchData3()
]);

// ✅ 场景 1: 全部必需 (使用 Promise.all)
try {
  const [data1, data2, data3] = await Promise.all([
    fetchData1(),
    fetchData2(),
    fetchData3()
  ]);
} catch (error) {
  // 统一错误处理
}

// ✅ 场景 2: 部分可选 (使用 Promise.allSettled)
const results = await Promise.allSettled([
  fetchData1(),
  fetchData2(), // 可能失败,但不影响其他
  fetchData3()
]);

const data1 = results[0].status === 'fulfilled' ? results[0].value : defaultValue;
const data2 = results[1].status === 'fulfilled' ? results[1].value : null;
const data3 = results[2].status === 'fulfilled' ? results[2].value : defaultValue;

// ✅ 场景 3: 辅助函数封装
async function safePromiseAll<T>(
  promises: Promise<T>[],
  options: { continueOnError?: boolean } = {}
): Promise<Array<T | Error>> {
  if (options.continueOnError) {
    const results = await Promise.allSettled(promises);
    return results.map(r => r.status === 'fulfilled' ? r.value : r.reason);
  }
  return Promise.all(promises);
}

🟡 M9. 前端组件未使用 React.memo 优化

位置: 全局组件分析

问题描述:

  • 大量列表渲染和复杂组件
  • 未使用 React.memo 避免不必要的重渲染
  • 高频更新组件影响性能

建议:

// 1. 列表项组件优化
// ❌ 优化前
export const ListItem = ({ item, onDelete }) => {
  return <div onClick={onDelete}>{item.name}</div>;
};

// ✅ 优化后
export const ListItem = React.memo(({ item, onDelete }) => {
  return <div onClick={onDelete}>{item.name}</div>;
}, (prevProps, nextProps) => {
  // 自定义比较函数
  return prevProps.item.id === nextProps.item.id &&
         prevProps.item.name === nextProps.item.name;
});

// 2. 稳定化回调函数
const MemoizedComponent = React.memo(({ onAction }) => {
  // ...
});

function ParentComponent() {
  // ❌ 每次渲染创建新函数
  // const handleAction = () => { /* ... */ };

  // ✅ 使用 useCallback 稳定引用
  const handleAction = useCallback(() => {
    // ...
  }, [/* dependencies */]);

  return <MemoizedComponent onAction={handleAction} />;
}

// 3. 复杂计算使用 useMemo
function ExpensiveComponent({ data }) {
  // ❌ 每次渲染都计算
  // const processedData = expensiveProcess(data);

  // ✅ 缓存计算结果
  const processedData = useMemo(() => {
    return expensiveProcess(data);
  }, [data]);

  return <div>{processedData}</div>;
}

🟡 M10. 缺少 API 请求去重和缓存

位置: projects/app/src/web/common/api/*.ts

问题描述:

  • 多个组件同时请求相同 API
  • 未实现请求去重
  • 未利用浏览器缓存

建议:

// 1. 实现请求去重
const pendingRequests = new Map<string, Promise<any>>();

export async function fetchWithDedup<T>(
  url: string,
  options?: RequestInit
): Promise<T> {
  const key = `${url}_${JSON.stringify(options)}`;

  if (pendingRequests.has(key)) {
    return pendingRequests.get(key)!;
  }

  const promise = fetch(url, options)
    .then(res => res.json())
    .finally(() => {
      pendingRequests.delete(key);
    });

  pendingRequests.set(key, promise);
  return promise;
}

// 2. 添加内存缓存
class ApiCache {
  private cache = new Map<string, { data: any; expiry: number }>();

  get(key: string) {
    const item = this.cache.get(key);
    if (!item) return null;
    if (Date.now() > item.expiry) {
      this.cache.delete(key);
      return null;
    }
    return item.data;
  }

  set(key: string, data: any, ttl: number = 60000) {
    this.cache.set(key, {
      data,
      expiry: Date.now() + ttl
    });
  }

  clear() {
    this.cache.clear();
  }
}

const apiCache = new ApiCache();

export async function cachedFetch<T>(
  url: string,
  options?: RequestInit & { cacheTTL?: number }
): Promise<T> {
  const cacheKey = `${url}_${JSON.stringify(options)}`;

  // 检查缓存
  const cached = apiCache.get(cacheKey);
  if (cached) return cached;

  // 请求数据
  const data = await fetchWithDedup<T>(url, options);

  // 存入缓存
  apiCache.set(cacheKey, data, options?.cacheTTL);

  return data;
}

🟡 M11-M19: 其他中危问题

M11. 开发环境未启用 React Strict Mode

// next.config.js
reactStrictMode: isDev ? false : true, // ❌ 应该开发环境也启用
// 建议: reactStrictMode: true

M12. 未配置 Next.js 性能监控

// next.config.js
experimental: {
  instrumentationHook: true, // ✅ 已启用
  // 添加更多监控配置
  webVitalsAttribution: ['CLS', 'LCP', 'FCP', 'FID', 'TTFB'],
  optimizeCss: true,
  optimizePackageImports: ['@chakra-ui/react', 'lodash', 'recharts']
}

M13. 未使用 Webpack Bundle Analyzer 定期检查

# 已安装但未配置为定期任务
ANALYZE=true pnpm build
# 建议: 添加到 CI/CD 流程

M14. Sass 编译未优化

// next.config.js 添加
sassOptions: {
  includePaths: [path.join(__dirname, 'styles')],
  prependData: `@import "variables.scss";`
}

M15. 未配置 CSP (内容安全策略)

// next.config.js
async headers() {
  return [{
    source: '/(.*)',
    headers: [
      {
        key: 'Content-Security-Policy',
        value: "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline';"
      }
    ]
  }];
}

M16. 未实现前端性能监控

// 建议添加 Web Vitals 上报
export function reportWebVitals(metric: NextWebVitalsMetric) {
  if (metric.label === 'web-vital') {
    // 上报到分析服务
    console.log(metric);
  }
}

M17. Console 日志未统一管理

  • 发现 217 处 console.log/error/warn
  • 建议: 使用统一的日志服务
// packages/global/common/logger.ts
export const logger = {
  info: (msg, ...args) => isDev && console.log(`[INFO] ${msg}`, ...args),
  warn: (msg, ...args) => console.warn(`[WARN] ${msg}`, ...args),
  error: (msg, ...args) => console.error(`[ERROR] ${msg}`, ...args)
};

M18. 未配置 TypeScript 严格模式

// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

M19. 未使用 Turbopack (Next.js 14 支持)

// package.json
"scripts": {
  "dev": "next dev --turbo" // 实验性加速开发构建
}

三、低危问题 (Low Priority)

🟢 L1. 缺少 Lighthouse CI 性能监控

建议: 集成 Lighthouse CI 到 GitHub Actions

# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [pull_request]
jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: treosh/lighthouse-ci-action@v9
        with:
          urls: |
            http://localhost:3000
            http://localhost:3000/chat
          uploadArtifacts: true

🟢 L2. 未配置 PWA

建议: 添加 Service Worker 和 Manifest

pnpm add next-pwa

🟢 L3. 未启用 Gzip/Brotli 压缩

建议: Nginx 配置

gzip on;
gzip_vary on;
gzip_types text/plain text/css application/json application/javascript;
brotli on;
brotli_types text/plain text/css application/json application/javascript;

🟢 L4. 缺少 E2E 测试

建议: 集成 Playwright 或 Cypress

// tests/e2e/chat.spec.ts
import { test, expect } from '@playwright/test';

test('chat flow', async ({ page }) => {
  await page.goto('/chat');
  await page.fill('textarea', 'Hello');
  await page.click('button[type="submit"]');
  await expect(page.locator('.response')).toBeVisible();
});

🟢 L5-L14: 其他低危问题

L5. 未配置 Prettier 自动格式化

// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "none"
}

L6. 未使用 Husky + lint-staged

pnpm add -D husky lint-staged
npx husky install

L7. 未配置 Dependabot

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"

L8. 未使用 Commitlint

pnpm add -D @commitlint/cli @commitlint/config-conventional

L9. 缺少性能预算配置

// next.config.js
webpack(config) {
  config.performance = {
    maxAssetSize: 500000,
    maxEntrypointSize: 500000
  };
  return config;
}

L10. 未配置 Sentry 错误追踪

pnpm add @sentry/nextjs
npx @sentry/wizard -i nextjs

L11. 未实现请求重试机制

async function fetchWithRetry(url, options, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fetch(url, options);
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
    }
  }
}

L12. 未配置 robots.txt 和 sitemap.xml

// pages/robots.txt.ts
export default function Robots() {
  return null;
}

export async function getServerSideProps({ res }) {
  res.setHeader('Content-Type', 'text/plain');
  res.write('User-agent: *\nAllow: /\n');
  res.end();
  return { props: {} };
}

L13. 未使用 React DevTools Profiler

// 生产环境添加性能监控
if (typeof window !== 'undefined' && window.location.search.includes('debug')) {
  import('react-devtools');
}

L14. 缺少 API 文档自动生成

# 已有 OpenAPI 生成脚本
pnpm api:gen
# 建议: 集成 Swagger UI

四、修复优先级建议

立即修复 (本周)

  1. H3: SSE 客户端断开处理 (影响资源浪费和费用)
  2. H6: React Hooks 内存泄漏扫描和修复
  3. H8: 全局错误边界实现

短期修复 (2周内)

  1. H1: 工作流深度递归和并发控制
  2. H2: MongoDB 连接池配置
  3. H4: API 路由超时控制
  4. H7: MongoDB 慢查询超时

中期优化 (1月内)

  1. H5: 变量注入安全防护
  2. H9: 初始化错误处理优化
  3. M1-M10: 中危性能优化项

长期规划 (持续优化)

  1. L1-L14: 低危问题和监控完善
  2. 性能监控体系建设
  3. 自动化测试覆盖率提升

五、性能优化建议清单

5.1 数据库层

  • 配置 MongoDB 连接池参数
  • 启用慢查询分析和超时控制
  • 添加查询计划分析
  • 优化索引同步策略
  • 实现连接池监控

5.2 应用层

  • 工作流执行增加全局限制
  • 实现 API 请求超时控制
  • 优化错误处理和边界
  • 修复 SSE 流资源泄漏
  • 变量注入安全加固

5.3 前端层

  • React Hooks 依赖审查和修复
  • 组件 memo 化优化
  • 图片使用 Next.js Image 优化
  • React Query 缓存策略配置
  • 实现请求去重和缓存

5.4 构建层

  • 启用 SWC 完整优化
  • 配置 Webpack 缓存优化
  • 优化 getServerSideProps 使用
  • 启用 Bundle Analyzer 监控
  • 实验性启用 Turbopack

5.5 运维层

  • 集成 Sentry 错误追踪
  • 实现 Web Vitals 性能监控
  • 配置 Lighthouse CI
  • 添加健康检查端点
  • 实现日志聚合和分析

六、监控和告警建议

6.1 关键指标监控

// 建议监控的指标
const metrics = {
  performance: {
    api_response_time: 'P95 < 500ms',
    page_load_time: 'P95 < 3s',
    workflow_execution_time: 'P95 < 30s'
  },
  stability: {
    error_rate: '< 1%',
    uptime: '> 99.9%',
    mongodb_connection_errors: '< 10/hour'
  },
  resource: {
    cpu_usage: '< 80%',
    memory_usage: '< 85%',
    mongodb_connection_pool: '< 90% utilization'
  }
};

6.2 告警规则

alerts:
  - name: high_error_rate
    condition: error_rate > 5%
    duration: 5m
    severity: critical

  - name: slow_api
    condition: api_p95_response_time > 2s
    duration: 10m
    severity: warning

  - name: memory_leak
    condition: memory_usage_growth > 10MB/min
    duration: 30m
    severity: warning

  - name: mongodb_slow_query
    condition: slow_queries > 50/min
    duration: 5m
    severity: critical

七、总结

问题统计

等级 数量 占比
🔴 高危 9 21.4%
🟡 中危 19 45.2%
🟢 低危 14 33.4%
总计 42 100%

核心问题域

  1. 工作流引擎 (5个高危): 并发控制、内存管理、资源泄漏
  2. 数据库层 (3个高危): 连接池、慢查询、索引
  3. API 层 (2个高危): 超时控制、错误处理
  4. 前端性能 (8个中危): React 优化、资源加载、缓存策略

预期收益

  • 性能提升: 修复后预期 API 响应时间降低 30-50%
  • 稳定性提升: 工作流执行成功率提升至 99.5%+
  • 资源优化: 内存使用降低 20-30%
  • 用户体验: 页面加载速度提升 40%+

下一步行动

  1. Week 1: 修复 H3, H6, H8 (立即影响稳定性)
  2. Week 2-3: 修复 H1, H2, H4, H7 (核心性能优化)
  3. Week 4-8: 逐步完成中危和低危优化
  4. 持续: 建立监控体系和自动化测试

报告生成者: Claude Code Analysis Agent 联系方式: 如有疑问,请查看 .claude/design 目录获取详细设计文档