# AGENTS.md — AI 编码助手项目指南

> 本文件面向 AI 编码助手。阅读者应假设对该项目一无所知。以下信息基于当前仓库实际文件、脚本和源码；不要把早期设计目标当作已实现事实。任何代码和功能修改都要落实到文档和测试上，如果生成git commit信息，要逐个列点把所有修改都列上，重要的、大的修改放前面，不重要的、小的修改列在后面。

---

## 项目概述

本项目是一个**语义分割系统**（Semantic Segmentation System），当前形态是 React 前端 + FastAPI 后端的全栈 Web 应用，用于视频/DICOM 医学影像上传、显式视频生成帧、交互式 Canvas 标注、视频片段传播、GT mask 导入、可选 SAM 2.1 tiny/small/base+/large 辅助分割、模板分类管理和标注导出。SAM 3 相关源码和安装脚本保留在仓库中，但由于当前产品不提供文本提示，前端入口已隐藏，后端 registry 也不暴露 `sam3` 模型。

- **项目名称**: `react-example`（`package.json` 中的 `name`）
- **前端入口**: `src/main.tsx` → `src/App.tsx`
- **前端服务入口**: `server.ts`（Express + Vite 中间件 / 生产静态服务；旧版 mock API 已清理）
- **后端入口**: `backend/main.py`（FastAPI）
- **默认前端地址**: `http://localhost:3000`
- **默认后端地址**: `http://localhost:8000`
- **前端 API 配置**: `src/lib/config.ts`，优先读取 `VITE_API_BASE_URL`，未配置时按当前浏览器 hostname 推导 `http://<host>:8000`
- **业务文档**: `语义分割系统构建方案.docx`（项目根目录）

---

## 技术栈

| 层级 | 技术 |
|------|------|
| 前端框架 | React 19 + TypeScript 5.8 |
| 构建工具 | Vite 6 |
| 前端样式 | TailwindCSS 4 + 自定义深色主题 |
| 前端状态 | Zustand（`src/store/useStore.ts`） |
| 前端请求 | Axios（`src/lib/api.ts`） |
| 实时通信 | WebSocket 客户端（`src/lib/websocket.ts`） |
| Canvas 渲染 | Konva + react-konva + use-image |
| 几何布尔运算 | polygon-clipping |
| 图标库 | lucide-react |
| 动画依赖 | motion（在 `package.json` 中声明） |
| AI SDK 依赖 | `@google/genai`（在 `package.json` 中声明；当前业务源码未直接调用） |
| 后端框架 | FastAPI + Uvicorn |
| ORM / 数据库 | SQLAlchemy + PostgreSQL |
| 缓存 / 队列 Broker | Redis |
| 后台任务 | Celery worker |
| 对象存储 | MinIO |
| AI 推理 | 当前启用 SAM 2.1 + PyTorch，可选 tiny/small/base+/large；`GET /api/ai/models/status` 返回真实 GPU 和各 SAM 2.1 变体状态；SAM 3 源码保留但产品入口禁用 |
| 视频 / 影像处理 | FFmpeg / OpenCV / pydicom |
| 运行时 | Node.js ES Modules；Python 3.11 后端环境；历史保留的 `sam3` Python 3.12 conda 环境不是当前必需运行条件 |

---

## 项目结构

