diff --git a/internal/project/domain.go b/internal/project/domain.go index 4bd208a..8f5d48a 100644 --- a/internal/project/domain.go +++ b/internal/project/domain.go @@ -17,6 +17,7 @@ import ( // 字符串常量保持与 DB CHECK 约束一致。 type Phase string +// 五阶段枚举值,与 migrations/0002 的 CHECK 约束完全一致。 const ( PhasePlanning Phase = "planning" PhaseAuditing Phase = "auditing" @@ -41,6 +42,7 @@ func (p Phase) IsValid() bool { // Status 是 Requirement / Issue 通用的开/关状态。 type Status string +// 开/关状态枚举值,与 DB CHECK 约束一致。 const ( StatusOpen Status = "open" StatusClosed Status = "closed" @@ -50,6 +52,7 @@ const ( // internal 所有登录用户可读;写权限两者都仅限 owner+admin。 type Visibility string +// 可见性枚举值,与 DB CHECK 约束一致。 const ( VisibilityPrivate Visibility = "private" VisibilityInternal Visibility = "internal" @@ -111,7 +114,10 @@ type Caller struct { IsAdmin bool } -// ProjectService 暴露 Project 聚合根的应用服务方法。 +// ProjectService 暴露 Project 聚合根的应用服务方法。包内有三个并列服务 +// (Project/Requirement/Issue),这里保留聚合名前缀以避免歧义。 +// +//nolint:revive // 名字带聚合根前缀比 "Service" 更准确:包里有 3 个并列服务接口 type ProjectService interface { Create(ctx context.Context, c Caller, in CreateProjectInput) (*Project, error) Get(ctx context.Context, c Caller, slug string) (*Project, error) diff --git a/internal/project/project_service.go b/internal/project/project_service.go index b85487a..dce3065 100644 --- a/internal/project/project_service.go +++ b/internal/project/project_service.go @@ -45,7 +45,7 @@ func assertReadable(p *Project, c Caller) error { // assertWritable 是 write 类操作的鉴权门面:仅 owner+admin。已归档项目额外 // 拒绝;调用方应在执行写入前调用此函数。 func assertWritable(p *Project, c Caller) error { - if !(c.IsAdmin || p.OwnerID == c.UserID) { + if !c.IsAdmin && p.OwnerID != c.UserID { // stranger 对 private 看不见;对 internal 也不能写。统一 not_found 防探测。 if p.Visibility == VisibilityPrivate { return errs.New(errs.CodeNotFound, "project 不存在") @@ -148,7 +148,7 @@ func (s *projectService) Archive(ctx context.Context, c Caller, slug string) err return err } // 归档/取消归档仍要 owner+admin 校验,但已归档不再额外阻塞 archive。 - if !(c.IsAdmin || p.OwnerID == c.UserID) { + if !c.IsAdmin && p.OwnerID != c.UserID { if p.Visibility == VisibilityPrivate { return errs.New(errs.CodeNotFound, "project 不存在") } @@ -169,7 +169,7 @@ func (s *projectService) Unarchive(ctx context.Context, c Caller, slug string) e if err != nil { return err } - if !(c.IsAdmin || p.OwnerID == c.UserID) { + if !c.IsAdmin && p.OwnerID != c.UserID { if p.Visibility == VisibilityPrivate { return errs.New(errs.CodeNotFound, "project 不存在") } diff --git a/internal/project/project_service_test.go b/internal/project/project_service_test.go index af6984d..357cac4 100644 --- a/internal/project/project_service_test.go +++ b/internal/project/project_service_test.go @@ -120,13 +120,13 @@ func (r *fakeRepo) UnarchiveProject(_ context.Context, id uuid.UUID) error { // ===== Requirement ===== func (r *fakeRepo) nextRequirementNumber(projectID uuid.UUID) int { - max := 0 + maxNum := 0 for _, x := range r.requirements { - if x.ProjectID == projectID && x.Number > max { - max = x.Number + if x.ProjectID == projectID && x.Number > maxNum { + maxNum = x.Number } } - return max + 1 + return maxNum + 1 } func (r *fakeRepo) CreateRequirement(_ context.Context, in *Requirement) (*Requirement, error) { @@ -235,13 +235,13 @@ func (r *fakeRepo) ReopenRequirement(_ context.Context, id uuid.UUID) error { // ===== Issue ===== func (r *fakeRepo) nextIssueNumber(projectID uuid.UUID) int { - max := 0 + maxNum := 0 for _, x := range r.issues { - if x.ProjectID == projectID && x.Number > max { - max = x.Number + if x.ProjectID == projectID && x.Number > maxNum { + maxNum = x.Number } } - return max + 1 + return maxNum + 1 } func (r *fakeRepo) CreateIssue(_ context.Context, in *Issue) (*Issue, error) { @@ -280,15 +280,12 @@ func (r *fakeRepo) ListIssues(_ context.Context, projectID uuid.UUID, filter Iss continue } if filter.Requirement != nil { - switch { - case *filter.Requirement == 0: + if *filter.Requirement == 0 { if x.RequirementID != nil { continue } - default: - if x.RequirementID == nil || *x.RequirementID != *requirementID { - continue - } + } else if x.RequirementID == nil || *x.RequirementID != *requirementID { + continue } } if filter.AssigneeID != nil { diff --git a/internal/project/repository.go b/internal/project/repository.go index bed7a16..9f21a98 100644 --- a/internal/project/repository.go +++ b/internal/project/repository.go @@ -232,7 +232,7 @@ func (r *pgRepo) CreateRequirement(ctx context.Context, in *Requirement) (*Requi func (r *pgRepo) GetRequirementByNumber(ctx context.Context, projectID uuid.UUID, number int) (*Requirement, error) { row, err := r.q.GetRequirementByNumber(ctx, projectsqlc.GetRequirementByNumberParams{ ProjectID: toPgUUID(projectID), - Number: int32(number), + Number: int32(number), //nolint:gosec // number 来自 service 层 number int 字段,原值即来自 DB int32,溢出不可达 }) if err != nil { if errors.Is(err, pgx.ErrNoRows) { @@ -364,7 +364,7 @@ func (r *pgRepo) CreateIssue(ctx context.Context, in *Issue) (*Issue, error) { func (r *pgRepo) GetIssueByNumber(ctx context.Context, projectID uuid.UUID, number int) (*Issue, error) { row, err := r.q.GetIssueByNumber(ctx, projectsqlc.GetIssueByNumberParams{ ProjectID: toPgUUID(projectID), - Number: int32(number), + Number: int32(number), //nolint:gosec // 同上:number 原始来自 DB int32 }) if err != nil { if errors.Is(err, pgx.ErrNoRows) {