feat(project): add workspace_id to issue/requirement with tri-state update

This commit is contained in:
2026-05-02 14:20:15 +08:00
parent 7429a817bc
commit 0cadec343c
17 changed files with 655 additions and 51 deletions
+24
View File
@@ -77,9 +77,12 @@ type Project struct {
}
// Requirement 表示一个项目内的需求。Number 在 (project_id) 内自增。
// WorkspaceID 为 nil 表示未关联任何 workspace;非 nil 时由 Service 层保证
// 该 workspace 与本 requirement 同 project(Plan 3 引入)。
type Requirement struct {
ID uuid.UUID
ProjectID uuid.UUID
WorkspaceID *uuid.UUID
Number int
Title string
Description string
@@ -93,10 +96,13 @@ type Requirement struct {
// Issue 可挂载到某个 Requirement,也可游离(RequirementID == nil)。
// AssigneeID 为 nil 表示未指派。CreatedBy 永远存在(DELETE RESTRICT)。
// WorkspaceID 为 nil 表示未关联 workspace;非 nil 时 DB 通过复合外键
// (project_id, workspace_id) 拒绝跨 project 关联(Plan 3 引入)。
type Issue struct {
ID uuid.UUID
ProjectID uuid.UUID
RequirementID *uuid.UUID
WorkspaceID *uuid.UUID
Number int
Title string
Description string
@@ -172,18 +178,27 @@ type UpdateProjectInput struct {
}
// CreateRequirementInput 创建一条需求。OwnerID 为 nil 时由 Service 默认为调用者。
// WorkspaceID 为 nil 表示不关联任何 workspace;非 nil 时直接落库(FK 由 PG 校验)。
type CreateRequirementInput struct {
Title string
Description string
OwnerID *uuid.UUID
WorkspaceID *uuid.UUID
}
// UpdateRequirementInput 同 UpdateProjectInput 的 patch 语义。Phase / Status 不在此处修改,
// 走专用方法 ChangePhase / Close / Reopen 以便 audit 区分。
//
// WorkspaceID 走"uuid.Nil sentinel"三态语义(与 RequirementNumber 的 **int 不同):
//
// nil —— 未提供(保持原 workspace_id 不变)
// &uuid.Nil —— 已提供,要求"解绑"(workspace_id 置 NULL)
// &id (非 Nil) —— 已提供,要求关联到指定 workspace
type UpdateRequirementInput struct {
Title *string
Description *string
OwnerID *uuid.UUID
WorkspaceID *uuid.UUID
}
// RequirementFilter 控制 List 时的过滤维度。Phase / Status 留零值("" / Status(""))表示
@@ -196,11 +211,13 @@ type RequirementFilter struct {
// CreateIssueInput 创建 Issue。RequirementNumber == nil 表示游离 Issue(不挂载到任何
// Requirement);非 nil 时 Service 会校验 1) 该 Requirement 与目标 Project 同属,
// 2) 未关闭。
// WorkspaceID 为 nil 表示不关联 workspace;非 nil 时 DB 复合 FK 保证同 project。
type CreateIssueInput struct {
Title string
Description string
RequirementNumber *int
AssigneeID *uuid.UUID
WorkspaceID *uuid.UUID
}
// UpdateIssueInput 是 Issue 的 patch 输入。RequirementNumber 为指针的指针,承载三种状态:
@@ -210,10 +227,17 @@ type CreateIssueInput struct {
// *x != nil —— 已提供,要求"挂载到本项目下 number=**x 的 Requirement"
//
// HTTP 层用 json.RawMessage 区分 "字段缺省 vs 显式 null vs 数字",再翻译为本三态。
//
// WorkspaceID 走"uuid.Nil sentinel"三态语义(不再嵌一层指针):
//
// nil —— 未提供(保持原 workspace_id 不变)
// &uuid.Nil —— 已提供,要求"解绑"(workspace_id 置 NULL)
// &id (非 Nil) —— 已提供,要求关联到指定 workspace(DB FK 校验同 project)
type UpdateIssueInput struct {
Title *string
Description *string
RequirementNumber **int
WorkspaceID *uuid.UUID
}
// IssueFilter 控制 List 时的过滤。Requirement 字段三态(与 sqlc requirement_filter