You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
+176
-3
@@ -40,9 +40,10 @@ func (p Phase) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ArtifactPhases 是允许产出文档型产物的三个阶段(与 requirement_artifacts.phase
|
||||
// CHECK 约束一致):实施/验收阶段的产出是代码(走 ACP),不在此列。
|
||||
var ArtifactPhases = []Phase{PhasePlanning, PhasePrototyping, PhaseAuditing}
|
||||
// ArtifactPhases 是允许产出文档型产物的五个阶段(与 requirement_artifacts.phase
|
||||
// CHECK 约束一致):implementing/reviewing 的产出是审计报告 / 评审记录(也是文档型
|
||||
// 产物),done 阶段是汇总视图、不单独建产物,故只留前五阶段。
|
||||
var ArtifactPhases = []Phase{PhasePlanning, PhasePrototyping, PhaseAuditing, PhaseImplementing, PhaseReviewing}
|
||||
|
||||
// IsArtifactPhase 报告 p 是否允许创建产物版本。
|
||||
func (p Phase) IsArtifactPhase() bool {
|
||||
@@ -54,6 +55,23 @@ func (p Phase) IsArtifactPhase() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verdict 是单个产物版本的评审结论,与 requirement_artifacts.verdict CHECK 一致。
|
||||
// 'none' 为默认(未评审);'pass' 表示通过、可作为阶段网关的"已批准产物";'fail'
|
||||
// 表示驳回。仅 'pass' 会被 ArtifactService.Approve 写入阶段指针。
|
||||
type Verdict string
|
||||
|
||||
// 评审结论枚举值。
|
||||
const (
|
||||
VerdictNone Verdict = "none"
|
||||
VerdictPass Verdict = "pass"
|
||||
VerdictFail Verdict = "fail"
|
||||
)
|
||||
|
||||
// IsValid 报告 v 是否在枚举集合内。
|
||||
func (v Verdict) IsValid() bool {
|
||||
return v == VerdictNone || v == VerdictPass || v == VerdictFail
|
||||
}
|
||||
|
||||
// Status 是 Requirement / Issue 通用的开/关状态。
|
||||
type Status string
|
||||
|
||||
@@ -127,6 +145,22 @@ type Issue struct {
|
||||
ClosedAt *time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
// ParentID 非 nil 表示本 issue 是某 issue 的子任务(任务分解)。父删除时
|
||||
// ON DELETE SET NULL 置空(orphan,不级联删子)。
|
||||
ParentID *uuid.UUID
|
||||
// Priority 0..3,越大越早被调度器选取。默认 0(normal)。
|
||||
Priority int
|
||||
}
|
||||
|
||||
// Dependency 表示一条 issue 依赖边:BlockedID 被 BlockerID 阻塞(blocked-by)。
|
||||
// BlockedID 仅在 BlockerID 关闭后才"就绪"。ProjectID 冗余存储用于作用域校验。
|
||||
type Dependency struct {
|
||||
ID uuid.UUID
|
||||
ProjectID uuid.UUID
|
||||
BlockedID uuid.UUID
|
||||
BlockerID uuid.UUID
|
||||
CreatedBy uuid.UUID
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// Artifact 是某条 Requirement 在某阶段的一个产物文档版本快照。Version 在
|
||||
@@ -143,6 +177,19 @@ type Artifact struct {
|
||||
SourceMessageID *int64
|
||||
CreatedBy uuid.UUID
|
||||
CreatedAt time.Time
|
||||
// Verdict 是该版本的评审结论(none/pass/fail)。新建产物默认 none。
|
||||
Verdict Verdict
|
||||
}
|
||||
|
||||
// PhasePointer 是某条 Requirement 在某阶段的"已批准/当前"产物指针。仅在首次
|
||||
// Approve(verdict=pass) 后才存在一行;ApprovedArtifactID 在被指向的产物删除时
|
||||
// 由 DB(ON DELETE SET NULL)置空。Done 等阶段网关据此判定前置产物是否就绪。
|
||||
type PhasePointer struct {
|
||||
RequirementID uuid.UUID
|
||||
Phase Phase
|
||||
ApprovedArtifactID *uuid.UUID
|
||||
ApprovedBy *uuid.UUID
|
||||
ApprovedAt *time.Time
|
||||
}
|
||||
|
||||
// Caller 表示发起请求的用户上下文。Service 层据此判定鉴权。
|
||||
@@ -151,6 +198,48 @@ type Caller struct {
|
||||
IsAdmin bool
|
||||
}
|
||||
|
||||
// Role 是 project_members.role 的角色枚举(与 0026 迁移的 CHECK 约束一致)。
|
||||
// 语义(在 owner+global-admin+internal-visibility 既有规则之上"叠加"授权,
|
||||
// 只增不减):
|
||||
//
|
||||
// admin 读 + 写 + 成员管理(owner 经迁移回填为本角色)
|
||||
// member 读 + 写(需求/issue 等)
|
||||
// viewer 只读
|
||||
//
|
||||
// RoleNone 是非成员的零值,仅在代码内部表示"无成员关系",不写入 DB。
|
||||
type Role string
|
||||
|
||||
// 角色枚举值。注意 DB CHECK 仅允许 viewer/member/admin;RoleNone 不入库。
|
||||
const (
|
||||
RoleNone Role = ""
|
||||
RoleViewer Role = "viewer"
|
||||
RoleMember Role = "member"
|
||||
RoleAdmin Role = "admin"
|
||||
)
|
||||
|
||||
// IsValid 报告 r 是否为可写入 DB 的合法角色(不含 RoleNone)。
|
||||
func (r Role) IsValid() bool {
|
||||
return r == RoleViewer || r == RoleMember || r == RoleAdmin
|
||||
}
|
||||
|
||||
// CanWrite 报告该角色是否授予写权限(member/admin)。
|
||||
func (r Role) CanWrite() bool { return r == RoleMember || r == RoleAdmin }
|
||||
|
||||
// CanRead 报告该角色是否授予读权限(任何已建立的成员关系都可读)。
|
||||
func (r Role) CanRead() bool { return r == RoleViewer || r == RoleMember || r == RoleAdmin }
|
||||
|
||||
// CanManageMembers 报告该角色是否可管理项目成员(仅 admin)。
|
||||
func (r Role) CanManageMembers() bool { return r == RoleAdmin }
|
||||
|
||||
// Member 是一条 project_members 关系:某用户在某 project 的角色。
|
||||
type Member struct {
|
||||
ProjectID uuid.UUID
|
||||
UserID uuid.UUID
|
||||
Role Role
|
||||
AddedBy *uuid.UUID
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// ProjectService 暴露 Project 聚合根的应用服务方法。包内有三个并列服务
|
||||
// (Project/Requirement/Issue),这里保留聚合名前缀以避免歧义。
|
||||
//
|
||||
@@ -163,6 +252,18 @@ type ProjectService interface {
|
||||
Update(ctx context.Context, c Caller, slug string, in UpdateProjectInput) (*Project, error)
|
||||
Archive(ctx context.Context, c Caller, slug string) error
|
||||
Unarchive(ctx context.Context, c Caller, slug string) error
|
||||
|
||||
// ===== 成员/角色 ACL(autonomy roadmap §11)=====
|
||||
|
||||
// ListMembers 返回 slug 项目的全部成员。要求 caller 对项目可读。
|
||||
ListMembers(ctx context.Context, c Caller, slug string) ([]*Member, error)
|
||||
// AddMember 新增或更新一名成员的角色。仅 project-admin 或 global-admin 可调用。
|
||||
AddMember(ctx context.Context, c Caller, slug string, in AddMemberInput) (*Member, error)
|
||||
// RemoveMember 移除一名成员。仅 project-admin 或 global-admin 可调用。
|
||||
RemoveMember(ctx context.Context, c Caller, slug string, userID uuid.UUID) error
|
||||
// MemberRole 返回 userID 在 projectID 的成员角色(非成员返回 RoleNone)。
|
||||
// 供 app 层 projectACL 桥接成员感知鉴权;不做可见性校验(调用方已校验)。
|
||||
MemberRole(ctx context.Context, projectID, userID uuid.UUID) (Role, error)
|
||||
}
|
||||
|
||||
// RequirementService 暴露 Requirement 聚合根的应用服务方法。
|
||||
@@ -185,6 +286,19 @@ type IssueService interface {
|
||||
Assign(ctx context.Context, c Caller, projectSlug string, number int, assignee *uuid.UUID) (*Issue, error)
|
||||
Close(ctx context.Context, c Caller, projectSlug string, number int) error
|
||||
Reopen(ctx context.Context, c Caller, projectSlug string, number int) error
|
||||
|
||||
// ===== 任务分解 / 依赖图(autonomy roadmap §10)=====
|
||||
|
||||
// CreateSubtask 在 parentNumber 指向的 issue 下创建一个子任务(设置 parent_id +
|
||||
// priority),继承 project。父 issue 须与目标 project 同属。
|
||||
CreateSubtask(ctx context.Context, c Caller, projectSlug string, parentNumber int, in CreateIssueInput) (*Issue, error)
|
||||
// AddDependency 新增一条依赖边:blocked 被 blocker 阻塞。拒绝自依赖、跨 project、
|
||||
// 重复、以及会形成环的边(沿 blocked-by 边做可达性检查)。
|
||||
AddDependency(ctx context.Context, c Caller, projectSlug string, in AddDependencyInput) (*Dependency, error)
|
||||
// RemoveDependency 删除一条依赖边(plan 修正用)。边不存在返回 NotFound。
|
||||
RemoveDependency(ctx context.Context, c Caller, projectSlug string, blockedNumber, blockerNumber int) error
|
||||
// ListDependencies 返回 number 指向 issue 的 (被谁阻塞 blockedBy, 阻塞了谁 blocks)。
|
||||
ListDependencies(ctx context.Context, c Caller, projectSlug string, number int) (blockedBy []*Issue, blocks []*Issue, err error)
|
||||
}
|
||||
|
||||
// ArtifactService 暴露 Requirement 阶段产物版本的应用服务方法。
|
||||
@@ -193,6 +307,46 @@ type ArtifactService interface {
|
||||
// List 的 phase 传零值("")表示返回全部阶段产物(done 阶段汇总视图用)。
|
||||
List(ctx context.Context, c Caller, projectSlug string, reqNumber int, phase Phase) ([]*Artifact, error)
|
||||
GetByVersion(ctx context.Context, c Caller, projectSlug string, reqNumber int, phase Phase, version int) (*Artifact, error)
|
||||
// Approve 给指定 (phase, version) 产物打 verdict(pass/fail)。verdict==pass 时
|
||||
// 同时把该阶段指针指向此产物(阶段网关据此放行后续 phase)。verdict==fail 仅
|
||||
// 落 verdict、不动指针。已关闭 requirement 拒绝批准。
|
||||
Approve(ctx context.Context, c Caller, projectSlug string, reqNumber int, phase Phase, version int, verdict Verdict) (*Artifact, error)
|
||||
}
|
||||
|
||||
// PhaseChangeEvent 是一次 requirement phase 流转的领域事件载荷。下游自动化
|
||||
// (如 webhook、触发 ACP run)通过 PhaseEventEmitter 订阅。
|
||||
type PhaseChangeEvent struct {
|
||||
ProjectID uuid.UUID
|
||||
ProjectSlug string
|
||||
RequirementID uuid.UUID
|
||||
RequirementNumber int
|
||||
From Phase
|
||||
To Phase
|
||||
ActorID uuid.UUID
|
||||
// OwnerID 是该需求的 owner——phase 变更通知的主要接收人(owner 关心进度,而非
|
||||
// 发起变更的 actor,后者可能是编排器/其它协作者)。
|
||||
OwnerID uuid.UUID
|
||||
}
|
||||
|
||||
// PhaseEventEmitter 把 phase 流转事件投递到通知/自动化总线。project 是领域模块,
|
||||
// 不直接 import infra/notify;由 app 层用 notify.Dispatcher 实现该窄接口。
|
||||
// 实现必须是 fire-and-forget 语义:投递失败不得阻塞 phase 流转。
|
||||
type PhaseEventEmitter interface {
|
||||
EmitPhaseChange(ctx context.Context, e PhaseChangeEvent)
|
||||
}
|
||||
|
||||
// WorkspaceStateLookup 是 Done 网关查询 workspace PR/合并状态的窄接口。由 app
|
||||
// 层用 changerequest/workspace 服务实现,避免 project 直接依赖那些模块。
|
||||
type WorkspaceStateLookup interface {
|
||||
// PullRequestMerged 报告该 requirement 是否已有合入主干的 PR(merged)。按
|
||||
// requirementID 过滤而非整个 workspace,避免同一 workspace 下其它需求的已合 PR 误判。
|
||||
PullRequestMerged(ctx context.Context, workspaceID, requirementID uuid.UUID) (bool, error)
|
||||
}
|
||||
|
||||
// GateRunner 在 ChangePhase 写库前运行目标 phase 的所有 entry 网关,全部通过才
|
||||
// 返回 nil;任一失败返回 CodePhaseGateFailed。实现见 phase_gate.go。
|
||||
type GateRunner interface {
|
||||
Check(ctx context.Context, r *Requirement, from, to Phase) error
|
||||
}
|
||||
|
||||
// ===== 输入 DTO =====
|
||||
@@ -216,6 +370,13 @@ type UpdateProjectInput struct {
|
||||
Visibility *Visibility
|
||||
}
|
||||
|
||||
// AddMemberInput 携带新增/更新一名 project 成员所需字段。Role 必须是合法角色
|
||||
// (viewer/member/admin)。
|
||||
type AddMemberInput struct {
|
||||
UserID uuid.UUID
|
||||
Role Role
|
||||
}
|
||||
|
||||
// CreateRequirementInput 创建一条需求。OwnerID 为 nil 时由 Service 默认为调用者。
|
||||
// WorkspaceID 为 nil 表示不关联任何 workspace;非 nil 时直接落库(FK 由 PG 校验)。
|
||||
type CreateRequirementInput struct {
|
||||
@@ -257,6 +418,18 @@ type CreateIssueInput struct {
|
||||
RequirementNumber *int
|
||||
AssigneeID *uuid.UUID
|
||||
WorkspaceID *uuid.UUID
|
||||
// ParentNumber 非 nil 表示创建为该编号 issue 的子任务(任务分解)。Service 校验
|
||||
// 父 issue 与目标 project 同属。
|
||||
ParentNumber *int
|
||||
// Priority 非 nil 时设置优先级(0..3);nil 时默认 0。
|
||||
Priority *int
|
||||
}
|
||||
|
||||
// AddDependencyInput 携带新增依赖边的两端 issue 编号。语义:BlockedNumber 被
|
||||
// BlockerNumber 阻塞。两端须在同一 project(由 Service 在同 project 上下文解析保证)。
|
||||
type AddDependencyInput struct {
|
||||
BlockedNumber int
|
||||
BlockerNumber int
|
||||
}
|
||||
|
||||
// CreateArtifactInput 创建一个阶段产物版本。Version 由 Service 自动计算
|
||||
|
||||
Reference in New Issue
Block a user