You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

5.5 KiB

项目素材服务技术栈合规性更新

日期:2026-01-29
类型:文档更新
影响范围docs/requirements/backend/04-services/project/project-resource-service.md


变更概述

将项目素材服务文档更新至 jointo-tech-stack v1.0 规范,确保所有设计符合项目技术栈约束。


主要变更

1. UUID v7 主键

变更前

project_resource_id = Column(Integer, primary_key=True, autoincrement=True)

变更后

project_resource_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid7)

说明

  • 应用层生成 UUID v7,非数据库默认值
  • 确保分布式环境下的唯一性和时序性

2. 移除物理外键约束

变更前

project_id UUID NOT NULL REFERENCES projects(project_id),
created_by UUID NOT NULL REFERENCES users(user_id),

变更后

project_id UUID NOT NULL,  -- 无物理外键,应用层校验
created_by UUID NOT NULL,  -- 无物理外键,应用层校验

说明

  • 禁止数据库层外键约束
  • Service 层添加引用完整性校验逻辑
  • 手动创建索引确保查询性能

3. SMALLINT + IntEnum 替代 PostgreSQL ENUM

变更前

CREATE TYPE resource_type AS ENUM ('character', 'scene', 'prop', 'footage');
type resource_type NOT NULL,

变更后

-- 素材类型:1=角色, 2=场景, 3=道具, 4=实拍
type SMALLINT NOT NULL,  -- 1=character, 2=scene, 3=prop, 4=footage
class ResourceType(IntEnum):
    """素材类型枚举"""
    CHARACTER = 1  # 角色
    SCENE = 2      # 场景
    PROP = 3       # 道具
    FOOTAGE = 4    # 实拍

说明

  • 使用 SMALLINT 存储枚举值
  • Python 层使用 IntEnum 定义枚举
  • 便于扩展和维护

4. AsyncSession 替代 Session

变更前

from sqlalchemy.orm import Session

class ProjectResourceService:
    def __init__(self, db: Session):
        self.db = db

变更后

from sqlalchemy.ext.asyncio import AsyncSession

class ProjectResourceService:
    def __init__(self, db: AsyncSession):
        self.db = db

说明

  • 所有数据库操作使用 async/await
  • 提升并发性能

5. Aware Datetime + TIMESTAMP

变更前

created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),

变更后

created_at = Column(TIMESTAMP, nullable=False, default=lambda: datetime.now(timezone.utc))
created_at TIMESTAMP NOT NULL,  -- 应用层传入 aware datetime

说明

  • 应用层使用 timezone.utc 的 aware datetime
  • 数据库使用 TIMESTAMP(非 TIMESTAMPTZ)
  • 应用层传入时间值,不使用数据库默认值

6. 统一 API 响应格式

变更前

{
  "id": 123,
  "name": "主角-张三",
  "type": "character"
}

变更后

{
  "code": 200,
  "message": "success",
  "data": {
    "project_resource_id": "019d1234-5678-7abc-def0-123456789abc",
    "name": "主角-张三",
    "type": "character"
  }
}

说明

  • 所有 API 响应使用统一格式
  • 包含 code、message、data 三个字段

7. COMMENT ON 语法

新增

COMMENT ON COLUMN project_resources.type IS '素材类型: 1=角色(character), 2=场景(scene), 3=道具(prop), 4=实拍(footage)';
COMMENT ON COLUMN project_resources.project_id IS '所属项目ID(无物理外键,应用层校验)';

说明

  • 使用 COMMENT ON 语法为字段添加注释
  • 便于数据库维护和理解

8. 应用层引用完整性校验

新增

async def upload_resource(self, user_id: uuid.UUID, project_id: uuid.UUID, ...):
    # 检查项目存在性(应用层引用完整性校验)
    from app.repositories.project_repository import ProjectRepository
    project_repo = ProjectRepository(self.db)
    project = await project_repo.get_by_id(project_id)
    if not project:
        raise NotFoundError("项目不存在")

说明

  • Service 层添加引用完整性校验
  • 确保关联数据存在
  • 替代数据库外键约束

影响范围

文档更新

  • project-resource-service.md - 完整更新至 v3.0

代码实现(待实施)

  • app/models/project_resource.py - 需要更新模型定义
  • app/services/project_resource_service.py - 需要更新服务实现
  • app/repositories/project_resource_repository.py - 需要更新仓储实现
  • app/api/v1/project_resources.py - 需要更新 API 路由
  • alembic/versions/xxx_project_resources.py - 需要创建迁移脚本

合规性检查清单

  • UUID v7 主键(应用层生成)
  • 无物理外键约束
  • SMALLINT + IntEnum 替代 PostgreSQL ENUM
  • AsyncSession 替代 Session
  • Aware datetime + TIMESTAMP
  • 统一 API 响应格式
  • COMMENT ON 语法
  • 应用层引用完整性校验
  • 手动创建索引
  • 设计说明完整

后续步骤

  1. 根据更新后的文档实现代码
  2. 创建数据库迁移脚本
  3. 编写单元测试和集成测试
  4. 更新 API 文档
  5. 代码评审和部署

相关文档


变更人:Kiro AI
审核状态:待审核