Files
Pre_Seg_Server/工程分析/经验记录.md
admin 4d65c37c73 fix(template): 修复模板库保存/颜色/拖拽排序,联动OntologyInspector,种子腹腔镜35分类模板
- backend/schemas.py: TemplateUpdate 添加 classes/rules 字段
- backend/models.py: Template 添加 description 列
- backend/routers/templates.py: create/update 打包/解包 mapping_rules.classes (已有)
- backend/main.py: seed 腹腔镜胆囊切除术35分类模板
- src/lib/api.ts: updateTemplate 改 PATCH,补齐 color/z_index,_mapTemplate 对齐 TS 接口
- src/store/useStore.ts: 新增 activeTemplateId/setActiveTemplateId
- src/components/TemplateRegistry.tsx: 随机颜色(HSL轮盘)、HTML5拖拽排序、批量JSON导入、一键载入腹腔镜模板、handleSave 补齐必填字段
- src/components/OntologyInspector.tsx: 完全重写,从store读取模板,支持模板切换和自定义分类
- src/components/VideoWorkspace.tsx: 进入时自动加载模板列表
- src/components/ProjectLibrary.tsx: 修复状态字符串 TS 严格类型报错
- 工程分析/: 更新实现方案与经验记录

Timestamp: 20260430_222830
2026-04-30 22:42:55 +08:00

23 KiB
Raw Blame History

经验记录Knowledge Base

本文件按代码编纂工作流规范,以四段式记录项目修改过程中遇到的关键问题及解决方案。
格式: A. 具体问题 / B. 产生原因 / C. 解决方案 / D. 后续如何避免


2026-04-30-00-17-44 — PyTorch CUDA + SAM2 + 封面 + 帧率 + DICOM 批量导入

A. 具体问题

  1. PyTorch 为 CPU 版本SAM2 未安装GPU 推理不可用
  2. 项目库视频卡片无封面缩略图
  3. 项目库 FPS 为硬编码 "30FPS",不显示真实原始帧率,也无法修改解析帧率
  4. 不支持 DICOM 连续帧批量导入

B. 产生原因

  1. 系统磁盘仅 24GBPyTorch CUDA wheel (~1GB) + SAM2 编译依赖导致 No space left on device
  2. 解析视频时未提取封面Project 模型无 thumbnail_url 字段
  3. 解析视频时未读取原始帧率Project 模型无 original_fps / parse_fps 字段
  4. upload 接口仅支持单文件,无批量 DICOM 上传接口Project 无 source_type 区分视频/DICOM

C. 解决方案

  1. 磁盘扩容后安装 PyTorch CUDA + SAM2
    • pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
    • pip install sam2(成功编译安装 sam2-1.1.0
    • 修正 config.pysam_model_configconfigs/sam2/sam2_hiera_t.yamlHydra 包内相对路径)
    • 验证 torch.cuda.is_available() → TrueRTX 4090 识别正常
  2. 视频封面
    • frame_parser.py 新增 extract_thumbnail(),从视频第一帧提取 640px JPEG 封面
    • media.py parse_media() 解析视频时自动上传封面到 projects/{id}/thumbnail.jpg
    • projects.py 返回 presigned URL
    • 前端 ProjectLibrary.tsx 卡片背景显示 <img> 封面
  3. 真实帧率 + 可修改解析帧率
    • models.py Project 新增 original_fps (Float), parse_fps (Float, default=30)
    • frame_parser.py get_video_fps() 用 OpenCV 读取真实帧率,parse_video() 返回 (frames, original_fps)
    • 前端 ProjectLibrary.tsx 上传视频时弹窗允许用户滑动设置 parse_fps (1-60)
    • 项目卡片显示 原 60.0fps30FPS 标签
  4. DICOM 批量导入
    • models.py Project 新增 source_type (video | dicom)
    • media.py 新增 /api/media/upload/dicom 接口,接收 List[UploadFile],上传多个 .dcm 到 uploads/{id}/dicom/
    • media.py parse_media() 支持 DICOM 模式:从 MinIO 下载整个 dicom 目录 → parse_dicom() 解析
    • 前端 ProjectLibrary.tsx 导入按钮展开菜单:导入视频 / 导入 DICOM 序列DICOM 用 <input multiple accept=".dcm">

