# 附件服务多态关联代码实现 > **变更类型**:功能实现 > **影响范围**:附件服务 > **日期**:2026-01-28 ## 实施概述 完成附件服务多态关联设计的代码实现,包括 Model、Schema、Repository、Service、API 层和数据库迁移脚本。 ## 实施内容 ### 1. Model 层 **文件**:`server/app/models/attachment.py` **实现内容**: - ✅ `AttachmentCategory` 枚举(DOCUMENT=1, IMAGE=2) - ✅ `RelatedType` 枚举(USER=1, PROJECT=2, STORYBOARD=3, CHARACTER=4, SCENE=5, PROP=6, LOCATION=7) - ✅ `AttachmentPurpose` 枚举(AVATAR=1, COVER=2, THUMBNAIL=3, DOCUMENT=4, REFERENCE=5, ATTACHMENT=6) - ✅ `Attachment` 模型(多态关联字段:related_id, related_type, attachment_purpose) - ✅ 枚举转换方法(from_string, to_string, get_display_name) - ✅ to_dict() 方法(camelCase 字段名) **核心字段**: ```python related_id: UUID # 关联实体 ID related_type: int (SMALLINT) # 关联实体类型 attachment_purpose: int (SMALLINT) # 附件用途 ``` ### 2. Schema 层 **文件**:`server/app/schemas/attachment.py` **实现内容**: - ✅ `AttachmentUploadRequest` - 上传请求 Schema(支持多态关联参数) - ✅ `AttachmentQueryRequest` - 查询请求 Schema - ✅ `AttachmentResponse` - 附件响应 Schema - ✅ `AttachmentListResponse` - 附件列表响应 Schema - ✅ `DownloadUrlResponse` - 下载链接响应 Schema - ✅ 字段验证器(category, related_type, attachment_purpose) ### 3. Repository 层 **文件**:`server/app/repositories/attachment_repository.py` **实现内容**: - ✅ `exists_user()` - 验证用户存在 - ✅ `exists_related_entity()` - 验证关联实体存在(多态) - ✅ `check_related_permission()` - 检查关联实体权限(多态) - ✅ `get_by_id()` - 根据 ID 获取附件 - ✅ `get_by_related()` - 获取关联实体的附件列表(多态查询) - ✅ `get_by_purpose()` - 获取指定用途的附件 - ✅ `create()` - 创建附件 - ✅ `soft_delete()` - 软删除附件 - ✅ `increment_access_count()` - 增加访问计数 - ✅ `increment_download_count()` - 增加下载计数 **注意事项**: - Storyboard、ScreenplayCharacter、ScreenplayScene 模型尚未实现,暂时跳过验证 - 待相关模型实现后,需要取消注释相应的验证代码 ### 4. Service 层 **文件**:`server/app/services/attachment_service.py` **实现内容**: - ✅ `upload_attachment()` - 上传附件(多态关联) - ✅ `get_attachment()` - 获取附件详情 - ✅ `get_download_url()` - 获取下载链接 - ✅ `delete_attachment()` - 删除附件 - ✅ `get_attachments_by_related()` - 获取关联实体的附件列表 - ✅ `get_attachment_by_purpose()` - 获取指定用途的附件 - ✅ 文件类型验证(ALLOWED_DOCUMENT_TYPES, ALLOWED_IMAGE_TYPES) - ✅ 文件大小验证(MAX_FILE_SIZE) - ✅ 权限检查(应用层引用完整性) **临时实现**: - 文件存储暂时使用简单逻辑(计算 checksum,生成临时 URL) - 待 FileStorageService 实现后,需要集成文件去重功能 ### 5. API 层 **文件**:`server/app/api/v1/attachments.py` **实现内容**: - ✅ `POST /attachments` - 上传附件 - ✅ `GET /attachments/{attachment_id}` - 获取附件详情 - ✅ `GET /attachments/{attachment_id}/download` - 获取下载链接 - ✅ `DELETE /attachments/{attachment_id}` - 删除附件 - ✅ `GET /attachments` - 获取关联实体的附件列表 - ✅ `GET /attachments/purpose/{related_type}/{related_id}/{purpose}` - 获取指定用途的附件 - ✅ 依赖注入(get_attachment_service) - ✅ 统一 ApiResponse 响应格式 **路由注册**: - ✅ 在 `server/app/api/v1/router.py` 中注册 attachments 路由 ### 6. 数据库迁移 **文件**:`server/alembic/versions/20260128_2100_create_attachments_table.py` **实现内容**: - ✅ 创建 attachments 表 - ✅ 添加表和列注释 - ✅ 创建核心索引(多态关联必须) - `idx_attachments_related` (related_id, related_type, attachment_purpose) - `idx_attachments_related_type` (related_type, related_id) - `idx_attachments_uploaded_by` (uploaded_by) - `idx_attachments_category` (category) - `idx_attachments_created_at` (created_at DESC) - `idx_attachments_checksum` (checksum) - ✅ 创建组合索引 - `idx_attachments_uploader_created` (uploaded_by, created_at DESC) - ✅ 创建全文搜索索引(pg_trgm) - `idx_attachments_name_trgm` - `idx_attachments_original_name_trgm` - ✅ 创建触发器(自动更新 updated_at) - ✅ downgrade() 回滚方法 ### 7. 模型导出 **文件**:`server/app/models/__init__.py` **实现内容**: - ✅ 导出 Attachment 模型 - ✅ 导出 AttachmentCategory 枚举 - ✅ 导出 RelatedType 枚举 - ✅ 导出 AttachmentPurpose 枚举 ## 代码统计 | 层级 | 文件 | 行数 | 说明 | |------|------|------|------| | Model | attachment.py | ~250 | 3个枚举 + 1个模型 | | Schema | attachment.py | ~120 | 5个 Schema 类 | | Repository | attachment_repository.py | ~220 | 11个方法 | | Service | attachment_service.py | ~280 | 6个方法 | | API | attachments.py | ~150 | 6个端点 | | Migration | 20260128_2100_*.py | ~180 | upgrade + downgrade | | **总计** | **6个文件** | **~1200行** | **完整实现** | ## 技术亮点 ### 1. 多态关联设计 ```python # 支持任意实体的附件管理 related_id: UUID # 通用关联 ID related_type: SMALLINT # 实体类型(1-7) attachment_purpose: SMALLINT # 附件用途(1-6) ``` ### 2. 枚举转换 ```python # 字符串 ↔ 枚举 ↔ 显示名称 RelatedType.from_string('project') # → RelatedType.PROJECT (2) RelatedType.PROJECT.to_string() # → 'project' RelatedType.get_display_name(2) # → '项目' ``` ### 3. 应用层引用完整性 ```python # Repository 层验证 await self.repository.exists_related_entity(related_id, related_type) await self.repository.check_related_permission(user_id, related_id, related_type, 'editor') ``` ### 4. 统一查询接口 ```python # 查询任意实体的附件 await service.get_attachments_by_related( user_id, related_id, related_type, attachment_purpose, category ) # 获取指定用途的附件 await service.get_attachment_by_purpose( user_id, related_id, related_type, purpose ) ``` ## 待完成工作 ### 高优先级 1. **FileStorageService 集成** - 实现文件去重功能 - 集成 MinIO/S3 对象存储 - 生成预签名下载 URL 2. **Storyboard 模型实现** - 实现 Storyboard 模型 - 取消 Repository 中的验证跳过逻辑 - 实现分镜权限检查 3. **Screenplay 模型实现** - 实现 ScreenplayCharacter 模型 - 实现 ScreenplayScene 模型 - 取消 Repository 中的验证跳过逻辑 ### 中优先级 4. **单元测试** - Model 层测试 - Repository 层测试 - Service 层测试 - API 层测试 5. **集成测试** - 上传附件流程测试 - 权限检查测试 - 多态查询测试 ### 低优先级 6. **性能优化** - 批量查询优化 - 缓存策略 - 索引优化 7. **监控告警** - 上传失败告警 - 存储空间监控 - 访问统计 ## 部署步骤 ### 1. 执行数据库迁移 ```bash # 在 Docker 容器内执行 docker exec jointo-server-app alembic upgrade head ``` ### 2. 验证迁移 ```bash # 检查表是否创建成功 docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d attachments" # 检查索引 docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\di attachments*" ``` ### 3. 重启服务 ```bash # 重启 FastAPI 服务 docker restart jointo-server-app ``` ### 4. 测试 API ```bash # 测试上传附件 curl -X POST http://localhost:8000/api/v1/attachments \ -H "Authorization: Bearer " \ -F "file=@test.jpg" \ -F "category=image" \ -F "relatedId=" \ -F "relatedType=project" \ -F "attachmentPurpose=cover" # 测试查询附件 curl -X GET "http://localhost:8000/api/v1/attachments?relatedId=&relatedType=project" \ -H "Authorization: Bearer " ``` ## 验证清单 - ✅ Model 层代码实现 - ✅ Schema 层代码实现 - ✅ Repository 层代码实现 - ✅ Service 层代码实现 - ✅ API 层代码实现 - ✅ 数据库迁移脚本 - ✅ 路由注册 - ✅ 模型导出 - ⏳ 数据库迁移执行(待部署) - ⏳ API 测试(待部署) - ⏳ 单元测试(待实现) - ⏳ 集成测试(待实现) ## 相关文档 - [附件服务文档](../../requirements/backend/04-services/resource/attachment-service.md) - [RFC 139: 附件服务多态关联设计](../rfcs/139-attachment-polymorphic-association.md) - [Changelog: 附件服务多态关联设计](./2026-01-28-attachment-polymorphic-association.md) --- **实施日期**:2026-01-28 **实施人员**:开发团队 **状态**:代码实现完成,待部署测试