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.
8.4 KiB
8.4 KiB
Folder Service 完整实现
日期:2026-02-02
类型:功能实现
影响范围:后端 - 文件夹服务
变更概述
基于 docs/requirements/backend/04-services/project/folder-service.md 文档,完成文件夹服务的完整实现,包括 Model 层修复、Repository 层补充、数据库迁移文件创建。
详细变更
1. Model 层修复
文件:server/app/models/folder.py
1.1 为所有模型类添加 __repr__ 方法
- ✅
Folder类:添加__repr__方法 - ✅
FolderMember类:添加__repr__方法 - ✅
FolderShare类:添加__repr__方法 - ✅
FolderExportJob类:添加__repr__方法
示例:
def __repr__(self) -> str:
"""字符串表示"""
return f"<Folder(id={self.id}, name='{self.name}', level={self.level})>"
1.2 修复 FolderMember 时间戳字段
变更:
- ❌ 删除:
joined_at字段(冗余) - ✅ 添加:
updated_at字段(标准时间戳)
修改前:
joined_at: datetime = Field(...)
created_at: datetime = Field(...)
修改后:
created_at: datetime = Field(...)
updated_at: datetime = Field(...)
2. Repository 层补充
2.1 创建 FolderShareRepository
文件:server/app/repositories/folder_share_repository.py(新建)
功能:
- ✅ 用户分享管理(创建、查询、撤销)
- ✅ 链接分享管理(创建、查询、撤销)
- ✅ 访问次数统计
- ✅ 分享记录查询
核心方法:
async def create_user_share(folder_id, shared_with_user_id, role, created_by)
async def create_link_share(folder_id, token, access_level, created_by, ...)
async def revoke_share(share_id)
async def get_folder_user_shares(folder_id)
async def get_folder_link_shares(folder_id)
2.2 创建 FolderExportRepository
文件:server/app/repositories/folder_export_repository.py(新建)
功能:
- ✅ 导出任务创建
- ✅ 任务状态更新
- ✅ 下载链接设置
- ✅ 任务取消
- ✅ 过期任务清理
核心方法:
async def create(folder_id, user_id, format, ...)
async def update_status(job_id, status, progress, error_message)
async def set_download_url(job_id, file_url, file_size, expires_at)
async def cancel_job(job_id)
async def cleanup_expired_jobs()
3. 数据库迁移文件
文件:server/alembic/versions/20260202_152029_folder_service_implementation.py(新建)
3.1 创建表结构
folders 表:
- ✅ 所有字段(id, name, description, parent_folder_id, owner_id, path, level, folder_category, sort_order, color, icon, cover_image_id, is_shared, created_at, updated_at, deleted_at)
- ✅ 所有索引(包括部分索引、全文搜索索引)
- ✅ 唯一性约束(部分唯一索引处理 NULL 值)
- ✅ 表和字段注释
folder_members 表:
- ✅ 所有字段(id, folder_id, user_id, role, inherited, invited_by, created_at, updated_at)
- ✅ 所有索引
- ✅ 唯一约束(folder_id + user_id)
- ✅ 表和字段注释
folder_shares 表:
- ✅ 所有字段(id, folder_id, share_type, shared_with_user_id, role, share_token, access_level, password_hash, expires_at, access_count, created_by, created_at, revoked_at)
- ✅ 所有索引
- ✅ 表和字段注释
folder_export_jobs 表:
- ✅ 所有字段(id, folder_id, user_id, format, include_subfolders, include_resources, export_format, status, progress, file_url, file_size, estimated_size, error_message, created_at, started_at, completed_at, expires_at)
- ✅ 所有索引
- ✅ 表和字段注释
3.2 创建触发器
触发器函数:
- ✅
update_updated_at_column():自动更新 updated_at 字段 - ✅
update_folder_path():自动计算文件夹路径和层级 - ✅
inherit_folder_category():子文件夹自动继承父文件夹分类
触发器:
- ✅
update_folders_updated_at:folders 表更新时触发 - ✅
update_folder_path_trigger:folders 表插入/更新时触发 - ✅
trigger_inherit_folder_category:folders 表插入时触发 - ✅
update_folder_members_updated_at:folder_members 表更新时触发
3.3 扩展 projects 表
- ✅ 添加
folder_id字段(逻辑外键) - ✅ 创建索引
idx_projects_folder_id - ✅ 添加字段注释
4. Schema 层修复
文件:server/app/schemas/folder.py
变更:
- ✅
FolderMemberResponse:将joined_at改为updated_at
5. API 层修复
文件:server/app/api/v1/folders.py
变更:
- ✅ 添加成员接口:返回
updatedAt而非joinedAt - ✅ 更新成员角色接口:返回
updatedAt而非joinedAt - ✅ 获取成员列表接口:返回
updatedAt而非joinedAt
技术栈合规性
✅ 符合项
-
数据库设计:
- ✅ 使用 TIMESTAMPTZ 记录事件时间
- ✅ 枚举值使用 SMALLINT 存储
- ✅ 无物理外键约束,引用完整性由应用层保证
- ✅ 使用触发器自动计算和继承字段
- ✅ 使用部分唯一索引处理 NULL 值
-
Model 层:
- ✅ 所有模型类实现
__repr__方法 - ✅ 标准时间戳字段(created_at, updated_at)
- ✅ 使用
primaryjoin明确关联条件
- ✅ 所有模型类实现
-
Repository 层:
- ✅ 完整的 CRUD 操作
- ✅ 日志记录(使用 logger)
- ✅ 异常处理
-
迁移文件:
- ✅ 包含完整的表结构、索引、约束
- ✅ 包含触发器函数和触发器
- ✅ 包含表和字段注释
- ✅ 提供 downgrade 方法
执行迁移
1. 检查迁移状态
docker exec jointo-server-app alembic current
2. 执行迁移
docker exec jointo-server-app alembic upgrade head
3. 验证表结构
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d folders"
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d folder_members"
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d folder_shares"
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d folder_export_jobs"
4. 验证触发器
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\df update_folder_path"
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\df inherit_folder_category"
测试建议
1. Model 层测试
# 测试 __repr__ 方法
folder = Folder(id=uuid4(), name="测试文件夹", level=0)
assert repr(folder) == "<Folder(id=..., name='测试文件夹', level=0)>"
2. Repository 层测试
# 测试分享功能
share_repo = FolderShareRepository(session)
share = await share_repo.create_user_share(
folder_id=folder_id,
shared_with_user_id=user_id,
role=MemberRole.VIEWER,
created_by=owner_id
)
assert share.share_type == 'user'
3. 触发器测试
-- 测试路径自动计算
INSERT INTO folders (id, name, owner_id, folder_category)
VALUES (gen_random_uuid(), '根文件夹', 'user-id', 1);
-- 验证 path = '/根文件夹', level = 0
-- 测试分类自动继承
INSERT INTO folders (id, name, parent_folder_id, owner_id)
VALUES (gen_random_uuid(), '子文件夹', 'parent-id', 'user-id');
-- 验证 folder_category 自动继承父文件夹
影响范围
新增功能
- ✅ 文件夹分享功能(用户分享、链接分享)
- ✅ 文件夹导出功能(异步任务)
- ✅ 文件夹路径自动计算
- ✅ 文件夹分类自动继承
数据库变更
- ✅ 新增 4 张表
- ✅ 新增 3 个触发器函数
- ✅ 新增 4 个触发器
- ✅ projects 表新增 folder_id 字段
API 变更
- ✅ 成员响应字段变更(joined_at → updated_at)
后续工作
-
测试覆盖:
- 编写 Repository 层单元测试
- 编写 Service 层单元测试
- 编写 API 层集成测试
-
功能完善:
- 实现导出任务的 Celery Worker
- 实现分享链接的访问验证
- 实现文件夹权限继承逻辑
-
性能优化:
- 添加 Redis 缓存(文件夹树、权限)
- 优化递归查询(使用 CTE)
相关文档
- 需求文档:
docs/requirements/backend/04-services/project/folder-service.md - 技术栈规范:
.claude/skills/jointo-tech-stack/references/database.md - 数据库规范:
.claude/skills/jointo-tech-stack/references/backend.md
作者
AI Assistant
审核状态
待审核