```
Seg_Server/
├── server.ts                      # Express + Vite 前端入口；不再提供旧版 /api mock
├── index.html                     # SPA HTML 入口
├── vite.config.ts                 # Vite 配置；含 @/* 路径别名与 DISABLE_HMR 逻辑
├── tsconfig.json                  # TypeScript 配置；@/* 映射到项目根目录
├── package.json                   # npm 依赖与脚本
├── .env.example                   # AI Studio/Gemini 前端环境变量模板
├── metadata.json                  # AI Studio 元数据
├── public/
│   └── logo.png                   # Sidebar 使用的 /logo.png
├── doc/                           # 当前实现审计、接口契约和后续实施文档
├── start_services.sh              # 本地一键启动 PostgreSQL/Redis/MinIO/FastAPI/Celery/前端
├── restart_dev_services.sh        # 本地开发重启脚本；重启 FastAPI/Celery/前端并检查 3000/8000
├── backend/                       # FastAPI 后端
│   ├── main.py                    # 应用入口、lifespan、CORS、路由注册、WebSocket
│   ├── config.py                  # Pydantic Settings；读取 backend/.env
│   ├── database.py                # SQLAlchemy Engine / Session
│   ├── models.py                  # User/Project/Frame/Template/Annotation/Mask/AuditLog/ProcessingTask ORM
│   ├── schemas.py                 # Pydantic 请求/响应模型
│   ├── minio_client.py            # MinIO 上传、下载、预签名 URL
│   ├── redis_client.py            # Redis 连接封装
│   ├── celery_app.py              # Celery app 配置
│   ├── worker_tasks.py            # Celery 任务入口
│   ├── download_sam2.py           # SAM 2 权重下载脚本
│   ├── setup_sam3_env.sh          # 历史保留的 SAM 3 独立 Python 3.12 环境安装脚本；当前产品入口禁用
│   ├── requirements.txt           # Python 依赖
│   ├── routers/
│   │   ├── auth.py                # /api/auth/login、/api/auth/me、鉴权依赖
│   │   ├── admin.py               # /api/admin/users、/api/admin/audit-logs、/api/admin/demo-factory-reset
│   │   ├── projects.py            # /api/projects 与 /api/projects/{id}/frames
│   │   ├── templates.py           # /api/templates
│   │   ├── media.py               # /api/media/upload、/upload/dicom、/parse
│   │   ├── ai.py                  # /api/ai/predict、/propagate、/propagate/task、/models/status、/auto、/annotate
│   │   └── export.py              # /api/export/{project_id}/coco、/masks
│   └── services/
│       ├── frame_parser.py        # FFmpeg/OpenCV 拆帧、pydicom 读片、帧上传
│       ├── propagation_task_runner.py # Celery 自动传播任务 runner
│       ├── sam2_engine.py         # SAM 2.1 变体选择、单帧推理和 video predictor 传播封装
│       ├── sam3_engine.py         # 历史保留的 SAM 3 桥接实现；当前未接入 registry
│       ├── sam3_external_worker.py # 历史保留的独立 sam3 helper；当前未被产品入口调用
│       └── sam_registry.py        # 当前暴露 SAM 2.1 变体、GPU 状态与推理分发
└── src/                           # React 前端
    ├── main.tsx                   # React StrictMode 挂载
    ├── App.tsx                    # 登录拦截 + 模块切换
    ├── index.css                  # TailwindCSS 导入 + 全局样式
    ├── store/useStore.ts          # Zustand 全局状态
    ├── lib/api.ts                 # Axios API 封装
    ├── lib/websocket.ts           # 解析进度 WebSocket 客户端
    ├── lib/utils.ts               # cn() 工具函数
    └── components/                # 扁平化组件目录
        ├── Login.tsx
        ├── Sidebar.tsx
        ├── Dashboard.tsx
        ├── ProjectLibrary.tsx
        ├── VideoWorkspace.tsx
        ├── CanvasArea.tsx
        ├── ToolsPalette.tsx
        ├── OntologyInspector.tsx
        ├── FrameTimeline.tsx
        ├── AISegmentation.tsx
        ├── TransientNotice.tsx
        └── TemplateRegistry.tsx
```

以下目录/文件通常是运行产物或本地数据，已在 `.gitignore` 中忽略：`node_modules/`、`dist/`、`models/`、`uploads/`、`frames/`、`Data_*/`、`*.mp4`、`*.dcm`、`*.7z`、`backend/.env`、日志文件等。

`doc/` 目录是当前项目的事实文档入口。修改功能前优先查看：

- `doc/03-frontend-element-audit.md`：哪些前端元素是真功能，哪些是 Mock/UI-only。
- `doc/04-api-contracts.md`：前后端接口契约，以及当前不一致点。
- `doc/05-implementation-plan.md`：建议的后续实施顺序。
- `doc/10-installation.md`：完整安装部署流程，覆盖 PostgreSQL、Redis、MinIO、FastAPI、Celery、前端和 SAM 2.1 权重。

---

## 构建与运行命令

### 前端 / Node 入口

```bash
npm install

# 开发模式：运行 tsx server.ts，Express 集成 Vite middleware，端口 3000
npm run dev

# 生产构建：输出 dist/
npm run build

# Vite 预览
npm run preview

# 生产模式运行 server.ts，服务 dist/
npm start

# TypeScript 类型检查
npm run lint

# 删除 dist/
npm run clean
```

