You've already forked agentic-coding-workflow
feat(project): domain types and sqlc queries for project/requirement/issue
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
// Package project 承载 Project / Requirement / Issue 三个 PM 聚合根的领域类型与
|
||||
// Service 接口契约。本文件只做类型与签名声明,业务实现在 *_service.go。
|
||||
//
|
||||
// 三个聚合根共享同一个 Go 包是有意为之:它们在 schema 上紧耦合(Issue 引用
|
||||
// Requirement,Requirement 属于 Project),且对外只暴露一组 chi route,拆包
|
||||
// 反而要互相 import。
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Phase 是 Requirement 的五阶段枚举。phase 不强制单向流动,可任意跳跃/回退。
|
||||
// 字符串常量保持与 DB CHECK 约束一致。
|
||||
type Phase string
|
||||
|
||||
const (
|
||||
PhasePlanning Phase = "planning"
|
||||
PhaseAuditing Phase = "auditing"
|
||||
PhaseImplementing Phase = "implementing"
|
||||
PhaseReviewing Phase = "reviewing"
|
||||
PhaseDone Phase = "done"
|
||||
)
|
||||
|
||||
// AllPhases 用于校验 phase 字符串合法性,顺序也对应前端看板/流转条的列序。
|
||||
var AllPhases = []Phase{PhasePlanning, PhaseAuditing, PhaseImplementing, PhaseReviewing, PhaseDone}
|
||||
|
||||
// IsValid 报告 p 是否在枚举集合内。
|
||||
func (p Phase) IsValid() bool {
|
||||
for _, x := range AllPhases {
|
||||
if p == x {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Status 是 Requirement / Issue 通用的开/关状态。
|
||||
type Status string
|
||||
|
||||
const (
|
||||
StatusOpen Status = "open"
|
||||
StatusClosed Status = "closed"
|
||||
)
|
||||
|
||||
// Visibility 控制 Project 的可见域:private 仅 owner+admin 可读,
|
||||
// internal 所有登录用户可读;写权限两者都仅限 owner+admin。
|
||||
type Visibility string
|
||||
|
||||
const (
|
||||
VisibilityPrivate Visibility = "private"
|
||||
VisibilityInternal Visibility = "internal"
|
||||
)
|
||||
|
||||
// IsValid 报告 v 是否在枚举集合内。
|
||||
func (v Visibility) IsValid() bool {
|
||||
return v == VisibilityPrivate || v == VisibilityInternal
|
||||
}
|
||||
|
||||
// Project 是顶层聚合根。ArchivedAt 为 nil 表示未归档。
|
||||
type Project struct {
|
||||
ID uuid.UUID
|
||||
Slug string
|
||||
Name string
|
||||
Description string
|
||||
Visibility Visibility
|
||||
OwnerID uuid.UUID
|
||||
ArchivedAt *time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Requirement 表示一个项目内的需求。Number 在 (project_id) 内自增。
|
||||
type Requirement struct {
|
||||
ID uuid.UUID
|
||||
ProjectID uuid.UUID
|
||||
Number int
|
||||
Title string
|
||||
Description string
|
||||
Phase Phase
|
||||
Status Status
|
||||
OwnerID uuid.UUID
|
||||
ClosedAt *time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Issue 可挂载到某个 Requirement,也可游离(RequirementID == nil)。
|
||||
// AssigneeID 为 nil 表示未指派。CreatedBy 永远存在(DELETE RESTRICT)。
|
||||
type Issue struct {
|
||||
ID uuid.UUID
|
||||
ProjectID uuid.UUID
|
||||
RequirementID *uuid.UUID
|
||||
Number int
|
||||
Title string
|
||||
Description string
|
||||
Status Status
|
||||
AssigneeID *uuid.UUID
|
||||
CreatedBy uuid.UUID
|
||||
ClosedAt *time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// Caller 表示发起请求的用户上下文。Service 层据此判定鉴权。
|
||||
type Caller struct {
|
||||
UserID uuid.UUID
|
||||
IsAdmin bool
|
||||
}
|
||||
|
||||
// ProjectService 暴露 Project 聚合根的应用服务方法。
|
||||
type ProjectService interface {
|
||||
Create(ctx context.Context, c Caller, in CreateProjectInput) (*Project, error)
|
||||
Get(ctx context.Context, c Caller, slug string) (*Project, error)
|
||||
List(ctx context.Context, c Caller, includeArchived bool) ([]*Project, error)
|
||||
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
|
||||
}
|
||||
|
||||
// RequirementService 暴露 Requirement 聚合根的应用服务方法。
|
||||
type RequirementService interface {
|
||||
Create(ctx context.Context, c Caller, projectSlug string, in CreateRequirementInput) (*Requirement, error)
|
||||
Get(ctx context.Context, c Caller, projectSlug string, number int) (*Requirement, error)
|
||||
List(ctx context.Context, c Caller, projectSlug string, filter RequirementFilter) ([]*Requirement, error)
|
||||
Update(ctx context.Context, c Caller, projectSlug string, number int, in UpdateRequirementInput) (*Requirement, error)
|
||||
ChangePhase(ctx context.Context, c Caller, projectSlug string, number int, to Phase) (*Requirement, error)
|
||||
Close(ctx context.Context, c Caller, projectSlug string, number int) error
|
||||
Reopen(ctx context.Context, c Caller, projectSlug string, number int) error
|
||||
}
|
||||
|
||||
// IssueService 暴露 Issue 聚合根的应用服务方法。
|
||||
type IssueService interface {
|
||||
Create(ctx context.Context, c Caller, projectSlug string, in CreateIssueInput) (*Issue, error)
|
||||
Get(ctx context.Context, c Caller, projectSlug string, number int) (*Issue, error)
|
||||
List(ctx context.Context, c Caller, projectSlug string, filter IssueFilter) ([]*Issue, error)
|
||||
Update(ctx context.Context, c Caller, projectSlug string, number int, in UpdateIssueInput) (*Issue, error)
|
||||
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
|
||||
}
|
||||
|
||||
// ===== 输入 DTO =====
|
||||
|
||||
type CreateProjectInput struct {
|
||||
Slug string
|
||||
Name string
|
||||
Description string
|
||||
Visibility Visibility
|
||||
}
|
||||
|
||||
type UpdateProjectInput struct {
|
||||
Name *string
|
||||
Description *string
|
||||
Visibility *Visibility
|
||||
}
|
||||
|
||||
type CreateRequirementInput struct {
|
||||
Title string
|
||||
Description string
|
||||
OwnerID *uuid.UUID
|
||||
}
|
||||
|
||||
type UpdateRequirementInput struct {
|
||||
Title *string
|
||||
Description *string
|
||||
OwnerID *uuid.UUID
|
||||
}
|
||||
|
||||
type RequirementFilter struct {
|
||||
Phase Phase
|
||||
Status Status
|
||||
}
|
||||
|
||||
type CreateIssueInput struct {
|
||||
Title string
|
||||
Description string
|
||||
RequirementNumber *int
|
||||
AssigneeID *uuid.UUID
|
||||
}
|
||||
|
||||
type UpdateIssueInput struct {
|
||||
Title *string
|
||||
Description *string
|
||||
RequirementNumber **int
|
||||
}
|
||||
|
||||
type IssueFilter struct {
|
||||
Status Status
|
||||
Requirement *int
|
||||
AssigneeID *uuid.UUID
|
||||
}
|
||||
Reference in New Issue
Block a user