refactor: introduce Wire dependency injection and interface-based architecture

- Add Google Wire for compile-time dependency injection
- Replace concrete service types with interfaces across handlers
- Remove global state (DB, cache) in favor of constructor injection
- Split monolithic files into focused modules:
  - config: separate files for each config domain
  - dto: converters split by domain (user, post, message, group)
  - cache: separate metrics.go and redis_cache.go
- Introduce unified apperrors package with string-based error codes
- Add transaction support with context-aware repository methods
- Upgrade golang.org/x/crypto from 0.17.0 to 0.26.0
This commit is contained in:
2026-03-13 09:38:18 +08:00
parent 1216423350
commit cf36b1350d
49 changed files with 2571 additions and 2218 deletions

View File

@@ -8,6 +8,7 @@ import (
"time"
"carrot_bbs/internal/cache"
apperrors "carrot_bbs/internal/errors"
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/sse"
"carrot_bbs/internal/pkg/utils"
@@ -23,25 +24,26 @@ const (
GroupCacheJitter = 0.1
)
// 群组服务错误定义
// 群组服务错误定义 - 使用统一的 AppError
var (
ErrGroupNotFound = &ServiceError{Code: 404, Message: "群组不存在"}
ErrNotGroupMember = &ServiceError{Code: 403, Message: "不是群成员"}
ErrNotGroupAdmin = &ServiceError{Code: 403, Message: "不是群管理员"}
ErrNotGroupOwner = &ServiceError{Code: 403, Message: "不是群主"}
ErrGroupFull = &ServiceError{Code: 400, Message: "群已满"}
ErrAlreadyMember = &ServiceError{Code: 400, Message: "已经是群成员"}
ErrCannotRemoveOwner = &ServiceError{Code: 400, Message: "不能移除群主"}
ErrCannotMuteOwner = &ServiceError{Code: 400, Message: "不能禁言群主"}
ErrMuted = &ServiceError{Code: 403, Message: "你已被禁言"}
ErrMuteAllEnabled = &ServiceError{Code: 403, Message: "全员禁言中"}
ErrCannotJoin = &ServiceError{Code: 400, Message: "该群不允许加入"}
ErrJoinRequestPending = &ServiceError{Code: 400, Message: "加群申请已提交"}
ErrGroupRequestNotFound = &ServiceError{Code: 404, Message: "加群请求不存在"}
ErrGroupRequestHandled = &ServiceError{Code: 400, Message: "该加群请求已处理"}
ErrNotRequestTarget = &ServiceError{Code: 400, Message: "不是邀请目标用户"}
ErrNoEligibleInvitee = &ServiceError{Code: 400, Message: "没有可邀请的用户"}
ErrNotMutualFollow = &ServiceError{Code: 400, Message: "仅支持邀请互相关注用户"}
ErrGroupNotFound = apperrors.ErrGroupNotFound
ErrNotGroupMember = apperrors.ErrNotGroupMember
ErrNotGroupAdmin = apperrors.ErrNotGroupAdmin
ErrNotGroupOwner = apperrors.ErrNotGroupOwner
ErrGroupFull = apperrors.ErrGroupFull
ErrAlreadyMember = apperrors.ErrAlreadyGroupMember
ErrCannotRemoveOwner = apperrors.ErrCannotRemoveOwner
ErrCannotMuteOwner = apperrors.ErrCannotMuteOwner
ErrMuted = apperrors.ErrMuted
ErrMuteAllEnabled = apperrors.ErrMuteAllEnabled
ErrCannotJoin = apperrors.ErrCannotJoin
ErrJoinRequestPending = apperrors.ErrJoinRequestPending
ErrGroupRequestNotFound = apperrors.ErrGroupRequestNotFound
ErrGroupRequestHandled = apperrors.ErrGroupRequestHandled
ErrNotRequestTarget = apperrors.ErrNotRequestTarget
ErrNoEligibleInvitee = apperrors.ErrNoEligibleInvitee
ErrNotMutualFollow = apperrors.ErrNotMutualFollow
ErrInviteNotAccepted = apperrors.ErrInviteNotAccepted
)
// GroupService 群组服务接口
@@ -104,7 +106,7 @@ type groupService struct {
}
// NewGroupService 创建群组服务
func NewGroupService(db *gorm.DB, groupRepo repository.GroupRepository, userRepo *repository.UserRepository, messageRepo *repository.MessageRepository, sseHub *sse.Hub) GroupService {
func NewGroupService(db *gorm.DB, groupRepo repository.GroupRepository, userRepo *repository.UserRepository, messageRepo *repository.MessageRepository, sseHub *sse.Hub, cacheBackend cache.Cache) GroupService {
return &groupService{
db: db,
groupRepo: groupRepo,
@@ -113,7 +115,7 @@ func NewGroupService(db *gorm.DB, groupRepo repository.GroupRepository, userRepo
requestRepo: repository.NewGroupJoinRequestRepository(db),
notifyRepo: repository.NewSystemNotificationRepository(db),
sseHub: sseHub,
cache: cache.GetCache(),
cache: cacheBackend,
}
}
@@ -937,7 +939,7 @@ func (s *groupService) SetGroupAddRequest(userID string, flag string, approve bo
if req.RequestType == model.GroupJoinRequestTypeInvite {
if req.ReviewerID == "" {
// 被邀请人还未同意,管理员不能提前审批
return &ServiceError{Code: 400, Message: "被邀请人尚未同意邀请,无法审批"}
return ErrInviteNotAccepted
}
if req.ReviewerID != req.TargetUserID {
// ReviewerID 不是被邀请人,说明已经被其他人处理过