D. 后续如何避免问题

  1. SAM2 配置路径必须用 Hydra 包内相对路径build_sam2() 使用 Hydra配置文件必须传 configs/sam2/xxx.yaml 而非绝对路径
  2. 数据库 schema 变更必须彻底清理旧表PostgreSQL drop_all() 可能因外键约束不彻底,生产环境应使用 Alembic 迁移,开发环境应手动 DROP TABLE ... CASCADE
  3. 大依赖安装必须预留足够磁盘空间PyTorch CUDA (~1GB) + SAM2 build (~500MB temp) 至少需要 5GB 可用空间
  4. 前端上传交互必须区分媒体类型:视频和 DICOM 的上传流程、文件选择器 accept、后续解析逻辑完全不同,应提供明确的模式切换

2026-04-29-23-28-13 — 视频帧显示链路全修复

A. 具体问题

  1. 项目库中没有默认视频 Data_MyVideo_1.mp4
  2. 分割工作区点击视频后画面一片黑(无影像)
  3. 导入新视频后进入工作区同样看不到视频帧

B. 产生原因

  1. 后端 lifespan 没有任何自动扫描/注册本地视频的逻辑;server.ts 的硬编码项目对前端不可见
  2. CanvasArea.tsx 硬编码了一张 Unsplash 外链,没有从 Zustand store 读取帧数据;进入工作区时不调用帧列表 API
  3. 上传流程不完整:未先创建项目再带 project_id 上传,上传后未触发 /api/media/parse 帧提取;后端 /frames 返回的是 MinIO 对象名而非可访问的 presigned URLMinIO presigned URL 的 host 为 localhost:9000,浏览器端无法访问
  4. 系统磁盘空间24GB紧张MinIO 在提取大量高清 PNG 帧时触发 XMinioStorageFull,导致帧上传失败

C. 解决方案

  1. 后端默认视频种子main.py lifespan 中启动后台线程,自动检测 Data_MyVideo_1.mp4,创建 Project → 上传 MinIO → 调用 FFmpeg 解析帧 → 注册 Frame 记录
  2. 后端帧 URL 修复projects.pylist_frames 在返回前为每个 frame.image_url 调用 get_presigned_url() 生成带签名的可访问 URL
  3. 后端 presigned URL host 修复.envMINIO_ENDPOINTlocalhost:9000 改为 192.168.3.11:9000,确保浏览器端可访问
  4. 后端 ProjectOut 增强schemas.py 添加 frame_countprojects.py 在查询时计算 len(p.frames),供前端显示帧数
  5. 后端 upload 自动创建项目media.pyupload_media 在不传 project_id 时自动以文件名创建 Project 并关联视频
  6. 前端帧加载中枢VideoWorkspace.tsxcurrentProject 变化时调用 getProjectFrames,若帧数为 0 则自动触发 parseMedia,获取后映射写入 Zustand store
  7. 前端 Canvas 真实渲染CanvasArea.tsx 接收 frameUrl prop使用 useImage(frameUrl) 加载真实帧AI 推理也使用当前帧 URL
  8. 前端时间轴真实帧FrameTimeline.tsx 从 store 读取 framescurrentFrameIndex,渲染真实帧缩略图 <img>,点击切换当前帧
  9. 前端上传链路完善ProjectLibrary.tsx 上传流程改为:创建项目 → uploadMedia(file, projectId)parseMedia(projectId) → 刷新列表
  10. 磁盘空间优化:将 frame_parser.py 的 FFmpeg 输出从 PNG (1920px, ~3MB/张) 改为 JPEG (640px, ~30KB/张),并限制默认视频只提取 100 帧,避免 MinIO 存储溢出

D. 后续如何避免问题

  1. MinIO endpoint 必须使用服务器 IP:任何生成外部可访问 URL 的服务MinIO presigned、后端 baseURL、WebSocket都必须使用服务器 LAN IP禁止 localhost
  2. 大文件/视频处理必须考虑磁盘预算:提取帧前估算总大小(帧数 × 单帧大小),必要时降低分辨率、改格式为 JPEG、限制 max_frames
  3. 前后端数据字段必须显式映射:后端 snake_case 与前端 camelCase 不一致时API 层必须做转换,不能依赖隐式兼容
  4. 上传-解析-显示链路必须闭环测试:任何涉及文件上传的功能,测试用例必须覆盖:上传 → 后端存储 → 解析 → 前端获取 → 前端渲染 的全流程

