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.
 

10 KiB

RFC 121: 项目服务实现

状态:已实现
创建时间:2026-01-20
实现时间:2026-01-20
作者:System


概述

实现项目管理服务的核心功能,包括 CRUD 操作、权限管理、成员管理、搜索筛选、分享功能等。


背景

项目(Project)是系统的核心实体,用户通过项目组织和管理分镜、视频等资源。需要实现完整的项目管理功能以支持业务需求。


目标

主要目标

  1. 实现项目的完整 CRUD 操作
  2. 实现三级权限管理(owner/editor/viewer)
  3. 支持协作项目的成员管理
  4. 实现全文搜索和多条件筛选
  5. 实现项目分享功能
  6. 为异步任务预留接口

非目标

  • 异步任务队列实现(后续 RFC)
  • 版本控制功能(后续 RFC)
  • 企业功能(V2)

技术方案

架构设计

采用三层架构:

API Layer (projects.py)
    ↓
Service Layer (project_service.py)
    ↓
Repository Layer (project_repository.py)
    ↓
Model Layer (project.py)

数据模型

1. Project(项目表)

class Project(SQLModel, table=True):
    id: UUID  # UUID v7 主键
    name: str
    description: Optional[str]
    type: ProjectType  # mine | collab
    owner_type: str  # V1: 固定为 'user'
    owner_id: UUID
    folder_id: Optional[UUID]
    display_order: int
    content_type: Optional[ProjectContentType]
    aspect_ratio: Optional[AspectRatioType]
    planned_duration: Optional[int]
    actual_duration: Optional[int]
    style_and_characters: Optional[str]
    settings: dict  # JSONB
    status: ProjectStatus
    created_at: datetime
    updated_at: datetime
    deleted_at: Optional[datetime]

2. ProjectMember(成员表)

class ProjectMember(SQLModel, table=True):
    id: UUID
    project_id: UUID
    user_id: UUID
    role: MemberRole  # owner | editor | viewer
    invited_by: Optional[UUID]
    joined_at: datetime
    created_at: datetime

3. ProjectShare(分享表)

class ProjectShare(SQLModel, table=True):
    id: UUID
    project_id: UUID
    share_token: str  # 唯一令牌
    password_hash: Optional[str]
    permission: SharePermission  # viewer | editor
    created_by: UUID
    created_at: datetime
    expires_at: Optional[datetime]
    last_accessed_at: Optional[datetime]
    access_count: int

4. ProjectVersion(版本表,预留)

class ProjectVersion(SQLModel, table=True):
    id: UUID
    project_id: UUID
    version_number: int
    snapshot_data: dict  # JSONB
    created_by: UUID
    note: Optional[str]
    created_at: datetime

核心功能实现

1. 搜索和筛选

实现方式

  • 使用 pg_trgm 扩展支持全文搜索
  • 在 name 和 description 字段上创建 GIN 索引
  • 使用 ILIKE 进行模糊匹配

查询条件

  • type: 项目类型(mine/collab)
  • folder_id: 所属文件夹
  • content_type: 内容类型
  • search: 关键词搜索

排序支持

  • created_at: 创建时间
  • updated_at: 更新时间
  • name: 名称
  • display_order: 自定义顺序

2. 权限管理

权限级别

  1. Owner:完全控制权(删除、添加成员、创建分享)
  2. Editor:编辑权限(修改项目、移动项目)
  3. Viewer:只读权限(查看项目)

权限检查逻辑

async def check_user_permission(user_id, project_id, required_role):
    # 1. 检查是否为所有者
    if project.owner_id == user_id:
        return True
    
    # 2. 检查成员权限
    member = await get_member(project_id, user_id)
    if member:
        return compare_role(member.role, required_role)
    
    return False

3. 分享功能

分享链接生成

share_token = secrets.token_urlsafe(32)
share_url = f"/share/p/{share_token}"

特性

  • 密码保护(可选)
  • 过期时间(可选)
  • 权限控制(viewer/editor)
  • 访问统计

4. 克隆功能

当前实现:同步版本

async def clone_project(source_project, new_name, owner_id, folder_id):
    # 1. 复制项目基本信息
    new_project = Project(...)
    
    # 2. TODO: 复制关联资源(分镜、视频、附件)
    # 需要等待相关模型实现
    
    return new_project

限制

  • 大项目可能超时
  • 暂不复制关联资源

TODO

  • 实现异步任务队列
  • 复制关联资源

5. 导出功能

当前实现:接口框架

async def export_project(user_id, project_id):
    return {
        'task_id': 'dev-placeholder',
        'status': 'pending',
        'message': '导出功能开发中,敬请期待'
    }

TODO

  • 实现异步任务队列
  • 实现 ZIP 打包逻辑
  • 实现文件下载管理

API 设计

端点列表