### FastAPI 后端

```bash
cd backend
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
```

### 一键启动

```bash
./start_services.sh
```

该脚本会依次检查/启动 PostgreSQL、Redis、MinIO、FastAPI 后端、Celery worker 和前端。

### 开发重启

```bash
./restart_dev_services.sh
```

本地代码改完后不要靠手工试进程。前端 `src/` 通常由 Vite 热更新；凡是修改 FastAPI 后端、Celery worker、拆帧/SAM runner 或任务逻辑，完成验证后都要运行 `./restart_dev_services.sh`，确保运行态加载最新代码。`restart_dev_services.sh` 会停止旧 FastAPI/Celery/前端进程，用独立后台进程重启三者，并检查 `http://localhost:8000/health` 和 `http://localhost:3000`。

---

## 运行时架构

### 前端

- 单页应用，无路由库；模块切换由 `useStore().activeModule` 控制。
- 模块值包括：`dashboard`、`projects`、`ai`、`workspace`、`templates`。
- 默认模块是 `workspace`。
- 未登录时渲染 `Login`。
- 登录成功后后端返回签名 JWT，token 写入 `localStorage`，Axios request interceptor 会附加 `Authorization: Bearer <token>`。
- `App.tsx` 在已有 token 或登录成功后调用 `/api/auth/me` 恢复当前用户，再调用 `getProjects()` 初始化当前用户项目列表。

### 后端

- 主后端是 `backend/main.py` 的 FastAPI 服务。
- `lifespan` 启动时会：
  - 创建数据库表；
  - 检查/创建 MinIO bucket `seg-media`；
  - 测试 Redis 连接；
  - 后台 seed 默认模板；
  - 如果本地存在 `Data_MyVideo_1.mp4`，后台 seed 默认演示项目并拆前 100 帧。
- API 路由包括：
  - `POST /api/auth/login`
  - `GET /api/auth/me`
  - `GET/POST/PATCH/DELETE /api/admin/users`
  - `GET /api/admin/audit-logs`
  - `POST /api/admin/demo-factory-reset`
  - `GET/POST/PATCH/DELETE /api/projects`
  - `GET/POST /api/projects/{project_id}/frames`
  - `GET/POST/PATCH/DELETE /api/templates`
  - `POST /api/media/upload`
  - `POST /api/media/upload/dicom`
  - `POST /api/media/parse`
  - `GET /api/tasks`
  - `GET /api/tasks/{task_id}`
  - `POST /api/tasks/{task_id}/cancel`
  - `POST /api/tasks/{task_id}/retry`
  - `POST /api/ai/predict`
  - `POST /api/ai/smooth-mask`
  - `POST /api/ai/propagate`
  - `POST /api/ai/propagate/task`
  - `GET /api/ai/models/status`
  - `POST /api/ai/auto`
  - `POST /api/ai/annotate`
  - `POST /api/ai/import-gt-mask`
  - `GET /api/ai/annotations`
  - `PATCH/DELETE /api/ai/annotations/{annotation_id}`
  - `GET /api/dashboard/overview`
  - `GET /api/export/{project_id}/coco`
  - `GET /api/export/{project_id}/masks`
  - `GET /health`
  - `WS /ws/progress`

### 存储

- PostgreSQL 存储项目、帧、模板、标注、mask 和后台任务元数据。
- MinIO 存储上传视频、DICOM、拆出的帧、缩略图等对象；前端展示使用预签名 URL。
- Redis 当前作为 Celery broker/result backend，并用于连接检查。

---

## 主要业务流程