2026-04-29-23-15-26 — 上传/WS/项目库三 Bug 联修

A. 具体问题

  1. 上传成功后控制台打印 undefined,前端显示 url 为 undefined
  2. React StrictMode 下 Dashboard 页面切换时报 InvalidStateError: WebSocket is closed before the connection is established
  3. 上传完成后项目库为空,不显示新上传的项目

B. 产生原因

  1. 后端 media.py 上传接口返回字段为 {object_name, file_url, size, message},而前端 api.tsuploadMedia 直接 return response.data,调用方解构 const { url, id }urlundefined
  2. React 18 StrictMode 在开发环境下会 double-mount/unmountDashboard.tsxuseEffect cleanup 调用 progressWS.disconnect(),后者无条件执行 this.ws.close();若此时 WebSocket 仍处于 CONNECTING(状态 0调用 .close() 会抛出 InvalidStateError
  3. uploadMedia 只将文件存入 MinIO未调用 createProject 创建数据库记录,也未在成功后主动刷新项目列表

C. 解决方案

  1. api.ts: 解构 file_urlobject_name,返回 { url: file_url, id: object_name }
  2. websocket.ts: disconnect() 中增加 readyState === WebSocket.OPEN 判断,仅对已连接套接字调用 .close()
  3. ProjectLibrary.tsx: uploadMedia resolve 后调用 getProjects()setProjects() 刷新列表
  4. Dashboard.tsx: 增加 mounted refcleanup 时置 false,回调中检查 mounted,并延迟 500ms 连接避免 mount/unmount 竞态

D. 后续如何避免问题

  1. 前后端接口契约必须显式文档化:新建/修改 API 时同步更新接口文档,字段名变更需两端对齐
  2. WebSocket 生命周期防御编程:所有 .close() 调用前必须检查 readyStateconnect/disconnect 需幂等
  3. 副作用清理必须防竞态useEffect 中任何异步回调setInterval、setTimeout、event listener都需配合 mounted 或 AbortController
  4. 上传后必须刷新列表:任何创建资源的操作成功后,应主动重新拉取列表或返回完整资源对象写入本地状态

2026-04-28-22-55-15 — 建立代码编纂工作流

A. 具体问题

项目缺少标准化的代码修改流程,导致需求管理、方案设计、测试验证、知识沉淀等环节可能遗漏,影响项目质量和可维护性。

B. 产生原因

项目初期以快速原型为主,未建立正式的工程化管理流程;随着功能增加,需要更严谨的变更管理机制。

C. 解决方案

建立完整的代码编纂工作流,包含 10 个阶段时间戳记录、工程分析、需求分析、实现方案人工审核、测试方案人工审核、执行前准备阅读经验记录、方案执行、经验沉淀、Gitea 备份、重新部署。

D. 后续如何避免问题

  • 后续所有项目修改严格按工作流执行
  • 每次修改前检查工作流检查表
  • 定期回顾经验记录,提取共性预防措施

2026-04-28-22-55-15 — 执行环境 Node.js 缺失

A. 具体问题

执行 npm run lintnpm run build 时提示 npm: command not found,当前 Shell 环境未安装 Node.js 运行时。

B. 产生原因

AI 助手运行的容器/环境与项目实际开发环境分离,后者才装有 Node.js 和 npm。

C. 解决方案

  • 文档创建和 git 操作可在 AI 环境中完成
  • 构建验证(npm run lintnpm run buildnpm start)需由用户在本地开发环境执行,或 AI 提供精确命令由用户自行运行
  • 实际解决: 用户提供了 sudo 权限和密码后AI 通过 NodeSource 安装了 Node.js 22.xcurl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash + sudo apt install -y nodejs),随后成功执行了完整部署流程
  • 在经验记录中标注此限制和解决方案,提醒后续流程

D. 后续如何避免问题

  • 每次执行阶段 6 和阶段 9 前,先检查 which npm
  • 如 npm 不可用,向用户申请 sudo 权限安装 Node.js或使用项目预设的容器/CI 环境
  • 如用户无法提供 sudo则提供精确的手动执行命令清单
  • 考虑在 CI/CD 流程中统一构建环境

2026-04-29-21-27-10 — 组件目录扁平化重构

A. 具体问题

