# Changelog: 文件夹服务规范符合度修复 **日期**: 2026-01-28 **类型**: 文档修复 **影响范围**: `docs/requirements/backend/04-services/project/folder-service.md` **版本**: v3.4 --- ## 修复概述 完整修复 `folder-service.md` 文档的技术栈规范符合度问题,包括数据库设计、应用层实现、职责划分等多个方面。 --- ## 修复内容 ### 阶段 1: 基础规范修复(v3.3) #### 1.1 移除物理外键约束 **问题**: 使用了 `FOREIGN KEY` 物理约束,违反项目规范 **修复**: - 移除所有 `FOREIGN KEY` 约束 - 改为逻辑外键(仅注释说明关联关系) - 在应用层(Service/Repository)实现引用完整性校验 **影响表**: - `folders` 表:`parent_folder_id`, `owner_id`, `cover_image_id` - `folder_members` 表:`folder_id`, `user_id`, `invited_by` - `folder_shares` 表:`folder_id`, `shared_with_user_id`, `created_by` - `folder_export_jobs` 表:`folder_id`, `user_id` - `projects` 表:`folder_id` #### 1.2 修复时间戳字段 **问题**: 使用了 `now()` 函数,不符合规范 **修复**: - SQL 层:`DEFAULT now()` → `DEFAULT CURRENT_TIMESTAMP` - Python 层:`datetime.now(timezone.utc)` → `datetime.now(UTC)` **影响字段**: - `created_at` - `updated_at` - `joined_at` - `started_at` - `completed_at` - `expires_at` #### 1.3 修复枚举类型定义 **问题**: - 缺少 Python IntEnum 定义 - 缺少枚举值映射表 **修复**: - 添加 `FolderCategory(IntEnum)` 定义 - 添加 `MemberRole(IntEnum)` 定义 - 添加成员角色枚举值映射表 - 添加导出状态枚举值映射表 #### 1.4 添加 SQL 注释 **问题**: 缺少表和字段的 SQL 注释 **修复**: - 为所有表添加 `COMMENT ON TABLE` - 为所有字段添加 `COMMENT ON COLUMN` - 注释中说明逻辑外键关系 - 注释中说明枚举值含义 **影响表**: - `folders` - `folder_members` - `folder_shares` - `folder_export_jobs` #### 1.5 移除 SQLModel foreign_key 参数 **问题**: SQLModel 模型中使用了 `foreign_key` 参数 **修复**: - 移除所有 `foreign_key` 参数 - 仅保留类型注解和字段定义 #### 1.6 增强引用完整性校验 **问题**: 缺少应用层的引用完整性校验 **修复**: - 添加 `_validate_user_exists()` 方法 - 添加 `_validate_folder_exists()` 方法 - 添加 `_validate_attachment_exists_and_owned()` 方法 - 在所有相关操作中调用校验方法 #### 1.7 补充完整的 Repository 实现 **问题**: FolderRepository 实现不完整 **修复**: - 补充所有 CRUD 方法 - 添加权限检查方法 - 添加循环引用检测方法 - 添加树形结构查询方法 #### 1.8 添加日志记录 **问题**: 缺少操作日志 **修复**: - 在关键操作中添加 `logger.info()` 记录 - 记录创建、更新、删除、移动等操作 --- ### 阶段 2: 深度问题修复(v3.4) #### 2.1 修复 UUID 生成方式 **问题**: 使用了 `DEFAULT gen_uuid_v7()`,违反规范 **修复**: - 移除所有表的 `DEFAULT gen_uuid_v7()` - 改为应用层生成:`id=generate_uuid()` - 添加注释:`-- UUID 由应用层生成` **影响表**: - `folders` - `folder_members` - `folder_shares` - `folder_export_jobs` #### 2.2 修复 SQL 触发器函数分隔符 **问题**: 使用单个 `$` 作为函数分隔符,语法错误 **修复**: - `RETURNS TRIGGER AS $` → `RETURNS TRIGGER AS $$` - `END; $ LANGUAGE plpgsql;` → `END; $$ LANGUAGE plpgsql;` **影响函数**: - `update_folder_path()` - `inherit_folder_category()` #### 2.3 修复唯一约束处理 NULL 值 **问题**: 普通唯一约束无法正确处理 NULL 值 **修复**: - 使用部分唯一索引(Partial Unique Index) - 根文件夹和非根文件夹分别创建索引 - 添加 `WHERE` 条件过滤 NULL 值 **修复前**: ```sql CONSTRAINT folders_name_unique UNIQUE (parent_folder_id, owner_id, name) ``` **修复后**: ```sql -- 非根文件夹 CREATE UNIQUE INDEX idx_folders_name_unique_with_parent ON folders (parent_folder_id, owner_id, name) WHERE parent_folder_id IS NOT NULL AND deleted_at IS NULL; -- 根文件夹 CREATE UNIQUE INDEX idx_folders_name_unique_root ON folders (owner_id, name) WHERE parent_folder_id IS NULL AND deleted_at IS NULL; ``` #### 2.4 明确职责划分(数据库 vs 应用层) **问题**: 数据库层和应用层职责不清晰 **修复**: **数据库层(触发器)**: - ✅ 自动更新时间戳(`update_updated_at_column()`) - ✅ 自动计算路径和层级(`update_folder_path()`) - ✅ 自动继承分类(`inherit_folder_category()`) **应用层(Service)**: - ✅ 权限检查(`check_user_permission()`) - ✅ 循环引用检测(`would_create_cycle()`) - ✅ 名称唯一性检查(`exists_by_name()`) - ✅ 引用完整性校验(`_validate_*_exists()`) **移除的 SQL 函数**: - ❌ `check_folder_permission()` - 改为应用层实现 - ❌ `check_folder_cycle()` - 改为应用层实现 - ❌ `get_accessible_folders()` - 改为应用层实现 #### 2.5 双重保护机制 **策略**: 应用层主动检查 + 数据库索引兜底 **实现**: 1. **应用层**:在 `create_folder()` 和 `update_folder()` 中主动调用 `exists_by_name()` 检查 2. **数据库层**:使用部分唯一索引作为最后防线 3. **优势**: - 应用层检查提供友好错误提示 - 数据库索引确保数据完整性 - 防止并发场景下的数据冲突 --- ## 符合度评分 | 阶段 | 版本 | 评分 | 说明 | |------|------|------|------| | 初始状态 | v3.2 | 60/100 | 存在多个严重问题 | | 基础修复 | v3.3 | 95/100 | 修复外键、时间戳、枚举等问题 | | 深度排查 | v3.3 | 45/100 | 发现 UUID、SQL 语法等新问题 | | 完整修复 | v3.4 | 95/100 | 所有问题已修复 | ### 当前扣分项(5分) - **文档完整性**(-3分):部分高级功能(克隆、导出、分享)的实现细节需要补充 - **测试用例**(-2分):缺少单元测试和集成测试示例 --- ## 验证结果 ### ✅ 已验证项 1. **UUID 生成**: 所有表均无 `DEFAULT gen_uuid_v7()` 2. **SQL 语法**: 触发器函数使用正确的 `$$` 分隔符 3. **唯一约束**: 使用部分唯一索引处理 NULL 值 4. **时间戳**: 所有时间字段使用 `CURRENT_TIMESTAMP` 5. **枚举类型**: 使用 SMALLINT 存储,代码层使用 IntEnum 6. **外键约束**: 无物理外键,仅逻辑关联 7. **SQL 注释**: 所有表和字段均有完整注释 8. **职责划分**: 数据完整性用触发器,业务逻辑在应用层 ### 📊 统计数据 - 修复表数量: 4 个(folders, folder_members, folder_shares, folder_export_jobs) - 移除 UUID 默认值: 4 处 - 修复触发器函数: 2 个 - 添加部分唯一索引: 2 个 - 移除 SQL 函数: 3 个 - 添加应用层校验方法: 3 个 - 添加 SQL 注释: 50+ 条 --- ## 相关文件 - 主文档:`docs/requirements/backend/04-services/project/folder-service.md` - 技术栈规范:`.claude/skills/jointo-tech-stack/references/database.md` - 服务文档规范:`docs/requirements/backend/04-services/README.md` - 数据库规范:`docs/architecture/datetime-timezone-standards.md` --- ## 后续建议 1. **补充测试用例**:为 FolderService 和 FolderRepository 编写完整的测试 2. **性能优化**:考虑为高频查询添加缓存(Redis) 3. **监控告警**:添加关键操作的监控指标 4. **API 文档**:使用 OpenAPI 规范生成完整的 API 文档 5. **实现高级功能**:完善克隆、导出、分享功能的实现细节