refactor(server): decouple services and improve architecture
All checks were successful
Build Backend / build (push) Successful in 4m55s
Build Backend / build-docker (push) Successful in 10m34s

- Introduce interfaces for all major services (JWT, PostAI, Comment, Message, Notification, QRCodeLogin, Upload, Vote, etc.) to support dependency inversion.
- Move query parameters from `internal/dto` to a new `internal/query` package to separate request payloads from data transfer objects.
- Refactor `internal/router` to use embedded `RouterDeps` for cleaner dependency management.
- Decouple handlers from repositories by injecting services instead of direct repository access, ensuring proper layering.
- Improve database initialization by moving it from `internal/model` to `internal/database`.
- Optimize message decryption by implementing a more efficient `BatchDecrypt` method in `MessageEncryptor` using a worker pool.
- Enhance error handling and security by implementing fail-fast checks for encryption key length during startup.
- Clean up unused code, including the `avatar` package and several unused DTOs.
This commit is contained in:
2026-06-15 03:41:59 +08:00
parent 9951043034
commit d9aa4b46c3
78 changed files with 2156 additions and 1640 deletions

View File

@@ -18,22 +18,34 @@ const (
NotificationCacheJitter = 0.1
)
// NotificationService 通知服务
type NotificationService struct {
// NotificationService 通知服务接口
type NotificationService interface {
Create(ctx context.Context, userID string, notificationType model.NotificationType, title, content string) (*model.Notification, error)
GetByUserID(ctx context.Context, userID string, page, pageSize int, unreadOnly bool) ([]*model.Notification, int64, error)
MarkAsReadWithUserID(ctx context.Context, id, userID string) error
MarkAllAsRead(ctx context.Context, userID string) error
GetUnreadCount(ctx context.Context, userID string) (int64, error)
DeleteNotification(ctx context.Context, id, userID string) error
ClearAllNotifications(ctx context.Context, userID string) error
GetNotificationsByCursor(ctx context.Context, userID string, unreadOnly bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Notification], error)
}
// notificationService 通知服务实现
type notificationService struct {
notificationRepo repository.NotificationRepository
cache cache.Cache
}
// NewNotificationService 创建通知服务
func NewNotificationService(notificationRepo repository.NotificationRepository, cacheBackend cache.Cache) *NotificationService {
return &NotificationService{
func NewNotificationService(notificationRepo repository.NotificationRepository, cacheBackend cache.Cache) NotificationService {
return &notificationService{
notificationRepo: notificationRepo,
cache: cacheBackend,
}
}
// Create 创建通知
func (s *NotificationService) Create(ctx context.Context, userID string, notificationType model.NotificationType, title, content string) (*model.Notification, error) {
func (s *notificationService) Create(ctx context.Context, userID string, notificationType model.NotificationType, title, content string) (*model.Notification, error) {
notification := &model.Notification{
UserID: userID,
Type: notificationType,
@@ -54,12 +66,12 @@ func (s *NotificationService) Create(ctx context.Context, userID string, notific
}
// GetByUserID 获取用户通知
func (s *NotificationService) GetByUserID(ctx context.Context, userID string, page, pageSize int, unreadOnly bool) ([]*model.Notification, int64, error) {
func (s *notificationService) GetByUserID(ctx context.Context, userID string, page, pageSize int, unreadOnly bool) ([]*model.Notification, int64, error) {
return s.notificationRepo.GetByUserID(userID, page, pageSize, unreadOnly)
}
// MarkAsReadWithUserID 标记为已读带用户ID验证所有权
func (s *NotificationService) MarkAsReadWithUserID(ctx context.Context, id, userID string) error {
func (s *notificationService) MarkAsReadWithUserID(ctx context.Context, id, userID string) error {
notification, err := s.notificationRepo.GetByID(id)
if err != nil {
return err
@@ -79,7 +91,7 @@ func (s *NotificationService) MarkAsReadWithUserID(ctx context.Context, id, user
}
// MarkAllAsRead 标记所有为已读
func (s *NotificationService) MarkAllAsRead(ctx context.Context, userID string) error {
func (s *notificationService) MarkAllAsRead(ctx context.Context, userID string) error {
err := s.notificationRepo.MarkAllAsRead(userID)
if err != nil {
return err
@@ -92,7 +104,7 @@ func (s *NotificationService) MarkAllAsRead(ctx context.Context, userID string)
}
// GetUnreadCount 获取未读数量(带缓存)
func (s *NotificationService) GetUnreadCount(ctx context.Context, userID string) (int64, error) {
func (s *notificationService) GetUnreadCount(ctx context.Context, userID string) (int64, error) {
cacheSettings := cache.GetSettings()
unreadTTL := cacheSettings.UnreadCountTTL
if unreadTTL <= 0 {
@@ -122,7 +134,7 @@ func (s *NotificationService) GetUnreadCount(ctx context.Context, userID string)
}
// DeleteNotification 删除通知(带用户验证)
func (s *NotificationService) DeleteNotification(ctx context.Context, id, userID string) error {
func (s *notificationService) DeleteNotification(ctx context.Context, id, userID string) error {
// 先检查通知是否属于该用户
notification, err := s.notificationRepo.GetByID(id)
if err != nil {
@@ -144,7 +156,7 @@ func (s *NotificationService) DeleteNotification(ctx context.Context, id, userID
}
// ClearAllNotifications 清空所有通知
func (s *NotificationService) ClearAllNotifications(ctx context.Context, userID string) error {
func (s *notificationService) ClearAllNotifications(ctx context.Context, userID string) error {
err := s.notificationRepo.DeleteAllByUserID(userID)
if err != nil {
return err
@@ -157,7 +169,7 @@ func (s *NotificationService) ClearAllNotifications(ctx context.Context, userID
}
// GetNotificationsByCursor 游标分页获取用户通知
func (s *NotificationService) GetNotificationsByCursor(ctx context.Context, userID string, unreadOnly bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Notification], error) {
func (s *notificationService) GetNotificationsByCursor(ctx context.Context, userID string, unreadOnly bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Notification], error) {
return s.notificationRepo.GetNotificationsByCursor(ctx, userID, unreadOnly, req)
}