1. 登录：`Login.tsx` 调用 `POST /api/auth/login`，后端用 `users` 表和密码哈希校验凭证，默认启动时会种子化开发管理员 `admin / 123456`；成功后返回签名 JWT，`GET /api/auth/me` 可读取当前用户；角色包括 `admin`、`annotator`、`viewer`，写入类业务接口要求 `admin/annotator`，用户管理后台要求 `admin`。
2. 用户管理：`Sidebar` 仅对 `admin` 显示“用户管理”，`UserAdmin.tsx` 调用 `/api/admin/users` 新增、停用/启用、改角色、改密码和删除无项目用户，并调用 `/api/admin/audit-logs` 展示登录和管理操作审计；演示部署可通过“恢复演示出厂设置”二次确认后调用 `/api/admin/demo-factory-reset`，清空演示数据，只保留默认 admin 和一个尚未生成帧的演示视频项目。
3. 项目管理：`ProjectLibrary.tsx` 调用项目 API 创建项目、拉取列表、删除项目；删除当前项目后会清空工作区当前项目、帧、mask 和选区。
4. 上传资源：视频走 `/api/media/upload`，只上传源文件并关联项目，不自动拆帧；DICOM 批量走 `/api/media/upload/dicom`。
5. 生成帧入队：用户在项目库点击“生成帧”，选择目标 FPS 后前端调用 `/api/media/parse`；后端创建 `ProcessingTask` 并投递 Celery，接口支持 `parse_fps`、`max_frames` 和 `target_width` 标准帧序列参数；项目库和模板库的成功/失败短反馈使用非阻塞 `TransientNotice`，会自动消失。
6. worker 执行：Celery worker 用 FFmpeg 优先拆视频帧，失败后用 OpenCV fallback，DICOM 使用 pydicom；视频帧按 `frame_%06d.jpg` 连续命名并记录 `timestamp_ms`、`source_frame_number` 和任务 `frame_sequence` 元数据。
7. 帧展示：`VideoWorkspace.tsx` 调用 `/api/projects/{id}/frames`，`CanvasArea.tsx` 和 `FrameTimeline.tsx` 显示当前帧与时间轴缩略图；`CanvasArea` 会按容器和帧尺寸默认居中放大底图并保留边距；`FrameTimeline` 会根据已保存标注回显到 `Mask.metadata` 的传播来源，把自动传播生成的帧在视频处理进度条显示为蓝色区段，人工/AI 标注帧显示红色竖线；每次自动传播成功处理帧后，`VideoWorkspace` 会把本次传播范围作为当前会话历史片段传给 `FrameTimeline`，在视频处理进度条上叠加同一蓝色系、最新传播最亮、旧传播逐次变暗且第 5 次及更早统一为阈值旧记录色的纯色条；视频处理进度条和红/蓝标识可点击跳转到对应帧；底部缩略图中人工/AI 标注帧用红色边框、自动传播/推理帧用蓝色边框，同一帧同时具备两种状态时红色标注边框优先保留，蓝色传播状态以内描边表达；当前帧仍以青色外框高亮优先；若当前帧同时是人工/AI 标注帧，则在青色外框内增加红色内描边，固定为外层当前帧、内层人工/AI 标注；进入自动传播、清空遮罩或特定范围帧导出选择模式时，播放进度条和视频处理进度条会显示黄色范围框，并可点击/拖拽选择起止帧；前端 `Frame` 会保留后端返回的帧序列时间戳和源帧号。
8. 手工标注：`CanvasArea.tsx` 支持多边形、矩形、圆、画笔和橡皮擦生成/编辑 polygon mask；多边形可按 Enter 或点击首节点闭合；画笔/橡皮擦可在左侧工具栏调整大小，画笔要求右侧语义分类树已有选中类别，画出的圆形连续笔触会在鼠标松开时一次性 union 成 mask，若与当前选中 mask 连通则自动合并到该 mask，橡皮擦要求已选中 mask 并在松开时从该 mask 中 difference 扣除；未选中特定 mask 时，Canvas 会按右侧语义分类树拖拽得到的内部覆盖优先级从低到高渲染 mask，使高优先级类别显示在上层；Canvas 左上角工具上下文提示会在切换工具或操作状态变化时短暂显示，数秒后自动隐藏，避免长期遮挡底图；工具栏有“调整多边形”入口，左侧 `ToolsPalette` 使用紧凑垂直布局并在高度不足时自身滚动，且在“重叠区域去除”之后提供紫色“导入 GT Mask”入口；工作区左侧工具栏不展示 AI 页的正向选点、反向选点和边界框选，也不重复放置撤销/重做；点击 mask 后可按住顶点直接拖动并实时更新 polygon，顶点/seed point 拖拽结束不会触发 Stage 平移或重置 Canvas 视口；也可删除 polygon 顶点、通过边中点或双击边界插入新顶点，并能选择编辑多 polygon mask 的单个子区域；选中整块 mask 可用 Delete/Backspace 删除，已保存 mask 会同步后端删除；区域合并/去除会隐藏编辑手柄并显示已选数量，第一个选中的主区域用黄色实线轮廓，后续参与合并/扣除的区域用红色虚线轮廓，使用 `polygon-clipping` 做 union/difference，内含去除结果用 even-odd 规则渲染 hole；Zustand 维护 `maskHistory/maskFuture` 支持撤销/重做。
9. AI 分割：侧栏和工作区工具栏的 AI 智能分割入口使用 Bot + Sparkles 组合图标强化 AI 识别；前端工具包括 SAM 2.1 变体选择、正向点、反向点和框选；AI 画布会按容器和当前帧尺寸默认居中放大底图并保留边距；工作区和 AI 页面都可点击已有提示点删除单点，AI 页面也可删除最近锚点、删除选中候选或清空本页锚点；这些删除入口会限制在当前提示点/本页 AI 候选范围内，避免误删工作区已有 mask。SAM 2.1 框选会建立候选 mask，后续正/反点通过 `interactive` prompt 携带原始框和累计点细化同一个候选 mask；AI 页面框选会先固化 `promptBox`，执行分割时只框选发送 `box` prompt，框选后继续加正/反点发送 `interactive` prompt；重复执行高精度分割会替换上一次 AI 页候选，只保留最新一个候选。包含反向点时工作区会传 `options.auto_filter_background=true` 和 `min_score=0.05`，如果后端过滤为空则移除旧候选 mask。后端 `ai.py` 期望按 `image_id`、`prompt_type`、`prompt_data`、`model` 和可选 `options` 调用 SAM registry。当前 registry 暴露 `sam2.1_hiera_tiny`、`sam2.1_hiera_small`、`sam2.1_hiera_base_plus`、`sam2.1_hiera_large`，并兼容 `sam2` 作为 tiny 别名；`model=sam3` 会被拒绝，`semantic` 文本提示也被禁用。SAM 2.1 支持点/框/interactive/自动分割和 video predictor 传播；多候选默认只采用最高分区域，避免重叠候选同时显示；AI 页面只渲染本页最新生成的候选 mask，不会把工作区已有 mask 带入 AI 画布；AI 页面生成的 mask 会写入全局 `masks` 并自动选中，右侧分类树可直接改标签，推送到工作区会切到“调整多边形”并保留选择和当前帧视角。`options.crop_to_prompt` 可对点/框/interactive prompt 做局部裁剪推理并回映射，`options.auto_filter_background` 可按分数和负向点过滤结果。
10. 视频片段传播：工作区以当前打开帧作为参考帧，使用该帧全部 mask 作为 seed，并用传播起始帧和传播结束帧指定追踪范围；用户可直接修改数字框，也可点击“自动传播”进入时间轴范围选择模式，在播放进度条或视频处理进度条上点击/拖拽选择范围，再点击“开始传播”。工作区顶栏有独立“传播权重”选择器，可为本次传播二次选择 SAM 2.1 tiny/small/base+/large 权重，不提供 SAM2/SAM3 家族切换，也不影响 AI 单帧分割权重；前端提交传播前会先保存当前项目中的 draft/dirty mask，使 seed 优先带稳定的后端 `source_annotation_id`，再按传播权重 id、seed mask、seed 来源 id 和前/后方向组装 `steps` 并调用 `POST /api/ai/propagate/task` 创建 `propagate_masks` 后台任务；后端入队时会规范化/校验权重 id 并把规范化后的 id 写入任务 payload/result；Celery worker 顺序执行各 step，避免多个视频 tracker 并发抢占 GPU；每个 step 会根据 seed 来源 id、方向和 seed 签名做幂等判断，同权重且未改变的 seed 直接跳过，已改变或换用其他权重的 seed 会先删除同源旧自动传播标注再重传；旧版本用前端临时 `source_mask_id` 生成的传播标注会按同一参考帧、方向和语义信息兼容清理；中间帧人工新增/修改同一物体后重新传播时，后端会在写入目标帧新结果前按语义和空间重叠清理旧传播结果，且写入前清理不受旧结果传播方向限制；后端按项目帧序列下载片段帧，当前使用所选 SAM 2.1 权重变体的 `SAM2VideoPredictor.add_new_mask()` + `propagate_in_video()`，并把后续帧结果保存为 `Annotation`；若历史或外部 seed 仍带 `geometry_smoothing`，forward/backward 两个方向的传播结果保存前仍会应用同一参数；当前工作区平滑按钮应用后会直接改写实际 polygon，后续传播以新几何参与签名和追踪。工作区轮询 `GET /api/tasks/{task_id}` 展示进度并刷新标注，Dashboard 也能显示/取消/重试传播任务。
11. GT 导入：工作区左侧工具栏“导入 GT Mask”调用 `/api/ai/import-gt-mask`；选择文件后前端会显示导入结果预览，并让用户决定未知 maskid 处理方式，可舍弃未知类别，也可导入为“未定义类别”等待重新命名。后端用 `cv2.IMREAD_UNCHANGED` 读取 mask，避免导出的低数值/16-bit `GT_label图` 被压成 0；GT 图片必须是灰度 maskid 图，或 RGB 三通道完全相同的 `[X,X,X]` maskid 图，0 为背景、X 为 maskid，不符合时返回明确错误；灰度/RGB 等通道图按模板 `maskId` 匹配类别，超出现有类别时按 `unknown_color_policy` 处理；如果 mask 图片尺寸和当前帧不同，会按当前帧长宽最近邻拉伸后再提取区域；每个连通域生成 polygon 标注，并用 distance transform 生成 seed point；前端回显 seed point，拖动后可归档更新。
12. 模板管理：`TemplateRegistry.tsx` 管理分类、颜色、maskid 和内部覆盖顺序；`OntologyInspector.tsx` 在工作区显示当前模板分类树，也支持拖拽调整内部覆盖顺序。maskid 只作为 GT_label/类别 ID，不参与排序。
13. 导出：工作区使用统一“分割结果导出”入口，导出前先保存待归档 mask；用户可选择整体视频、特定范围帧或当前图片，默认导出范围为当前图片，并勾选分开二值 mask、GT_label 黑白图、Pro_label 彩色图和 Mix_label 原图叠加图。选择特定范围帧时，可直接修改起止帧输入框，也可在播放进度条或视频处理进度条上点击/拖拽选择导出范围；选择 Mix_label 时可调透明度，默认 0.3，并显示当前/待导出第一帧预览。下载 ZIP 文件名使用 `{项目库项目名}_seg_T_{起始时间戳}-{结束时间戳}_P_{起始项目帧序号}-{结束项目帧序号}.zip`，项目名来自 `Project.name` 并替换文件系统不安全字符，时间戳格式为 `0h00m00s000ms`，帧号使用项目抽帧后的 1-based 顺序而非原视频帧号。后端保留兼容的 COCO JSON 和 PNG mask ZIP 接口，同时新增统一结果 ZIP；统一 ZIP 固定包含 `annotations_coco.json`、`maskid_GT像素值_类别映射.json` 和 `原始图片/`；导出时 GT_label 像素值使用类别真实 `maskid`，缺失 `maskid` 的旧标注才补下一个可用值，保证导出的 GT_label 可按同一模板再导入；选择分开 mask 时输出 `分开Mask分割结果/{视频名称_时间戳_项目帧序号}_分别导出/{视频名称_时间戳_项目帧序号}_{类别名称}_maskid{maskid}.png`，同一帧同一类别合并为一张图；选择 GT_label/Pro_label/Mix_label 时分别输出 `GT_label图/{视频名称_时间戳_项目帧序号}.png`、`Pro_label彩色分割结果/{视频名称_时间戳_项目帧序号}.png`、`Mix_label重叠覆盖彩色分割结果/{视频名称_时间戳_项目帧序号}.png`。maskid 不参与覆盖排序，GT_label/Pro_label/Mix_label 重叠区域覆盖顺序由内部拖拽排序字段决定，并与未选中状态下的 Canvas 显示顺序一致。

