# 项目素材服务技术栈合规性更新 **日期**:2026-01-29 **类型**:文档更新 **影响范围**:`docs/requirements/backend/04-services/project/project-resource-service.md` --- ## 变更概述 将项目素材服务文档更新至 jointo-tech-stack v1.0 规范,确保所有设计符合项目技术栈约束。 --- ## 主要变更 ### 1. UUID v7 主键 **变更前**: ```python project_resource_id = Column(Integer, primary_key=True, autoincrement=True) ``` **变更后**: ```python project_resource_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid7) ``` **说明**: - 应用层生成 UUID v7,非数据库默认值 - 确保分布式环境下的唯一性和时序性 ### 2. 移除物理外键约束 **变更前**: ```sql project_id UUID NOT NULL REFERENCES projects(project_id), created_by UUID NOT NULL REFERENCES users(user_id), ``` **变更后**: ```sql project_id UUID NOT NULL, -- 无物理外键,应用层校验 created_by UUID NOT NULL, -- 无物理外键,应用层校验 ``` **说明**: - 禁止数据库层外键约束 - Service 层添加引用完整性校验逻辑 - 手动创建索引确保查询性能 ### 3. SMALLINT + IntEnum 替代 PostgreSQL ENUM **变更前**: ```sql CREATE TYPE resource_type AS ENUM ('character', 'scene', 'prop', 'footage'); type resource_type NOT NULL, ``` **变更后**: ```sql -- 素材类型:1=角色, 2=场景, 3=道具, 4=实拍 type SMALLINT NOT NULL, -- 1=character, 2=scene, 3=prop, 4=footage ``` ```python class ResourceType(IntEnum): """素材类型枚举""" CHARACTER = 1 # 角色 SCENE = 2 # 场景 PROP = 3 # 道具 FOOTAGE = 4 # 实拍 ``` **说明**: - 使用 SMALLINT 存储枚举值 - Python 层使用 IntEnum 定义枚举 - 便于扩展和维护 ### 4. AsyncSession 替代 Session **变更前**: ```python from sqlalchemy.orm import Session class ProjectResourceService: def __init__(self, db: Session): self.db = db ``` **变更后**: ```python from sqlalchemy.ext.asyncio import AsyncSession class ProjectResourceService: def __init__(self, db: AsyncSession): self.db = db ``` **说明**: - 所有数据库操作使用 async/await - 提升并发性能 ### 5. Aware Datetime + TIMESTAMP **变更前**: ```python created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc)) ``` ```sql created_at TIMESTAMPTZ NOT NULL DEFAULT now(), ``` **变更后**: ```python created_at = Column(TIMESTAMP, nullable=False, default=lambda: datetime.now(timezone.utc)) ``` ```sql created_at TIMESTAMP NOT NULL, -- 应用层传入 aware datetime ``` **说明**: - 应用层使用 timezone.utc 的 aware datetime - 数据库使用 TIMESTAMP(非 TIMESTAMPTZ) - 应用层传入时间值,不使用数据库默认值 ### 6. 统一 API 响应格式 **变更前**: ```json { "id": 123, "name": "主角-张三", "type": "character" } ``` **变更后**: ```json { "code": 200, "message": "success", "data": { "project_resource_id": "019d1234-5678-7abc-def0-123456789abc", "name": "主角-张三", "type": "character" } } ``` **说明**: - 所有 API 响应使用统一格式 - 包含 code、message、data 三个字段 ### 7. COMMENT ON 语法 **新增**: ```sql 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. 应用层引用完整性校验 **新增**: ```python 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` - 需要创建迁移脚本 --- ## 合规性检查清单 - [x] UUID v7 主键(应用层生成) - [x] 无物理外键约束 - [x] SMALLINT + IntEnum 替代 PostgreSQL ENUM - [x] AsyncSession 替代 Session - [x] Aware datetime + TIMESTAMP - [x] 统一 API 响应格式 - [x] COMMENT ON 语法 - [x] 应用层引用完整性校验 - [x] 手动创建索引 - [x] 设计说明完整 --- ## 后续步骤 1. 根据更新后的文档实现代码 2. 创建数据库迁移脚本 3. 编写单元测试和集成测试 4. 更新 API 文档 5. 代码评审和部署 --- ## 相关文档 - [jointo-tech-stack Skill](/.claude/skills/jointo-tech-stack/SKILL.md) - [Backend 规范](/.claude/skills/jointo-tech-stack/references/backend.md) - [Database 规范](/.claude/skills/jointo-tech-stack/references/database.md) - [API Design 规范](/.claude/skills/jointo-tech-stack/references/api-design.md) --- **变更人**:Kiro AI **审核状态**:待审核