{
  "project": "MarkLite",
  "version": "0.1.1",
  "analysisDate": "2026-06-03",
  "techStack": {
    "electron": "28.3.3",
    "react": "18.3.1",
    "typescript": "5.6.3",
    "vite": "electron-vite 3.0.0",
    "stateManagement": "zustand 5.0.6",
    "editor": "CodeMirror 6",
    "database": "Dexie (IndexedDB)"
  },
  "currentStatus": {
    "typescriptCheck": "PASS",
    "eslintConfig": "MISSING",
    "testCoverage": "NONE",
    "documentation": "NONE",
    "ci": "NONE"
  },
  "codebaseStats": {
    "totalSourceFiles": 44,
    "mainProcessFiles": 5,
    "preloadFiles": 1,
    "rendererFiles": 36,
    "sharedFiles": 2,
    "components": 14,
    "stores": 3,
    "hooks": 7,
    "dbRepositories": 3,
    "typeDefinitions": 5,
    "styleFiles": 3
  },
  "optimizationRequirements": {
    "1_codeQuality": {
      "title": "代码质量与规范",
      "priority": "HIGH",
      "items": [
        {
          "id": "CQ-01",
          "title": "配置 ESLint (Flat Config)",
          "priority": "P0-CRITICAL",
          "description": "package.json 中已有 @typescript-eslint/eslint-plugin、eslint、eslint-plugin-react-hooks 等依赖，但缺少 eslint.config.js 配置文件。npm run lint 无法正常工作。",
          "currentState": "devDependencies 已安装但无配置文件",
          "expectedState": "创建 eslint.config.js (ESLint v9 flat config 格式)，配置 TypeScript + React + React Hooks 规则",
          "effort": "small",
          "details": {
            "configFormat": "ESM flat config (eslint.config.js)",
            "plugins": ["@typescript-eslint/eslint-plugin", "eslint-plugin-react-hooks", "eslint-plugin-react-refresh"],
            "rules": [
              "typescript-eslint/recommended",
              "react-hooks/recommended",
              "no-unused-vars (error)",
              "no-console (warn)",
              "prefer-const"
            ]
          }
        },
        {
          "id": "CQ-02",
          "title": "添加 Prettier 代码格式化",
          "priority": "P1-HIGH",
          "description": "项目无统一代码格式化工具，代码风格靠人工维护（缩进、引号、分号等不一致风险高）。",
          "currentState": "无 Prettier 配置",
          "expectedState": "添加 .prettierrc 配置 + 与 ESLint 集成",
          "effort": "small",
          "details": {
            "config": {
              "semi": false,
              "singleQuote": true,
              "tabWidth": 2,
              "trailingComma": "none",
              "printWidth": 100
            }
          }
        },
        {
          "id": "CQ-03",
          "title": "添加 .editorconfig",
          "priority": "P2-MEDIUM",
          "description": "统一编辑器行为配置，确保不同开发者环境一致。",
          "currentState": "无 .editorconfig",
          "expectedState": "添加 .editorconfig 文件",
          "effort": "trivial"
        },
        {
          "id": "CQ-04",
          "title": "修复 TypeScript 严格模式下的隐式 any",
          "priority": "P1-HIGH",
          "description": "虽然 tsc --noEmit 通过，但部分回调参数缺少类型标注（如 CustomEvent detail），依赖类型推断。",
          "currentState": "编译通过但存在隐式类型",
          "expectedState": "所有函数参数显式标注类型",
          "effort": "medium"
        },
        {
          "id": "CQ-05",
          "title": "统一错误处理模式",
          "priority": "P1-HIGH",
          "description": "多处 catch 块为空或仅 console.error，用户看不到有意义的错误信息。App.tsx 中 showToast('操作失败') 过于笼统。",
          "currentState": "分散的 try-catch，错误消息不具体",
          "expectedState": "统一的错误处理函数，包含具体错误描述和日志",
          "effort": "medium"
        }
      ]
    },
    "2_performance": {
      "title": "性能优化",
      "priority": "HIGH",
      "items": [
        {
          "id": "PF-01",
          "title": "Markdown 渲染处理器缓存",
          "priority": "P0-CRITICAL",
          "description": "renderMarkdown() 每次调用都创建新的 unified() 处理器管道（含 7 个插件），大文件渲染时开销显著。unified 处理器创建后应缓存复用。",
          "currentState": "每次渲染创建新 processor (7个插件)",
          "expectedState": "缓存 processor 实例，仅在 filePath 变化时重建",
          "effort": "small",
          "impact": "HIGH - 减少每次渲染的初始化开销",
          "details": {
            "location": "src/renderer/lib/markdown.ts",
            "solution": "使用 Map<string, Processor> 按 filePath 缓存，或使用 useMemo 在组件层面缓存"
          }
        },
        {
          "id": "PF-02",
          "title": "Zustand 选择器优化 - 避免订阅整个 tabs 数组",
          "priority": "P0-CRITICAL",
          "description": "Editor.tsx、Preview.tsx、StatusBar.tsx、Sidebar.tsx 都订阅 tabs 数组然后 .find() 查找 activeTab。每次任何 tab 的 content 变化都会触发这些组件重渲染。",
          "currentState": "const tabs = useTabStore(s => s.tabs); const activeTab = tabs.find(...)",
          "expectedState": "使用 useShallow 或自定义选择器仅订阅 activeTab",
          "effort": "medium",
          "impact": "HIGH - 减少不必要的重渲染",
          "affectedFiles": [
            "src/renderer/components/Editor/Editor.tsx",
            "src/renderer/components/Preview/Preview.tsx",
            "src/renderer/components/StatusBar/StatusBar.tsx",
            "src/renderer/components/Sidebar/Sidebar.tsx"
          ],
          "solution": "在 tabStore 中添加 getActiveTab 选择器方法，或使用 zustand useShallow"
        },
        {
          "id": "PF-03",
          "title": "React.memo 包装纯展示组件",
          "priority": "P1-HIGH",
          "description": "Toolbar、StatusBar、Icons 等纯展示组件未使用 React.memo，父组件重渲染时会连带重渲染。",
          "currentState": "无任何组件使用 React.memo",
          "expectedState": "对 Toolbar、StatusBar、TabBar、Preview 等组件使用 memo 包装",
          "effort": "small",
          "impact": "MEDIUM"
        },
        {
          "id": "PF-04",
          "title": "CodeMirror 主题切换优化",
          "priority": "P1-HIGH",
          "description": "useCodeMirror.ts 中 darkMode 变化时销毁并重建整个 EditorView（第93行），导致编辑器完全重新初始化。",
          "currentState": "darkMode 变化 → 整个 EditorView 销毁重建",
          "expectedState": "使用 CodeMirror Compartment 动态切换主题扩展",
          "effort": "medium",
          "impact": "HIGH - 切换主题时保持编辑器状态",
          "details": {
            "location": "src/renderer/components/Editor/useCodeMirror.ts",
            "solution": "使用 @codemirror/state 的 Compartment API 动态 reconfigure 主题扩展"
          }
        },
        {
          "id": "PF-05",
          "title": "CodeMirror 内容更新优化",
          "priority": "P2-MEDIUM",
          "description": "setContent() 使用 from:0 到 length 全量替换，对大文件（10万行+）性能差。应使用事务 diff 或仅在内容实际变化时替换。",
          "currentState": "全量替换: changes: { from: 0, to: current.length, insert: newContent }",
          "expectedState": "仅在内容不同时替换，大文件考虑增量更新",
          "effort": "medium"
        },
        {
          "id": "PF-06",
          "title": "Bundle 大小优化 - 代码分割",
          "priority": "P2-MEDIUM",
          "description": "所有渲染进程代码打包为单一 bundle。rehype-highlight (含 highlight.js)、CodeMirror 等大型库未做懒加载。",
          "currentState": "单 bundle，无代码分割",
          "expectedState": "动态 import 预览相关库、分割 vendor chunk",
          "effort": "medium",
          "details": {
            "chunks": [
              "vendor-react: react + react-dom",
              "vendor-codemirror: @codemirror/*",
              "vendor-markdown: unified + remark + rehype 生态",
              "app: 业务代码"
            ]
          }
        },
        {
          "id": "PF-07",
          "title": "Preview 渲染防抖",
          "priority": "P2-MEDIUM",
          "description": "Preview.tsx 在 activeTab?.content 变化时立即触发异步渲染。快速输入时会频繁调用 renderMarkdown。",
          "currentState": "content 变化立即渲染",
          "expectedState": "添加 150-300ms 防抖，避免快速输入时频繁渲染",
          "effort": "small"
        },
        {
          "id": "PF-08",
          "title": "保存到 IndexedDB 的去抖优化",
          "priority": "P2-MEDIUM",
          "description": "tabStore 中多处使用 setTimeout(() => saveToDB(), 0) 异步保存，但没有去抖。频繁操作时会多次写入。",
          "currentState": "setTimeout(fn, 0) 立即触发",
          "expectedState": "使用 debounce (300-500ms) 合并多次保存",
          "effort": "small"
        }
      ]
    },
    "3_architecture": {
      "title": "架构优化",
      "priority": "MEDIUM",
      "items": [
        {
          "id": "AR-01",
          "title": "App.tsx 拆分 - About 对话框提取",
          "priority": "P1-HIGH",
          "description": "App.tsx 有 307 行，About 对话框 JSX 内联（约 40 行），文件打开/保存逻辑也堆积在组件中。",
          "currentState": "App.tsx 包含 About 弹窗、文件操作、事件监听等所有逻辑",
          "expectedState": "提取 AboutDialog 组件、提取 useFileOperations hook",
          "effort": "medium",
          "details": {
            "extractions": [
              {
                "name": "AboutDialog",
                "from": "App.tsx lines 261-300",
                "to": "src/renderer/components/AboutDialog/AboutDialog.tsx"
              },
              {
                "name": "useFileOperations",
                "description": "提取 handleOpenFile, handleSave, handleSaveAs, handleOpenRecent 为自定义 hook",
                "to": "src/renderer/hooks/useFileOperations.ts"
              }
            ]
          }
        },
        {
          "id": "AR-02",
          "title": "Sidebar 组件拆分",
          "priority": "P1-HIGH",
          "description": "Sidebar.tsx 有 241 行，包含 FileTree 递归组件、resize 逻辑、独立文件列表等。应拆分为独立文件。",
          "currentState": "FileTree 组件定义在 Sidebar.tsx 内",
          "expectedState": "FileTree 提取为独立组件，resize 逻辑提取为 hook",
          "effort": "medium",
          "details": {
            "extractions": [
              {
                "name": "FileTree",
                "from": "Sidebar.tsx lines 180-239",
                "to": "src/renderer/components/Sidebar/FileTree.tsx"
              },
              {
                "name": "useSidebarResize",
                "description": "提取 resize 相关逻辑为自定义 hook",
                "to": "src/renderer/hooks/useSidebarResize.ts"
              }
            ]
          }
        },
        {
          "id": "AR-03",
          "title": "统一设置加载 - 消除 useTheme 和 useSettings 的重复加载",
          "priority": "P2-MEDIUM",
          "description": "useTheme 和 useSettings 各自独立调用 settingsRepository.load()，导致启动时两次 IndexedDB 读取。",
          "currentState": "useTheme.load() + useSettings.load() = 两次 DB 读取",
          "expectedState": "统一为单个 useSettingsInit hook，一次加载分发到 store",
          "effort": "small"
        },
        {
          "id": "AR-04",
          "title": "消除 DOM CustomEvent 中间层",
          "priority": "P2-MEDIUM",
          "description": "useFileWatch.ts 通过 window.dispatchEvent(CustomEvent) 传递文件修改事件，App.tsx 再 addEventListener 监听。应直接通过 Zustand store 或回调传递。",
          "currentState": "IPC → CustomEvent DOM → App.tsx listener",
          "expectedState": "IPC → Zustand store action → 组件响应",
          "effort": "small"
        },
        {
          "id": "AR-05",
          "title": "添加 React ErrorBoundary",
          "priority": "P1-HIGH",
          "description": "无全局错误边界。任何渲染错误会导致白屏。Electron 应用中尤其需要，因为用户无法刷新页面恢复。",
          "currentState": "无 ErrorBoundary",
          "expectedState": "添加 ErrorBoundary 组件包裹 App，显示错误信息和重启按钮",
          "effort": "small"
        },
        {
          "id": "AR-06",
          "title": "Icons 组件按需加载",
          "priority": "P2-MEDIUM",
          "description": "Icons.tsx 有 216 行，包含 16 个 SVG 图标组件。虽然是函数组件有 tree-shaking，但单文件过大影响维护。",
          "currentState": "16 个图标定义在单文件",
          "expectedState": "按功能模块拆分: toolbar-icons.tsx, sidebar-icons.tsx, app-icons.tsx",
          "effort": "small"
        },
        {
          "id": "AR-07",
          "title": "tabStore 异步操作模式统一",
          "priority": "P2-MEDIUM",
          "description": "tabStore 中大量使用 setTimeout(() => saveToDB(), 0) 和 setTimeout(() => tabRepository.saveActiveTabId(), 0)。模式不统一且容易出错。",
          "currentState": "分散的 setTimeout 调用",
          "expectedState": "使用 Zustand middleware (subscribeWithSelector) 或统一的 persist 逻辑",
          "effort": "medium"
        }
      ]
    },
    "4_userExperience": {
      "title": "用户体验",
      "priority": "MEDIUM",
      "items": [
        {
          "id": "UX-01",
          "title": "替换原生 confirm() 为自定义确认对话框",
          "priority": "P1-HIGH",
          "description": "TabBar.tsx 和 useUnsavedWarning.ts 使用浏览器原生 confirm() 对话框，样式丑陋且不可自定义。Electron 应用应使用自定义模态框或 electron.dialog。",
          "currentState": "5 处使用 confirm() 原生对话框",
          "expectedState": "自定义 ConfirmDialog 组件或使用 electron.dialog.showMessageBox",
          "effort": "medium",
          "affectedLocations": [
            "src/renderer/components/TabBar/TabBar.tsx (4处)",
            "src/renderer/hooks/useUnsavedWarning.ts (1处)"
          ]
        },
        {
          "id": "UX-02",
          "title": "添加加载状态指示",
          "priority": "P1-HIGH",
          "description": "文件打开、目录树加载、Markdown 渲染等异步操作无加载状态。用户无法感知操作是否正在进行。",
          "currentState": "无 loading 状态",
          "expectedState": "添加文件打开 spinner、目录树加载骨架屏、预览渲染指示器",
          "effort": "medium"
        },
        {
          "id": "UX-03",
          "title": "添加编辑器+预览分屏模式",
          "priority": "P2-MEDIUM",
          "description": "当前只有 'editor' 和 'preview' 两种模式，缺少 VS Code 风格的左右分屏同时编辑和预览。",
          "currentState": "viewMode: 'editor' | 'preview'",
          "expectedState": "新增 'split' 模式: 左侧编辑器 + 右侧实时预览",
          "effort": "large",
          "details": {
            "implementation": [
              "Settings.ViewMode 新增 'split'",
              "Editor 和 Preview 同时渲染",
              "编辑器滚动同步预览",
              "Ctrl+3 快捷键"
            ]
          }
        },
        {
          "id": "UX-04",
          "title": "TabBar 拖拽排序",
          "priority": "P3-LOW",
          "description": "标签页不支持拖拽排序，无法自定义标签顺序。",
          "currentState": "标签页固定顺序",
          "expectedState": "支持拖拽重新排列标签页",
          "effort": "large"
        },
        {
          "id": "UX-05",
          "title": "改进 Toast 通知系统",
          "priority": "P2-MEDIUM",
          "description": "当前 Toast 仅支持单条消息，3秒后消失。不支持不同类型（success/error/warning）和堆叠。",
          "currentState": "单条 toast，无类型区分",
          "expectedState": "支持多条堆叠、不同类型（成功/错误/警告）、可关闭",
          "effort": "small"
        },
        {
          "id": "UX-06",
          "title": "添加文件搜索功能 (Ctrl+P)",
          "priority": "P3-LOW",
          "description": "无快速文件搜索/打开功能。当打开文件夹后，应支持按文件名快速搜索打开。",
          "currentState": "仅支持文件夹树浏览",
          "expectedState": "Ctrl+P 快速搜索面板，模糊匹配文件名",
          "effort": "large"
        },
        {
          "id": "UX-07",
          "title": "可访问性增强",
          "priority": "P2-MEDIUM",
          "description": "部分组件缺少 ARIA 属性。Sidebar resize handle 无键盘支持。文件树展开/折叠无键盘导航。",
          "currentState": "基本的 role/aria-label 已添加",
          "expectedState": "完整的键盘导航、focus 管理、屏幕阅读器支持",
          "effort": "medium",
          "details": {
            "missing": [
              "resize handle 需要 role='separator' + 键盘调整",
              "文件树需要 aria-expanded、aria-owns",
              "右键菜单需要 role='menu' + 键盘导航",
              "About 对话框需要 focus trap"
            ]
          }
        }
      ]
    },
    "5_developmentExperience": {
      "title": "开发体验",
      "priority": "MEDIUM",
      "items": [
        {
          "id": "DX-01",
          "title": "添加单元测试框架",
          "priority": "P1-HIGH",
          "description": "项目零测试覆盖。核心逻辑（tabStore、fileUtils、markdown 渲染）应有单元测试。",
          "currentState": "无测试文件、无测试框架",
          "expectedState": "Vitest + React Testing Library，核心模块测试覆盖 > 60%",
          "effort": "large",
          "details": {
            "framework": "vitest + @testing-library/react + jsdom",
            "priority_test_targets": [
              "src/renderer/stores/tabStore.ts - 标签页 CRUD 逻辑",
              "src/renderer/lib/fileUtils.ts - 文件名/路径工具",
              "src/renderer/lib/markdown.ts - Markdown 渲染",
              "src/renderer/db/schema.ts - 数据库 schema",
              "src/main/file-system.ts - 文件系统操作"
            ],
            "scripts": {
              "test": "vitest run",
              "test:watch": "vitest",
              "test:coverage": "vitest run --coverage"
            }
          }
        },
        {
          "id": "DX-02",
          "title": "强化 preload 类型安全",
          "priority": "P2-MEDIUM",
          "description": "types/ipc.ts 定义了 ElectronAPI 接口和 IpcInvokeMap，但 preload/index.ts 未使用这些类型约束。contextBridge.exposeInMainWorld 返回值无类型检查。",
          "currentState": "preload 使用字面量对象，未引用 ElectronAPI 类型",
          "expectedState": "preload 实现强制匹配 ElectronAPI 接口类型",
          "effort": "small",
          "details": {
            "solution": "const api: ElectronAPI = { ... } 在 preload 中强制类型检查"
          }
        },
        {
          "id": "DX-03",
          "title": "添加类型安全的 IPC 通信层",
          "priority": "P2-MEDIUM",
          "description": "types/ipc.ts 定义了 IpcInvokeMap 但未被使用。应建立类型安全的 IPC 调用包装器。",
          "currentState": "IpcInvokeMap 已定义但未使用",
          "expectedState": "渲染进程通过类型安全的 invoke 函数调用 IPC",
          "effort": "medium"
        },
        {
          "id": "DX-04",
          "title": "添加项目文档",
          "priority": "P2-MEDIUM",
          "description": "无 README.md、无 CONTRIBUTING.md、无开发环境搭建文档。",
          "currentState": "无文档",
          "expectedState": "README.md 含项目介绍、安装步骤、开发指南、构建说明",
          "effort": "small",
          "details": {
            "files": [
              "README.md - 项目介绍、截图、安装、开发、构建",
              "CONTRIBUTING.md - 贡献指南、代码规范、PR 流程",
              "CHANGELOG.md - 版本变更记录"
            ]
          }
        },
        {
          "id": "DX-05",
          "title": "添加 Git hooks (husky + lint-staged)",
          "priority": "P2-MEDIUM",
          "description": "无 pre-commit 钩子，代码质量无法在提交时保证。",
          "currentState": "无 Git hooks",
          "expectedState": "husky + lint-staged: 提交前自动运行 ESLint + 类型检查",
          "effort": "small"
        },
        {
          "id": "DX-06",
          "title": "添加 CI/CD 配置",
          "priority": "P3-LOW",
          "description": "无持续集成配置。应添加 GitHub Actions 或 Gitee CI 配置。",
          "currentState": "无 CI 配置",
          "expectedState": "CI 流水线: lint → typecheck → test → build",
          "effort": "small"
        },
        {
          "id": "DX-07",
          "title": "添加路径别名到 Vite 配置",
          "priority": "P3-LOW",
          "description": "tsconfig.json 定义了 @renderer/*、@main/*、@shared/* 路径别名，但 electron.vite.config.ts 中 renderer 的 alias 只有 @renderer 和 @shared，缺少 @main。",
          "currentState": "renderer alias 缺少 @main 映射",
          "expectedState": "补全所有路径别名映射",
          "effort": "trivial"
        }
      ]
    },
    "6_security": {
      "title": "安全加固",
      "priority": "HIGH",
      "items": [
        {
          "id": "SE-01",
          "title": "CSP (Content Security Policy) 配置",
          "priority": "P1-HIGH",
          "description": "未配置 CSP。Preview 使用 dangerouslySetInnerHTML 渲染 HTML，虽然 rehype-sanitize 做了清理，但缺少 CSP 作为第二道防线。",
          "currentState": "无 CSP 配置",
          "expectedState": "在 index.html 和 BrowserWindow 中配置严格 CSP",
          "effort": "small"
        },
        {
          "id": "SE-02",
          "title": "Preview 中 file:// 协议安全",
          "priority": "P1-HIGH",
          "description": "rehypeFixImages 将相对路径图片转为 file:// URL。虽然拒绝了 '..' 但未做更严格的路径校验（如 symlink 跟踪）。",
          "currentState": "仅检查 '..' 路径遍历",
          "expectedState": "使用 path.resolve + 检查结果路径是否在允许目录内",
          "effort": "small"
        },
        {
          "id": "SE-03",
          "title": "Electron 安全最佳实践检查",
          "priority": "P2-MEDIUM",
          "description": "需确认 BrowserWindow 配置中 webPreferences 的安全设置（nodeIntegration、contextIsolation、sandbox 等）。",
          "currentState": "未检查 window-manager.ts 中的 webPreferences",
          "expectedState": "确保 nodeIntegration=false、contextIsolation=true、sandbox=true",
          "effort": "small"
        }
      ]
    }
  },
  "implementationPlan": {
    "phase1_foundation": {
      "name": "基础补全 (1-2天)",
      "priority": "P0",
      "items": ["CQ-01", "CQ-02", "CQ-03", "AR-05", "DX-07"],
      "description": "ESLint + Prettier + EditorConfig + ErrorBoundary + 路径别名修复"
    },
    "phase2_criticalPerf": {
      "name": "关键性能修复 (1-2天)",
      "priority": "P0",
      "items": ["PF-01", "PF-02", "PF-04", "PF-07", "PF-08"],
      "description": "Markdown 缓存 + Zustand 选择器 + CodeMirror Compartment + 防抖"
    },
    "phase3_codeQuality": {
      "name": "代码质量提升 (2-3天)",
      "priority": "P1",
      "items": ["CQ-04", "CQ-05", "AR-01", "AR-02", "AR-03", "AR-04", "PF-03"],
      "description": "类型完善 + 错误处理统一 + 组件拆分 + 重复逻辑消除"
    },
    "phase4_userExperience": {
      "name": "用户体验改进 (2-3天)",
      "priority": "P1",
      "items": ["UX-01", "UX-02", "UX-05", "UX-07"],
      "description": "自定义确认框 + 加载状态 + Toast 改进 + 可访问性"
    },
    "phase5_developerExperience": {
      "name": "开发体验 (2-3天)",
      "priority": "P2",
      "items": ["DX-01", "DX-02", "DX-04", "DX-05"],
      "description": "单元测试 + 类型安全 + 文档 + Git hooks"
    },
    "phase6_advanced": {
      "name": "高级功能 (3-5天)",
      "priority": "P2-P3",
      "items": ["PF-06", "UX-03", "UX-04", "UX-06", "SE-01", "SE-02", "SE-03", "DX-06"],
      "description": "代码分割 + 分屏模式 + 拖拽排序 + 搜索 + 安全加固 + CI"
    }
  },
  "riskAssessment": {
    "highRisk": [
      {
        "id": "PF-04",
        "risk": "CodeMirror Compartment 重构可能影响编辑器初始化和标签切换逻辑",
        "mitigation": "保留现有逻辑作为 fallback，逐步迁移到 Compartment"
      },
      {
        "id": "UX-03",
        "risk": "分屏模式需要同时维护两个编辑器实例，内存和性能需关注",
        "mitigation": "使用虚拟化、延迟加载预览面板"
      }
    ],
    "mediumRisk": [
      {
        "id": "PF-02",
        "risk": "Zustand 选择器重构可能遗漏某些订阅点",
        "mitigation": "使用 React DevTools Profiler 验证重渲染情况"
      },
      {
        "id": "SE-01",
        "risk": "CSP 配置过于严格可能阻断 CodeMirror 样式注入",
        "mitigation": "使用 nonce 或 hash 方式允许 CodeMirror 内联样式"
      }
    ]
  }
}