---

## 当前实现注意事项

- `src/lib/config.ts` 会优先读取 `VITE_API_BASE_URL` 和 `VITE_WS_PROGRESS_URL`；未配置时按当前浏览器 hostname 推导后端 `:8000` 地址。
- 前端 `predictMask()` 已按后端 `PredictRequest` 发送 `image_id`、`prompt_type`、`prompt_data`、`model`，并将后端 `polygons` 转成 Konva 可渲染的 `pathData`。
- 手工绘制工具会生成可保存的 `Mask.segmentation`；撤销/重做通过 `maskHistory/maskFuture` 工作。
- Polygon 顶点编辑和新增顶点会重算 `pathData/segmentation/bbox/area`；已保存 mask 进入 dirty 状态后复用归档 PATCH 链路。
- 区域合并/去除会重算主 mask 的几何；合并已保存的次级 mask 时会通过工作区回调删除对应后端标注。
- 前端 `importGtMask()` 已对齐后端 `/api/ai/import-gt-mask`；工作区左侧工具栏“导入 GT Mask”会在上传前显示导入结果预览并选择未知 maskid 策略，后端支持二值 mask、低数值/16-bit GT_label 灰度图和 RGB 三通道完全相同的 `[X,X,X]` maskid 图，不再按彩色 RGB 类别图做颜色匹配；尺寸不同的 mask 会最近邻拉伸到当前帧，导入后回显多类别标注和 seed point。
- 前端 `exportCoco()` 已对齐后端 `/api/export/{project_id}/coco`；前端 `exportMasks()` 已对齐后端 `/api/export/{project_id}/masks`；前端 `exportSegmentationResults()` 已对齐后端 `/api/export/{project_id}/results`；工作区“分割结果导出”按钮会先保存当前待归档 mask，再按所选范围、outputs 和 Mix_label 透明度下载统一 ZIP；特定范围帧导出可用帧号输入框或时间轴拖拽选择范围；下载文件名按项目库项目名、导出范围首尾时间戳和首尾项目帧序号生成；统一 ZIP 包含 maskid/GT 像素值映射 JSON、原始图片文件夹、按帧/类别合并的分开 Mask 文件夹、GT_label 图文件夹、Pro_label 彩色图文件夹和 Mix_label 叠加图文件夹；GT_label 像素值使用类别真实 `maskid` 并跨图一致。
- 右侧语义分类树和 Canvas “应用分类”都会把分类变更同步到同一传播链前后帧对应 mask；识别依据为 `source_annotation_id`、`source_mask_id` 和 `propagation_seed_key`，被同步更新的已保存 mask 会进入 dirty 状态，等待工作区归档保存 PATCH 到后端。
- 工作区保存状态按钮会按当前项目待保存数量显示“保存 X 个改动”或“已全部保存”，并已接入 `POST /api/ai/annotate` 和 `PATCH /api/ai/annotations/{id}`；加载工作区时会通过 `GET /api/ai/annotations` 回显已保存标注。
- 右侧实例属性面板“边缘平滑强度/应用边缘平滑”已接入 `POST /api/ai/smooth-mask`；滑杆会即时更新数值，但后端预览请求有短防抖，避免拖动时连续请求卡顿；预览不写入撤销历史也不标 dirty；点击应用后会把返回 polygon 作为新的实际 mask 几何写入当前 mask 和同传播链前后对应 mask，整次应用作为一个撤销/重做历史步骤，相关 mask 标记为 dirty/draft，平滑强度重置为 0，用户可继续用 polygon 编辑工具调整新多边形。
- 工作区“自动传播”按钮已接入 `POST /api/ai/propagate/task`；若用户尚未显式设置范围，第一次点击会进入时间轴范围选择模式，第二次点击“开始传播”才提交后台任务；当前启用所选 SAM 2.1 变体的视频 predictor 后台任务，运行中轮询任务进度，完成后刷新后端已保存标注；工作区顶栏模型状态用紧凑 GPU/CPU 徽标，具体 SAM 2.1 传播权重由旁边下拉选择；同步 `POST /api/ai/propagate` 仍作为单 seed 兼容接口保留。
- 工作区顶栏短状态会自动消失；保存、导出、导入 GT、传播进行中和无帧项目提示会保留到状态变化。
- 工作区“清空遮罩”会调用 `DELETE /api/ai/annotations/{id}` 删除当前帧已保存标注，并清空当前帧本地 mask。
- 项目状态已统一为 `pending`、`parsing`、`ready`、`error`；前端 `src/lib/api.ts` 会兼容归一化旧库中可能存在的 `Ready`、`Parsing`、`Error`。
- 项目库的视频导入与生成帧是两个独立动作：导入视频只上传源文件，生成帧按钮才会带 `parse_fps` 调用 `/api/media/parse`；工作区不会再因“有视频但无帧”自动创建拆帧任务。
- `server.ts` 不再提供旧版 `/api/login`、`/api/projects`、`/api/templates` mock；当前前端真实 API 调用走 FastAPI 的 `/api/auth/*`、`/api/projects`、`/api/templates` 等接口。
- `Dashboard.tsx` 初始统计、任务进度和活动日志来自 `GET /api/dashboard/overview`；任务进度来自 `processing_tasks` queued/running/success/failed/cancelled，处理中统计只计算 queued/running，支持取消 queued/running 任务、重试 failed/cancelled 任务和查看失败详情。Celery worker 通过 Redis pub/sub 的 `seg:progress` 频道推送细粒度进度，再由 FastAPI 广播到 `/ws/progress`；前端 WebSocket 客户端通过 `onopen/onclose/onerror` 更新连接状态，并定时发送 `ping` 心跳。

