# label-backend ## 项目简介 `label-backend` 是知识图谱智能标注平台的后端服务,负责资料上传、任务分发、提取标注、问答生成、训练样本导出、系统配置和视频预处理等核心流程。 系统采用 Spring Boot 3 + MyBatis-Plus + PostgreSQL + Redis 的技术组合,面向多租户标注场景设计,支持: - 公司级数据隔离 - 基于 Redis Token 的认证鉴权 - 提取与问答两阶段标注流程 - 导出训练数据并对接微调任务 - 视频预处理与异步回调 - 审计日志与任务状态追踪 代码结构已按扁平标准目录整理,主包位于 `src/main/java/com/label`。 ## 功能特性 - 认证鉴权 - 使用 UUID Bearer Token + Redis 会话存储 - 自定义 `@RequireAuth`、`@RequireRole` - 角色分级:`ADMIN > REVIEWER > ANNOTATOR > UPLOADER` - 多租户隔离 - 基于 `CompanyContext` + `TenantLineInnerInterceptor` - 对租户表自动追加 `company_id` 条件 - 特殊表通过显式 `companyId` 参数校验 - 公司与用户管理 - 公司 CRUD - 公司内用户创建、状态变更、角色变更 - 角色变更和禁用后即时刷新或失效 Redis Token - 资料管理 - 支持文本、图片、视频三类原始资料 - 上传到 RustFS,数据库保存元数据 - 支持按角色查看、查询详情、删除 - 任务管理 - 任务池、我的任务、待审批队列、管理员全量视图 - Redis 分布式锁 + 数据库原子更新保证任务领取并发安全 - 提取标注 - AI 预标注 - 标注结果整体覆盖更新 - 提交、审批通过、驳回 - 问答生成 - 基于提取审批通过事件生成候选问答对 - 支持编辑、提交、审批、驳回 - 训练数据导出 - 查询已审批样本 - 创建导出批次 - 触发微调任务并查询状态 - 系统配置 - 支持公司专属配置覆盖全局默认配置 - 配置项存储于 `sys_config` - 视频处理 - 支持触发视频预处理任务 - 支持异步回调、失败重试、管理员重置 ## 技术栈 - Java 21 - Spring Boot 3.1.5 - Spring MVC - MyBatis-Plus 3.5.3.1 - PostgreSQL - Redis - Spring AOP - springdoc-openapi - Testcontainers - RustFS / S3 兼容对象存储 ## 项目结构 项目根目录结构: ```text label_backend/ ├── assembly/ # 分发包描述与占位目录 ├── docs/ # 设计、计划、规范文档 ├── scripts/ # 启动脚本 ├── src/ │ ├── main/ │ │ ├── java/com/label/ # 主代码 │ │ └── resources/ │ │ ├── application.yml │ │ ├── logback.xml │ │ └── sql/ # 初始化 SQL,不打入构建产物 │ └── test/ │ ├── java/ # 单元测试与集成测试 │ └── resources/db/init.sql # Testcontainers 测试初始化 SQL ├── docker-compose.yml ├── Dockerfile ├── pom.xml └── README.md ``` Java 包结构: ```text com.label ├── annotation # 自定义注解,如 RequireAuth / RequireRole / OperationLog ├── aspect # AOP 审计切面 ├── common # 通用能力:auth、context、exception、result、storage、ai、statemachine ├── config # Spring 配置、MyBatis-Plus 配置、认证拦截器注册 ├── controller # 所有 REST 接口 ├── dto # DTO ├── entity # 实体 ├── event # 领域事件 ├── interceptor # 认证拦截器 ├── listener # 事件监听器 ├── mapper # MyBatis Mapper ├── service # 业务服务 └── util # 工具类 ``` ## 数据库表结构 初始化脚本位于 [init.sql](d:/workspace/label/label_backend/src/main/resources/sql/init.sql),包含 11 张核心表: - `sys_company` - 租户公司表 - `sys_user` - 公司用户表,包含角色与状态 - `source_data` - 原始资料元数据,支持 `TEXT` / `IMAGE` / `VIDEO` - `annotation_task` - 标注任务表,支持 `EXTRACTION` / `QA_GENERATION` - `annotation_result` - 提取阶段 JSON 结果 - `training_dataset` - 训练样本数据,存储 GLM 格式 JSON - `export_batch` - 导出批次与微调任务状态 - `sys_config` - 全局与公司级配置 - `sys_operation_log` - 审计日志,只追加不更新 - `annotation_task_history` - 任务状态变更历史 - `video_process_job` - 视频预处理任务与回调状态 当前主要状态机: - `source_data.status` - `PENDING` / `PREPROCESSING` / `EXTRACTING` / `QA_REVIEW` / `APPROVED` - `annotation_task.status` - `UNCLAIMED` / `IN_PROGRESS` / `SUBMITTED` / `APPROVED` / `REJECTED` - `training_dataset.status` - `PENDING_REVIEW` / `APPROVED` / `REJECTED` - `video_process_job.status` - `PENDING` / `RETRYING` / `SUCCESS` / `FAILED` ## 配置说明 主配置文件位于 [application.yml](d:/workspace/label/label_backend/src/main/resources/application.yml)。 ### 环境变量 | 变量名 | 说明 | |---|---| | `SPRING_DATASOURCE_URL` | PostgreSQL JDBC 地址 | | `SPRING_DATASOURCE_USERNAME` | PostgreSQL 用户名 | | `SPRING_DATASOURCE_PASSWORD` | PostgreSQL 密码 | | `SPRING_DATA_REDIS_HOST` | Redis 主机 | | `SPRING_DATA_REDIS_PORT` | Redis 端口 | | `SPRING_DATA_REDIS_PASSWORD` | Redis 密码 | | `RUSTFS_ENDPOINT` | RustFS / S3 兼容服务地址 | | `RUSTFS_ACCESS_KEY` | RustFS Access Key | | `RUSTFS_SECRET_KEY` | RustFS Secret Key | | `AI_SERVICE_BASE_URL` | AI 服务地址 | | `VIDEO_CALLBACK_SECRET` | 视频处理回调共享密钥 | ### 关键配置项 - `auth.enabled` - `true` 时启用真实 Token 鉴权 - `false` 时使用 mock 身份,便于本地开发 - `auth.mock-company-id` - 开发模式下的模拟公司 ID - `auth.mock-user-id` - 开发模式下的模拟用户 ID - `auth.mock-role` - 开发模式下的模拟角色 - `token.ttl-seconds` - Token 有效期,默认 7200 秒 - `springdoc.api-docs.path` - OpenAPI 文档路径,默认 `/v3/api-docs` - `springdoc.swagger-ui.path` - Swagger UI 路径,默认 `/swagger-ui.html` ## API接口 以下为当前主要接口分组。 ### 1. 认证接口 - `POST /api/auth/login` - 登录并返回 Bearer Token - `POST /api/auth/logout` - 登出并立即失效当前 Token - `GET /api/auth/me` - 获取当前登录用户信息 ### 2. 公司管理 - `GET /api/companies` - `POST /api/companies` - `PUT /api/companies/{id}` - `PUT /api/companies/{id}/status` - `DELETE /api/companies/{id}` ### 3. 用户管理 - `GET /api/users` - `POST /api/users` - `PUT /api/users/{id}` - `PUT /api/users/{id}/status` - `PUT /api/users/{id}/role` ### 4. 资料管理 - `POST /api/source/upload` - `GET /api/source/list` - `GET /api/source/{id}` - `DELETE /api/source/{id}` ### 5. 任务管理 - `GET /api/tasks/pool` - `GET /api/tasks/mine` - `GET /api/tasks/pending-review` - `GET /api/tasks` - `POST /api/tasks` - `GET /api/tasks/{id}` - `POST /api/tasks/{id}/claim` - `POST /api/tasks/{id}/unclaim` - `POST /api/tasks/{id}/reclaim` - `PUT /api/tasks/{id}/reassign` ### 6. 提取标注 - `GET /api/extraction/{taskId}` - `PUT /api/extraction/{taskId}` - `POST /api/extraction/{taskId}/submit` - `POST /api/extraction/{taskId}/approve` - `POST /api/extraction/{taskId}/reject` ### 7. 问答生成 - `GET /api/qa/{taskId}` - `PUT /api/qa/{taskId}` - `POST /api/qa/{taskId}/submit` - `POST /api/qa/{taskId}/approve` - `POST /api/qa/{taskId}/reject` ### 8. 导出与微调 - `GET /api/training/samples` - `POST /api/export/batch` - `POST /api/export/{batchId}/finetune` - `GET /api/export/{batchId}/status` - `GET /api/export/list` ### 9. 系统配置 - `GET /api/config` - `PUT /api/config/{key}` ### 10. 视频处理 - `POST /api/video/process` - `GET /api/video/jobs/{jobId}` - `POST /api/video/jobs/{jobId}/reset` - `POST /api/video/callback` ## 定时任务 当前项目中**没有启用 Spring `@Scheduled` 定时同步任务**。 现有异步能力主要通过以下方式完成: - 事务提交后事件监听 - 提取审批通过后触发问答生成 - 外部 AI 服务异步回调 - 视频处理完成后回调 `/api/video/callback` - Redis 分布式锁 - 用于任务领取并发控制 如果后续需要周期性任务,建议单独引入明确的调度场景,不要复用当前业务链路中的事件机制。 ## 部署说明 ### 1. 数据库初始化 初始化 SQL 位于: - 开发/部署初始化脚本 - [src/main/resources/sql/init.sql](d:/workspace/label/label_backend/src/main/resources/sql/init.sql) 说明: - `src/main/resources/sql/init.sql` 会随源码保存,但**不会被打入 jar、target/classes 或分发包** - `docker-compose.yml` 通过挂载该文件完成 PostgreSQL 初始化 ### 2. 本地构建 ```bash mvn clean package -DskipTests ``` 构建产物: ... - `target/label-backend-1.0.0-SNAPSHOT.zip` - `target/label-backend-1.0.0-SNAPSHOT.tar.gz` ### 3. 分发包结构 分发包由 [distribution.xml](d:/workspace/label/label_backend/assembly/distribution.xml) 组装,解压后结构如下: ```text label-backend-/ ├── bin/ │ └── start.sh ├── etc/ │ ├── application.yml │ └── logback.xml ├── libs/ │ ├── label-backend-.jar │ └── *.jar └── logs/ ``` ### 4. 启动脚本 启动脚本位于 [start.sh](d:/workspace/label/label_backend/scripts/start.sh)。 行为说明: - 在 Docker 容器中检测到 `/.dockerenv` 时,前台 `exec java ...` - 在宿主机环境中使用 `nohup` 后台启动 - 日志默认写入 `logs/startup.log` ### 5. Docker Compose 启动 ```bash docker compose up -d ``` 当前 `docker-compose.yml` 会启动: - PostgreSQL - Redis - RustFS(当前使用 MinIO 作为 S3 兼容替代) - backend - ai-service 占位服务 - frontend 占位服务 ### 6. Docker 镜像构建 ```bash docker build -t label-backend:latest . ``` `Dockerfile` 使用多阶段构建,并从项目根目录的 `scripts/start.sh` 复制启动脚本。 ## 注意事项 1. 开发模式下 `auth.enabled=false` - 此时会使用 mock 用户身份,不适合生产环境 - 生产部署前必须显式启用真实鉴权 2. 多租户隔离仍依赖 `CompanyContext` + `TenantLineInnerInterceptor` - 租户表查询默认依赖租户拦截器 - 个别特殊场景通过显式 `companyId` 参数校验 3. `sys_config`、`sys_company`、`video_process_job` 属于特殊表 - 其中部分表被排除出自动租户注入,需在服务层显式控制 4. SQL 已迁移到 `src/main/resources/sql` - 仅作为源码级初始化文件保留 - 不会打进构建产物 5. 集成测试依赖 Testcontainers - 运行完整集成测试需要本机可用 Docker 环境 6. 认证实现已移除 Shiro - 当前使用自定义拦截器、注解与 Redis Token 7. 用户上下文 ThreadLocal 已移除 - 当前只保留 `CompanyContext` - 用户主体通过请求属性中的 `TokenPrincipal` 传递 ## 开发规范 当前约束摘要: - 统一扁平目录结构,避免再次引入按业务域分层的旧目录 - DTO 统一放在 `dto/`,不再拆分 `request/response` - Service 统一放在 `service/`,不拆 `service/impl` - 业务规则优先放在 Service,Controller 只负责 HTTP 协议层 - 新增接口需同步补齐 Swagger 注解与测试 - 所有对外接口参数必须在 Swagger 中明确体现名称、类型和含义 - 固定结构请求体禁止继续使用匿名 `Map` 或 `Map`,必须定义 DTO 并补齐 `@Schema` 字段说明 - 固定结构响应应优先使用明确 DTO,或至少为 Swagger 暴露对象补齐字段级 `@Schema` 注解 - 路径参数、查询参数、请求体、分页包装和通用返回体都必须维护可读的 OpenAPI 文档说明 - 需要保持历史兼容的原始 JSON 字符串请求体可以继续使用 `String`,但必须在 Swagger `@RequestBody` 中说明完整 JSON body 的提交方式和兼容原因 - 修改 Controller 参数、请求 DTO、响应 DTO 或对外实体后,必须运行 `mvn -Dtest=OpenApiAnnotationTest test`,确保 Swagger 参数名称、类型和含义没有回退 - 目录、配置、打包方式变化后,README、设计文档和部署说明必须同步更新