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.
 

7.9 KiB

从新建项目到拆完分镜存储的完整流程

%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#e3f2fd','primaryTextColor':'#000','primaryBorderColor':'#1976d2','lineColor':'#424242','secondaryColor':'#fff3e0','tertiaryColor':'#f3e5f5','noteBkgColor':'#fff9c4','noteTextColor':'#000','noteBorderColor':'#fbc02d'}}}%%
sequenceDiagram
    autonumber
    
    actor User as 用户
    participant ProjectAPI as API Layer<br/>/api/v1/projects
    participant ProjectService as ProjectService
    participant ProjectRepo as ProjectRepository
    participant ProjectDB as PostgreSQL<br/>projects 表
    
    participant StoryboardAPI as API Layer<br/>/api/v1/storyboards
    participant StoryboardService as StoryboardService
    participant StoryboardRepo as StoryboardRepository
    participant StoryboardDB as PostgreSQL<br/>storyboards 表
    participant ItemDB as PostgreSQL<br/>storyboard_items 表

    %% 阶段 1: 创建项目
    rect rgb(227, 242, 253)
        Note over User,ProjectDB: 阶段 1: 创建项目
        
        User->>+ProjectAPI: POST /api/v1/projects<br/>{name, type, sharedResources, ...}
        ProjectAPI->>+ProjectService: create_project(user_id, project_data)
        
        Note right of ProjectService: 验证逻辑<br/>1. 检查文件夹权限<br/>2. 检查名称唯一性<br/>3. 转换枚举值
        
        ProjectService->>+ProjectRepo: create(project)
        ProjectRepo->>+ProjectDB: INSERT INTO projects<br/>(id, name, type, owner_id, ...)
        ProjectDB-->>-ProjectRepo: project_id (UUID v7)
        ProjectRepo-->>-ProjectService: Project 对象
        
        alt 协作项目 (type = "collab")
            ProjectService->>ProjectRepo: add_member(project_id, user_id, OWNER)
            ProjectRepo->>ProjectDB: INSERT INTO project_members
        end
        
        alt 有共享资源 (shared_resources)
            ProjectService->>ProjectService: 调用 ProjectResourceShareService<br/>创建共享资源关联
            Note right of ProjectService: ADR 02: 跨项目资源共享<br/>存储到 project_resource_shares 表
            
            loop 处理每个共享配置
                alt source_type = "folder"
                    ProjectService->>ProjectDB: 查询文件夹下的所有父项目
                    ProjectDB-->>ProjectService: 返回项目列表
                    loop 为每个项目创建共享记录
                        ProjectService->>ProjectDB: INSERT INTO project_resource_shares<br/>(source_project_id, target_project_id,<br/>share_type=1, status=1)
                    end
                else source_type = "project"
                    ProjectService->>ProjectDB: INSERT INTO project_resource_shares<br/>(source_project_id, target_project_id,<br/>share_type=1, status=1)
                else source_type = "resource"
                    ProjectService->>ProjectDB: INSERT INTO project_resource_shares<br/>(source_project_id, target_project_id,<br/>share_type=3, resource_type, resource_id,<br/>status=1)
                end
            end
        end
        
        ProjectService-->>-ProjectAPI: Project 对象
        ProjectAPI-->>-User: 200 OK<br/>{id, name, type, status, ...}
        
        Note over User: 项目创建完成<br/>- 项目 ID: UUID v7<br/>- 状态: active<br/>- 类型: mine/collab
    end

    %% 阶段 2: 创建分镜
    rect rgb(255, 243, 224)
        Note over User,ItemDB: 阶段 2: 创建分镜
        
        User->>+StoryboardAPI: POST /api/v1/storyboards<br/>{projectId, title, description, ...}
        StoryboardAPI->>+StoryboardService: create_storyboard(user_id, project_id, title, ...)
        
        Note right of StoryboardService: 分镜创建逻辑<br/>1. 检查项目权限 (editor)<br/>2. 获取下一个 order_index<br/>3. 计算 end_time<br/>4. 默认时长 5 秒
        
        StoryboardService->>+ProjectRepo: check_user_permission(user_id, project_id, 'editor')
        ProjectRepo->>ProjectDB: SELECT FROM projects/project_members
        ProjectDB-->>ProjectRepo: 权限验证结果
        ProjectRepo-->>-StoryboardService: has_permission = True
        
        StoryboardService->>+StoryboardRepo: get_max_order(project_id)
        StoryboardRepo->>StoryboardDB: SELECT MAX(order_index)<br/>FROM storyboards<br/>WHERE project_id = ?
        StoryboardDB-->>StoryboardRepo: max_order (例如: 5)
        StoryboardRepo-->>-StoryboardService: max_order = 5
        
        Note right of StoryboardService: 计算顺序索引<br/>order_index = max_order + 1<br/>例如: 5 + 1 = 6
        
        StoryboardService->>+StoryboardRepo: create(storyboard)
        StoryboardRepo->>+StoryboardDB: INSERT INTO storyboards<br/>(storyboard_id, project_id, title,<br/>order_index, start_time, end_time, ...)
        StoryboardDB-->>-StoryboardRepo: storyboard_id (UUID v7)
        StoryboardRepo-->>-StoryboardService: Storyboard 对象
        
        StoryboardService-->>-StoryboardAPI: Storyboard 对象
        StoryboardAPI-->>-User: 200 OK<br/>{storyboardId, orderIndex, startTime, ...}
        
        Note over User: 分镜创建完成<br/>- 分镜 ID: UUID v7<br/>- 镜号: order_index<br/>- 时间轴: start_time → end_time
    end

    %% 阶段 3: 添加元素到分镜
    rect rgb(243, 229, 245)
        Note over User,ItemDB: 阶段 3: 添加元素到分镜 (循环)
        
        loop 为每个分镜添加元素
            User->>+StoryboardAPI: POST /api/v1/storyboards/{id}/items<br/>{itemType, elementTagId/resourceId, ...}
            StoryboardAPI->>+StoryboardService: add_element_to_storyboard(user_id, storyboard_id, ...)
            
            Note right of StoryboardService: 元素类型验证<br/>item_type = 1: 剧本元素标签<br/>item_type = 2: 项目素材
            
            StoryboardService->>+StoryboardRepo: get_by_id(storyboard_id)
            StoryboardRepo->>StoryboardDB: SELECT FROM storyboards
            StoryboardDB-->>StoryboardRepo: Storyboard 对象
            StoryboardRepo-->>-StoryboardService: Storyboard 对象
            
            StoryboardService->>ProjectRepo: check_user_permission(user_id, project_id, 'editor')
            ProjectRepo->>ProjectDB: 权限验证
            ProjectDB-->>ProjectRepo: 验证结果
            ProjectRepo-->>StoryboardService: has_permission = True
            
            alt item_type = 1 (剧本元素标签)
                Note right of StoryboardService: 验证 element_tag_id 存在<br/>获取标签信息
            else item_type = 2 (项目素材)
                Note right of StoryboardService: 验证 resource_id 存在<br/>获取素材信息
            end
            
            StoryboardService->>+StoryboardRepo: get_max_display_order(storyboard_id)
            StoryboardRepo->>ItemDB: SELECT MAX(display_order)<br/>FROM storyboard_items
            ItemDB-->>StoryboardRepo: max_order (例如: 3)
            StoryboardRepo-->>-StoryboardService: max_order = 3
            
            Note right of StoryboardService: 计算显示顺序<br/>display_order = max_order + 1<br/>例如: 3 + 1 = 4
            
            StoryboardService->>+StoryboardRepo: create_item(item)
            StoryboardRepo->>+ItemDB: INSERT INTO storyboard_items<br/>(item_id, storyboard_id, item_type,<br/>element_tag_id, resource_id, ...)
            ItemDB-->>-StoryboardRepo: item_id (UUID v7)
            StoryboardRepo-->>-StoryboardService: StoryboardItem 对象
            
            alt item_type = 2 (项目素材)
                StoryboardService->>ProjectDB: UPDATE project_resources<br/>SET usage_count = usage_count + 1
                Note right of StoryboardService: 增加素材引用计数
            end
            
            StoryboardService-->>-StoryboardAPI: StoryboardItem 对象
            StoryboardAPI-->>-User: 200 OK<br/>{itemId, itemType, displayOrder, ...}
        end
        
        Note over User: 分镜元素添加完成<br/>- 元素 ID: UUID v7<br/>- 元素类型: 标签/素材<br/>- 显示顺序: display_order
    end