---

## 代码风格与约定

### 样式规范

- 深色主题为主，常见背景色包括 `#0a0a0a`、`#111`、`#0d0d0d`、`#151515`、`#1e1e1e`。
- 青色（如 `cyan-400` / `cyan-500`）用于激活状态、主按钮和关键指标。
- 前端样式主要使用 TailwindCSS 工具类，通过 `cn()` 合并条件类名。
- `src/index.css` 使用 TailwindCSS 4 的 `@import "tailwindcss";`。

### 组件规范

- 组件使用函数组件 + Hooks。
- 当前组件目录是扁平结构：`src/components/*.tsx`，不是按模块子目录分层。
- Props 类型优先使用 TypeScript `interface`。
- UI 文本保持中文。
- 代码与注释优先使用英文。

### 命名规范

- 组件文件使用 PascalCase，例如 `AISegmentation.tsx`。
- 工具文件使用 camelCase，例如 `utils.ts`。
- 类型和接口使用 PascalCase。

---

## 测试策略

当前仓库已配置前端 Vitest 测试和后端 pytest 测试。测试依据 `doc/07-current-requirements-freeze.md`、`doc/08-current-design-freeze.md` 和 `doc/09-test-plan.md`。

- 前端测试配置：`vitest.config.ts`，共享 setup 在 `src/test/setup.tsx`。
- 前端测试命令：`npm run test:run`。
- 后端测试依赖：`backend/requirements-dev.txt`。
- 后端测试命令：`pytest backend/tests`，或在 `backend/` 目录执行 `pytest tests`。
- 基础静态校验：`npm run lint`、`npm run build`、`python -m py_compile backend/routers/ai.py backend/routers/templates.py backend/schemas.py`。
- 后端测试使用内存 SQLite、fake MinIO 和 fake SAM registry，不依赖真实 PostgreSQL、MinIO、Redis 或模型权重。