方法 路径 描述 权限
GET /projects 获取项目列表 认证
POST /projects 创建项目 认证
GET /projects/{id} 获取详情 viewer
PUT /projects/{id} 更新项目 editor
DELETE /projects/{id} 删除项目 owner
POST /projects/{id}/move 移动项目 editor
POST /projects/{id}/clone 克隆项目 viewer
POST /projects/{id}/export 导出项目 viewer
POST /projects/{id}/shares 创建分享 owner
GET /projects/{id}/shares 获取分享列表 viewer
DELETE /projects/{id}/shares/{share_id} 撤销分享 owner
PUT /projects/{id}/order 更新排序 editor
GET /projects/{id}/members 获取成员列表 viewer
POST /projects/{id}/members 添加成员 owner
DELETE /projects/{id}/members/{user_id} 移除成员 owner

请求示例

创建项目

POST /api/v1/projects
Content-Type: application/json

{
  "name": "我的广告片",
  "description": "2026年春节广告",
  "type": "mine",
  "folderId": "uuid-here",
  "contentType": "ad",
  "aspectRatio": "16:9",
  "plannedDuration": 60,
  "settings": {
    "resolution": "1920x1080",
    "fps": 30
  }
}

搜索项目

GET /api/v1/projects?search=广告&contentType=ad&sortBy=updated_at&sortOrder=desc&page=1&pageSize=20

创建分享

POST /api/v1/projects/{id}/shares
Content-Type: application/json

{
  "password": "optional-password",
  "permission": "viewer",
  "expiresAt": "2026-02-01T00:00:00Z"
}

数据库设计

表结构

projects 表

CREATE TABLE projects (
    project_id UUID PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    type project_type NOT NULL DEFAULT 'mine',
    owner_type VARCHAR(20) NOT NULL DEFAULT 'user',
    owner_id UUID NOT NULL REFERENCES users(user_id),
    folder_id UUID REFERENCES folders(id),
    display_order INTEGER NOT NULL DEFAULT 0,
    thumbnail_url VARCHAR(500),
    cover_image_id UUID,
    ai_credits_budget INTEGER NOT NULL DEFAULT 0,
    budget_consumed INTEGER NOT NULL DEFAULT 0,
    content_type project_content_type,
    aspect_ratio aspect_ratio_type,
    planned_duration INTEGER,
    actual_duration INTEGER,
    style_and_characters TEXT,
    settings JSONB NOT NULL DEFAULT '{}',
    status project_status NOT NULL DEFAULT 'active',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    deleted_at TIMESTAMPTZ,
    CONSTRAINT projects_name_unique UNIQUE NULLS NOT DISTINCT (folder_id, name, owner_id)
);

索引策略

基础索引

  • idx_projects_owner: (owner_type, owner_id)
  • idx_projects_folder_id: (folder_id)
  • idx_projects_type: (type)
  • idx_projects_status: (status)

时间索引

  • idx_projects_created_at: (created_at)
  • idx_projects_updated_at: (updated_at)

全文搜索索引

  • idx_projects_name_trgm: GIN (name gin_trgm_ops)
  • idx_projects_description_trgm: GIN (description gin_trgm_ops)

JSONB 索引

  • idx_projects_settings_gin: GIN (settings)

实现细节

文件清单

新建文件(6 个):

  1. server/app/models/project.py - 数据模型
  2. server/app/schemas/project.py - Schema 定义
  3. server/app/repositories/project_repository.py - 数据访问层
  4. server/app/services/project_service.py - 业务逻辑层
  5. server/app/api/v1/projects.py - API 路由
  6. server/app/migrations/003_project_tables.py - 数据库迁移

修改文件(2 个):

  1. server/app/api/v1/router.py - 添加路由注册
  2. docs/requirements/backend/04-services/project/project-service.md - 更新文档

代码统计

  • 模型层:~250 行
  • Schema 层:~300 行
  • Repository 层:~450 行
  • Service 层:~500 行
  • API 层:~400 行
  • 迁移脚本:~250 行

总计:~2150 行代码


测试策略

单元测试

Repository 层

  • 测试 CRUD 操作
  • 测试查询和筛选
  • 测试权限检查

Service 层

  • 测试业务逻辑
  • 测试权限验证
  • 测试异常处理

集成测试

API 层

  • 测试所有端点
  • 测试认证和授权
  • 测试错误响应

性能测试

  • 搜索性能(1000+ 项目)
  • 分页性能
  • 索引效率

风险和限制

已知限制

  1. 克隆功能

    • 同步执行,大项目可能超时
    • 暂不复制关联资源
  2. 导出功能

    • 仅返回开发中状态
    • 需要异步任务队列支持
  3. 全文搜索

    • 使用 ILIKE,性能一般
    • 可升级为 similarity 函数

技术债务

  1. 权限继承逻辑需要完善
  2. 批量操作支持
  3. 项目统计信息
  4. 搜索性能优化

后续工作

短期(1-2 周)

  1. 实现异步任务队列(Celery/ARQ)
  2. 完善克隆功能(复制关联资源)
  3. 实现导出功能

中期(1-2 月)

  1. 实现版本控制功能
  2. 优化全文搜索性能
  3. 实现批量操作

长期(3+ 月)

  1. 企业功能支持(V2)
  2. 项目模板功能
  3. 项目分析和统计

参考资料


RFC 状态:已实现
实现时间:2026-01-20