src/components/ 下 7 个子目录共 11 个组件文件扁平化到根目录时,需要同步更新多处 import 相对路径,存在遗漏风险。

B. 产生原因

组件文件在子目录中时,引用 lib/utils.ts 的路径为 ../../lib/utils,引用其他组件的路径为 ../workspace/XXX;扁平化到根目录后,这些路径需分别变更为 ../lib/utils./XXX。涉及文件多、路径变体多,手工逐一修改容易遗漏。

C. 解决方案

  • 重构前先通过 grep 全局扫描所有 import 语句,建立完整的"文件-旧路径-新路径"映射表
  • 移动文件和修改路径分两步执行,每步完成后都用 grep 验证旧路径模式是否完全消失
  • 最后运行 npm run lintnpm run build 作为最终校验TypeScript 编译器会捕获任何遗漏的路径错误

D. 后续如何避免问题

  • 任何涉及文件移动的 refactoring都必须先全局 grep 所有相对路径引用,形成清单后再执行
  • 执行后立即用 grep 反向验证旧路径模式残留
  • 始终将 npm run lint 作为路径重构后的强制检查步骤

2026-04-29-21-51-19 — 全栈系统改造FastAPI + SAM2 + PostgreSQL + Redis + MinIO

A. 具体问题

  1. 将纯前端 React 应用改造为全栈系统时工程涉及后端框架替换、数据库设计、对象存储、AI 推理引擎、前端状态管理重构等多个复杂模块,单次执行工程量大。
  2. 系统磁盘空间24G不足PyTorch CUDA 版本(>2GB和 sam2 pip 包编译(需下载 CUDA 工具链 + 编译 C++ 扩展)均因 OSError: No space left on device 失败。
  3. MinIO 对象存储在磁盘紧张时报 XMinioStorageFull,导致文件上传失败。
  4. 前端 Agent 执行时因目录扁平化后子目录不存在,产生多次 File not found 错误。

B. 产生原因

  1. 项目改造范围超出单次会议合理容量,涉及 15+ 后端文件、10+ 前端文件、4 个基础设施服务、1 个 AI 模型栈。
  2. 系统盘仅有 24GBconda 环境2GB、node_modules222MB、模型权重1.5GB、MinIO 帧文件1.4GB)叠加后迅速耗尽空间。
  3. sam2 的 pip 包依赖 torch>=2.5.1pip 会尝试重新下载完整 torch wheel530MB作为 build dependency即使 torch 已安装。
  4. 前端 Agent 的 prompt 中未明确说明组件目录已扁平化Agent 仍尝试读取旧的子目录路径。