---

## 安全注意事项

- FastAPI 已有真实 `users` 表、密码哈希和签名 JWT；默认 `admin / 123456` 只是开发种子用户，生产部署应通过环境变量或数据库改密。
- 业务路由会校验 Bearer token；项目、帧、标注、任务、Dashboard 和导出按当前用户拥有的项目过滤，模板支持系统模板（`owner_user_id IS NULL`）和用户模板。
- 角色分为 `admin`、`annotator`、`viewer`：`admin/annotator` 可调用写入类业务接口，`viewer` 只能调用读接口；`/api/admin/*` 仅允许 `admin`。
- 管理员后台支持用户新增、停用/启用、改角色、改密码、删除无项目用户、查看登录/用户管理审计日志，以及二次确认后恢复演示出厂设置；禁止管理员删除、停用或降级自己。
- JWT 默认开发密钥在 `backend/config.py`，生产部署必须通过 `backend/.env` 覆盖 `JWT_SECRET_KEY`。
- `backend/.env` 被 `.gitignore` 忽略；不要提交真实数据库、MinIO、Redis、模型路径等敏感配置。
- `start_services.sh` 中包含本机路径和 sudo 启动逻辑，迁移机器时要审查。
- Express `server.ts` 只负责前端开发/静态服务，不承担业务 API 或鉴权。

---

## AI Studio / Vite 特定配置

- `.env.example` 包含 `GEMINI_API_KEY` 和 `APP_URL`，说明这些值由 AI Studio 注入。
- `vite.config.ts` 通过 `loadEnv` 把 `GEMINI_API_KEY` 注入到 `process.env.GEMINI_API_KEY`。
- `vite.config.ts` 中的 `DISABLE_HMR` 逻辑用于关闭 HMR，避免 AI Studio agent 编辑时闪烁。**不要随意修改该逻辑。**
