# 项目管理服务 - 流程图与关系图
> **文档版本**:v1.0
> **最后更新**:2026-02-02
> **关联文档**:[项目管理服务](./project-service.md)
---
## 目录
1. [数据库表关系图](#数据库表关系图)
2. [项目创建流程图](#项目创建流程图)
3. [项目克隆流程图](#项目克隆流程图)
4. [权限检查流程图](#权限检查流程图)
5. [项目生命周期状态图](#项目生命周期状态图)
6. [子项目关系图](#子项目关系图)
---
## 数据库表关系图
```mermaid
erDiagram
projects ||--o{ project_members : "has members"
projects ||--o{ project_shares : "has shares"
projects ||--o{ project_versions : "has versions"
projects ||--o{ projects : "parent-child"
projects }o--|| users : "owned by"
projects }o--o| folders : "belongs to"
projects }o--o| screenplays : "linked to"
projects }o--o| attachments : "cover image"
projects {
uuid project_id PK "UUID v7"
text name "项目名称"
smallint type "1=mine, 2=collab"
text owner_type "user | organization"
uuid owner_id FK "逻辑外键"
uuid folder_id FK "逻辑外键"
uuid parent_project_id FK "父项目ID"
uuid screenplay_id FK "剧本ID(子项目)"
uuid cover_image_id FK "封面图片ID"
smallint content_type "1=ad, 2=movie..."
smallint aspect_ratio "1=16:9, 2=9:16..."
integer planned_duration "计划时长(秒)"
integer actual_duration "实际时长(秒)"
text visual_style "视觉风格"
jsonb settings "项目配置"
smallint status "0=active, 2=trashed, 3=deleted"
timestamptz created_at
timestamptz updated_at
timestamptz trashed_at
timestamptz deleted_at
}
project_members {
uuid member_id PK "UUID v7"
uuid project_id FK "逻辑外键"
uuid user_id FK "逻辑外键"
smallint role "1=owner, 2=editor, 3=viewer"
uuid invited_by FK "邀请人ID"
timestamptz created_at
timestamptz updated_at
}
project_shares {
uuid share_id PK "UUID v7"
uuid project_id FK "逻辑外键"
text share_token UK "分享令牌"
text password_hash "密码哈希"
smallint permission "1=viewer, 2=editor"
uuid created_by FK "创建者ID"
timestamptz created_at
timestamptz expires_at
timestamptz last_accessed_at
integer access_count
}
project_versions {
uuid version_id PK "UUID v7"
uuid project_id FK "逻辑外键"
integer version_number "版本号"
jsonb snapshot_data "项目快照"
uuid created_by FK "创建者ID"
text note "版本说明"
timestamptz created_at
}
users {
uuid user_id PK
text nickname
}
folders {
uuid folder_id PK
text name
}
screenplays {
uuid screenplay_id PK
text title
}
attachments {
uuid attachment_id PK
text file_url
}
```
**说明**:
- 所有外键关系均为**逻辑外键**(无物理约束)
- 引用完整性由应用层(Service/Repository)保证
- `projects` 表支持自引用(父子项目关系)
- 子项目必须关联剧本(`parent_project_id` 和 `screenplay_id` 同时存在或同时为空)
---
## 项目创建流程图
```mermaid
flowchart TD
Start([用户请求创建项目]) --> ValidateAuth{验证用户身份}
ValidateAuth -->|未登录| Error1[返回 401 未授权]
ValidateAuth -->|已登录| ValidateUser{校验用户存在性}
ValidateUser -->|用户不存在| Error2[返回 400 用户不存在]
ValidateUser -->|用户存在| CheckFolder{是否指定文件夹?}
CheckFolder -->|是| ValidateFolder{校验文件夹存在性}
CheckFolder -->|否| CheckCover
ValidateFolder -->|文件夹不存在| Error3[返回 400 文件夹不存在]
ValidateFolder -->|文件夹存在| CheckFolderPerm{检查文件夹权限}
CheckFolderPerm -->|无权限| Error4[返回 403 无权限]
CheckFolderPerm -->|有权限| CheckCover
CheckCover{是否指定封面图片?} -->|是| ValidateCover{校验附件存在性和所属权}
CheckCover -->|否| ValidateType
ValidateCover -->|附件不存在或无权限| Error5[返回 400/403]
ValidateCover -->|校验通过| ValidateType
ValidateType{验证项目类型} -->|无效类型| Error6[返回 400 无效类型]
ValidateType -->|有效类型| GenerateUUID[生成 UUID v7]
GenerateUUID --> CreateProject[创建项目记录]
CreateProject --> CheckCollab{是否为协作项目?}
CheckCollab -->|是| AddOwnerMember[添加创建者为成员
role=owner]
CheckCollab -->|否| LogCreate
AddOwnerMember --> LogCreate[记录日志]
LogCreate --> Success([返回项目信息])
style Start fill:#e1f5e1
style Success fill:#e1f5e1
style Error1 fill:#ffe1e1
style Error2 fill:#ffe1e1
style Error3 fill:#ffe1e1
style Error4 fill:#ffe1e1
style Error5 fill:#ffe1e1
style Error6 fill:#ffe1e1
```
**流程说明**:
1. **身份验证**:检查用户登录状态
2. **用户校验**:确认用户存在(引用完整性)
3. **文件夹校验**:如果指定文件夹,检查存在性和权限
4. **封面图片校验**:如果指定封面,检查附件存在性和所属权
5. **类型验证**:确保项目类型为 `mine` 或 `collab`
6. **UUID 生成**:应用层生成 UUID v7
7. **创建项目**:插入数据库记录
8. **成员管理**:协作项目自动添加创建者为 owner
9. **日志记录**:记录操作日志
---
## 项目克隆流程图
```mermaid
flowchart TD
Start([用户请求克隆项目]) --> CheckPerm{检查源项目权限}
CheckPerm -->|无权限| Error1[返回 403 无权限]
CheckPerm -->|有 viewer 权限| GetSource[获取源项目信息]
GetSource --> GenerateName[生成唯一副本名称
基础名称-副本N]
GenerateName --> CreateTask{创建异步任务}
CreateTask --> ReturnTaskId[返回 task_id
status=pending]
ReturnTaskId --> AsyncStart([异步任务开始])
AsyncStart --> CloneBasic[复制项目基本信息]
CloneBasic --> CloneSettings[复制项目配置]
CloneSettings --> CloneStoryboards{复制分镜?}
CloneStoryboards -->|是| CopyStoryboards[复制所有分镜]
CloneStoryboards -->|否| CloneResources
CopyStoryboards --> CloneResources{复制资源?}
CloneResources -->|是| CopyResources[复制视频/附件]
CloneResources -->|否| UpdateProgress
CopyResources --> UpdateProgress[更新任务进度]
UpdateProgress --> Commit[提交事务]
Commit --> Success{克隆成功?}
Success -->|是| TaskComplete[任务状态=completed
progress=100]
Success -->|否| TaskFailed[任务状态=failed
记录错误信息]
TaskComplete --> End([用户查询任务状态])
TaskFailed --> End
style Start fill:#e1f5e1
style End fill:#e1f5e1
style Error1 fill:#ffe1e1
style AsyncStart fill:#fff4e1
style TaskComplete fill:#e1f5e1
style TaskFailed fill:#ffe1e1
```
**流程说明**:
1. **权限检查**:确保用户至少有 viewer 权限
2. **名称生成**:自动生成唯一的副本名称(避免重名)
3. **异步任务**:创建任务并立即返回 task_id
4. **基本信息复制**:复制项目名称、描述、类型等
5. **配置复制**:复制 settings(分辨率、帧率等)
6. **分镜复制**:复制所有分镜及其关联资源
7. **资源复制**:复制视频、附件等文件
8. **进度更新**:实时更新任务进度
9. **状态通知**:任务完成或失败后更新状态
---
## 权限检查流程图
```mermaid
flowchart TD
Start([检查用户权限]) --> GetProject{获取项目信息}
GetProject -->|项目不存在| Return1[返回 False]
GetProject -->|项目存在| CheckOwner{是否为项目所有者?}
CheckOwner -->|是| Return2[返回 True
所有者拥有所有权限]
CheckOwner -->|否| CheckType{项目类型?}
CheckType -->|个人项目 mine| Return3[返回 False
非所有者无权限]
CheckType -->|协作项目 collab| QueryMember[查询成员表
project_members]
QueryMember --> IsMember{是否为成员?}
IsMember -->|否| Return4[返回 False]
IsMember -->|是| GetRole[获取成员角色]
GetRole --> CompareRole{角色权限对比}
CompareRole --> CalcHierarchy[权限层级:
owner=3
editor=2
viewer=1]
CalcHierarchy --> CheckRequired{成员权限 >= 所需权限?}
CheckRequired -->|是| Return5[返回 True]
CheckRequired -->|否| Return6[返回 False]
style Start fill:#e1f5e1
style Return2 fill:#e1f5e1
style Return5 fill:#e1f5e1
style Return1 fill:#ffe1e1
style Return3 fill:#ffe1e1
style Return4 fill:#ffe1e1
style Return6 fill:#ffe1e1
```
**权限层级说明**:
- `owner` (3):所有权限(创建、编辑、删除、管理成员、分享)
- `editor` (2):编辑权限(创建、编辑分镜和资源)
- `viewer` (1):查看权限(只读访问)
**权限检查逻辑**:
1. **项目所有者**:自动拥有所有权限
2. **个人项目**:只有所有者有权限
3. **协作项目**:检查成员表中的角色
4. **权限对比**:成员角色权限 >= 所需权限时通过
**示例**:
- 用户角色为 `editor`,所需权限为 `viewer` → 通过(2 >= 1)
- 用户角色为 `viewer`,所需权限为 `editor` → 拒绝(1 < 2)
---
## 项目生命周期状态图
```mermaid
stateDiagram-v2
[*] --> Active: 创建项目
Active --> Archived: 用户归档
Archived --> Active: 取消归档
Active --> Trashed: 移至回收站
(DELETE /projects/{id})
Archived --> Trashed: 移至回收站
Trashed --> Active: 从回收站恢复
(POST /projects/{id}/restore)
Trashed --> SoftDeleted: 永久删除
(DELETE /projects/{id}/permanent)
Trashed --> SoftDeleted: 30天后自动清理
SoftDeleted --> [*]: 物理删除
(仅管理员)
note right of Active
status = 0
用户可见、可编辑
end note
note right of Archived
status = 1
用户可见、只读
end note
note right of Trashed
status = 2
回收站可见
30天内可恢复
trashed_at 记录时间
end note
note right of SoftDeleted
status = 3
用户不可见
数据保留
deleted_at 记录时间
end note
```
**状态说明**:
| 状态 | 数值 | 用户可见 | 可编辑 | 说明 |
|------|------|---------|--------|------|
| **Active** | 0 | ✅ | ✅ | 活跃项目,正常使用 |
| **Archived** | 1 | ✅ | ❌ | 归档项目,只读(预留功能) |
| **Trashed** | 2 | ⚠️ | ❌ | 回收站,30天内可恢复 |
| **SoftDeleted** | 3 | ❌ | ❌ | 软删除,用户不可见,数据保留 |
**状态转换规则**:
1. **创建项目** → Active
2. **用户归档** → Active ↔ Archived(预留功能)
3. **移至回收站** → Active/Archived → Trashed
4. **从回收站恢复** → Trashed → Active
5. **永久删除** → Trashed → SoftDeleted
6. **自动清理** → Trashed(30天后)→ SoftDeleted
7. **物理删除** → SoftDeleted → 数据库删除(仅管理员)
**回收站机制**:
- 用户删除项目时,状态变为 `Trashed`,设置 `trashed_at`
- 30天内可通过 API 恢复
- 30天后自动转为 `SoftDeleted`
- 用户可在回收站中立即永久删除(转为 `SoftDeleted`)
---
## 子项目关系图
```mermaid
flowchart TD
subgraph "父项目 (Parent Project)"
P1[项目: 电视剧制作
parent_project_id = NULL
screenplay_id = NULL]
end
subgraph "子项目 (Subprojects)"
S1[子项目: 第1集
parent_project_id = P1.id
screenplay_id = SC1.id]
S2[子项目: 第2集
parent_project_id = P1.id
screenplay_id = SC2.id]
S3[子项目: 第3集
parent_project_id = P1.id
screenplay_id = SC3.id]
end
subgraph "剧本 (Screenplays)"
SC1[剧本: 第1集剧本
screenplay_id = SC1]
SC2[剧本: 第2集剧本
screenplay_id = SC2]
SC3[剧本: 第3集剧本
screenplay_id = SC3]
end
P1 -->|创建子项目| S1
P1 -->|创建子项目| S2
P1 -->|创建子项目| S3
S1 -.->|关联剧本
一对一| SC1
S2 -.->|关联剧本
一对一| SC2
S3 -.->|关联剧本
一对一| SC3
subgraph "继承关系"
I1[权限继承:
子项目继承父项目的成员权限]
I2[设置继承:
子项目复制父项目的 settings]
I3[文件夹继承:
子项目与父项目在同一文件夹]
end
P1 -.->|继承| I1
P1 -.->|继承| I2
P1 -.->|继承| I3
style P1 fill:#e1f5e1
style S1 fill:#fff4e1
style S2 fill:#fff4e1
style S3 fill:#fff4e1
style SC1 fill:#e1e5ff
style SC2 fill:#e1e5ff
style SC3 fill:#e1e5ff
```
**子项目特性**:
1. **一对一关系**:每个子项目关联一个剧本
2. **权限继承**:子项目自动继承父项目的成员权限
3. **设置继承**:子项目复制父项目的配置(分辨率、帧率等)
4. **独立管理**:子项目可独立管理分镜、资源、导出等
5. **自动创建**:上传剧本时自动创建子项目
**数据库约束**:
```sql
-- 子项目约束:parent_project_id 和 screenplay_id 必须同时存在或同时为空
CONSTRAINT projects_subproject_screenplay_check CHECK (
(parent_project_id IS NULL AND screenplay_id IS NULL) OR
(parent_project_id IS NOT NULL AND screenplay_id IS NOT NULL)
)
```
**使用场景**:
- **电视剧制作**:父项目为整部剧,每集为一个子项目
- **系列广告**:父项目为广告系列,每个广告为一个子项目
- **多章节内容**:父项目为整体内容,每章节为一个子项目
**API 接口**:
```bash
# 获取子项目列表
GET /api/v1/projects/{parent_project_id}/subprojects
# 创建子项目(通常由剧本服务自动调用)
POST /api/v1/projects/{parent_project_id}/subprojects
```
---
## 相关文档
- [项目管理服务](./project-service.md) - 服务实现、API 接口、数据库设计
- [项目资源管理服务](./project-resource-service.md) - 项目资源关联管理
- [文件夹管理服务](../folder/folder-service.md) - 文件夹权限和归属
- [剧本管理服务](../screenplay/screenplay-service.md) - 剧本与子项目关联
---
**文档版本**:v1.0
**最后更新**:2026-02-02