C. 解决方案

  1. 任务拆分 + 并行 Agent: 将后端和前端代码编写拆分为两个独立 Agent 并行执行,基础设施安装与代码编写并行推进,显著缩短总耗时。
  2. 磁盘管理策略:
    • 安装 PyTorch CPU 版本替代 CUDA 版本(占用更小)
    • 只保留 sam2_hiera_tiny.pt149MB删除其他大模型
    • 清理 conda pkgs 缓存(释放 600MB+
    • 删除 MinIO 中解析生成的临时帧文件(释放 1.4GB
  3. sam2 安装降级: 当前环境以 stub 模式运行,提供 install_sam2.sh 脚本供用户在扩展磁盘后执行真实安装。
  4. API 路径修复: 后端添加 /api/auth/login 路由,修复前端 api.ts 中 /api/predict/api/ai/predict 的路径不匹配。
  5. MinIO API 适配: minio 7.2.x 中 presigned_url() 已改为 get_presigned_url(),需从 datetime.timedelta 传入 expires。

D. 后续如何避免问题

  1. 大型改造前先做磁盘评估: 执行 df -h 确认可用空间 > 5GB 再开始安装大型依赖。
  2. AI 模型依赖延迟加载: 所有 AI 推理引擎必须实现 graceful fallback模型缺失时不阻塞系统启动。
  3. Agent prompt 需同步最新目录结构: 给 Agent 的上下文必须包含当前真实的文件路径,避免 File not found
  4. 构建依赖隔离: 使用 --no-build-isolation--no-deps 安装源码包,避免 pip 重复下载已安装的依赖。
  5. MinIO 空间监控: 定期清理解析产生的临时帧文件,或配置 MinIO 使用独立大容量数据盘。

2026-04-29-22-29-26 — README.md 完善

A. 具体问题

项目全栈改造完成后README.md 仍为旧版 AI Studio 模板,未反映真实系统架构和部署流程,新用户无法按文档独立完成部署。

B. 产生原因

前期聚焦功能开发,文档滞后;改造涉及后端/前端/基础设施/AI 模型多个层级,文档编写工作量大。

C. 解决方案

按代码编纂工作流,编写需求分析→实现方案→测试方案,然后一次性重写 README.md涵盖系统架构、技术栈、目录结构、分步部署命令、环境变量、访问凭证、常见问题。

D. 后续如何避免问题

  • 任何架构级变更后,同步更新 README.md
  • 将 README 纳入代码审查清单
  • 新成员入职时按 README 走通部署流程作为验收标准

2026-04-29-22-37-36 — 登录报错 ERR_CONNECTION_REFUSED

A. 具体问题

用户通过浏览器访问前端并点击登录时,控制台报错 POST http://localhost:8000/api/auth/login net::ERR_CONNECTION_REFUSED,登录失败。

B. 产生原因

  1. 前端 api.tsbaseURL 硬编码为 http://localhost:8000
  2. 用户通过局域网 IPhttp://192.168.3.11:3000)访问前端,而非 http://localhost:3000
  3. 浏览器运行前端代码时,将 localhost 解析为用户本地机器(而非服务器),向用户本地 8000 端口发请求
  4. 用户本地 8000 端口无服务TCP 连接被拒绝
  5. 同时后端 CORS 配置仅允许 http://localhost:3000,未允许 IP 地址访问

C. 解决方案

  1. src/lib/api.tsbaseURLhttp://localhost:8000 改为服务器实际 IP http://192.168.3.11:8000
  2. backend/config.pycors_origins["http://localhost:3000"] 扩展为 ["http://localhost:3000", "http://192.168.3.11:3000"]
  3. 重启后端服务使 CORS 生效,重新构建前端使 baseURL 生效

D. 后续如何避免问题

  1. 部署时统一使用服务器实际 IP 替代 localhost避免浏览器端解析歧义
  2. 前端 baseURL 应支持环境变量配置(如 VITE_API_BASE_URL),不同环境注入不同值
  3. 后端 CORS origins 应使用配置化列表,支持开发/测试/生产多环境
  4. 在 README 中明确说明访问地址,提醒用户必须使用服务器 IP 而非 localhost

2026-04-29-22-49-38 — WebSocket 404 + 项目状态异常 + 导入按钮无响应

A. 具体问题

  1. 控制台报错 WebSocket connection to 'ws://localhost:8000/ws/progress' failed
  2. 项目库中"测试视频项目"状态显示为"异常"(红色)
  3. "导入多媒体资源"按钮点击无反应

B. 产生原因

  1. websocket.ts 仍为 ws://localhost:8000/ws/progress,未随前端 baseURL 一起改为服务器 IP
  2. FastAPI 后端未实现 /ws/progress WebSocket 路由
  3. Uvicorn 缺少 WebSocket 支持库(websocketswsproto 未安装)
  4. 后端 Project 模型默认状态为 "pending",前端只识别 "Ready" / "Parsing",其他状态均显示"异常"
  5. ProjectLibrary.tsx 中"导入多媒体资源"按钮为纯静态 <button>,无 onClick 事件和隐藏的 <input type="file">

C. 解决方案

  1. websocket.ts URL 改为 ws://192.168.3.11:8000/ws/progress
  2. backend/main.py 添加 @app.websocket("/ws/progress") 路由 + ConnectionManager 连接管理
  3. pip install websockets 为 Uvicorn 提供 WebSocket 协议支持
  4. 后端 Project.status 默认值从 "pending" 改为 "Ready"
  5. 前端增加 'pending' / 'Pending' 状态分支显示"待处理"
  6. 为导入按钮添加 onClick + useRef<HTMLInputElement> + 隐藏文件输入框,调用 uploadMedia API

D. 后续如何避免问题

  1. 任何涉及网络地址的配置HTTP / WebSocket必须同步修改不能遗漏
  2. 新增 WebSocket 功能时,同步检查 Uvicorn 是否安装了协议支持库
  3. 前后端状态枚举值必须对齐,或后端返回时做映射转换
  4. 所有按钮类 UI 元素必须绑定事件处理器,禁止纯装饰性按钮

2026-04-29-23-02-56 — Logo 部署 + Favicon 404

A. 具体问题

  1. Sidebar.tsx 引用 /Logo.png 但文件不存在logo 无法显示
  2. 浏览器控制台报 favicon.ico 404

B. 产生原因

  1. logo_square.png 位于项目根目录,但 Vite 不会自动将根目录文件暴露为静态资源
  2. 前端代码引用路径为 /Logo.png(首字母大写),与实际文件名 logo_square.png 不匹配
  3. index.html 无 favicon 声明,浏览器默认请求 /favicon.ico

C. 解决方案

  1. 创建 public/ 目录Vite 原生支持,自动暴露到根 URL
  2. logo_square.png 复制为 public/logo.png
  3. Sidebar.tsx 引用路径改为 /logo.png
  4. index.html 添加 <link rel="icon" type="image/png" href="/logo.png" />

D. 后续如何避免问题

  1. 静态资源图片、字体、favicon统一放入 public/ 目录
  2. 资源文件名与代码引用严格保持大小写一致
  3. 每个项目初始化时都配置好 favicon避免浏览器自动请求不存在的 .ico

新增经验请追加到文件末尾,保持时间倒序或正序均可,但需确保每条经验包含完整的 A/B/C/D 四段。


2026-04-30-22-38 — 模板库保存失效 + 颜色重复 + 拖拽排序 + OntologyInspector 联动

A. 具体问题

  1. TemplateRegistry.tsx 点击保存无反应,模板数据未写入后端
  2. addClass() 所有新类别颜色相同(硬编码 #06b6d4
  3. z-index 仅显示文本,无拖拽调整功能
  4. OntologyInspector.tsx 完全硬编码 mock 数据,未与模板库联动
  5. 后端 seed 脚本启动时报 descriptionTemplate 的无效关键字参数

B. 产生原因

  1. 前端 updateTemplatePUT 请求,但后端 @router.patch 只接受 PATCH → 405
  2. createTemplate payload 未传 color/z_index,但后端 TemplateBase 要求 color 必填
  3. TemplateUpdate schema 缺少 classes/rules 字段update 时分类数据被丢弃
  4. Template ORM 模型缺少 descriptionseed 脚本直接传 description=... 导致 TypeError
  5. api.ts_mapTemplate 返回了 color/z_index,但前端 Template TS 接口未定义这些字段,导致 TS 编译错误被忽略后引发运行时字段缺失
  6. OntologyInspector 从未接入 store 或 API完全独立维护一份 mock 数据

C. 解决方案

  1. 对齐 HTTP 方法: api.ts updateTemplate 改为 apiClient.patch(...)
  2. 补齐必填字段: handleSave 中构造 payload 时始终携带 colorz_index
  3. 扩展 Update Schema: backend/schemas.py TemplateUpdate 添加 classesrules 字段
  4. 数据库 Schema 补丁: ALTER TABLE templates ADD COLUMN description TEXT; + models.py 添加 description = Column(Text, nullable=True)
  5. TS 类型对齐: _mapTemplate 只返回 Template 接口中定义的字段,避免隐式 any
  6. HTML5 拖拽排序: 用 draggable + dataTransfer.setData 实现项间拖拽,释放后重算 z-index数组倒序 ×10
  7. OntologyInspector 重写: 从 store 读取 templates/activeTemplateId,顶部加模板选择器,支持自定义分类添加
  8. 工作区预加载: VideoWorkspace 进入时若 templates 为空自动 getTemplates()

D. 后续如何避免问题

  1. 前后端 HTTP 方法必须严格对齐: FastAPI @router.patch 只响应 PATCH前端不能用 PUT/POST 代替,否则报 405
  2. Schema 变更必须双向同步: 后端 BaseModel 添加字段后,前端 payload 类型、ORM 模型、数据库表必须同时更新
  3. TS 接口必须与 API 响应严格一致: _mapTemplate 返回的字段如果不在 Template 接口中,必须通过 & 扩展接口或过滤字段,避免运行时丢失数据
  4. Mock 数据必须尽早替换为真实数据流: 任何硬编码的 mock 数据在联调阶段都是技术债,应在功能开发初期就接入 store/API
  5. seed 脚本必须与 ORM 模型严格一致: 新增模型字段后seed 逻辑也要同步更新,否则启动即报错