package logic import ( "context" friendentity "spark-server/internal/module/friend/entity" "spark-server/internal/module/moment/entity" userentity "spark-server/internal/module/user/entity" "spark-server/internal/pkg/media" "go.uber.org/zap" ) // Repository persists Moments. Model implements it. type Repository interface { CreatePost(ctx context.Context, post *entity.Post, audience []int64) error GetPost(ctx context.Context, id int64) (*entity.Post, error) ListByAuthors(ctx context.Context, authorIDs []int64, cursor int64, limit int) ([]*entity.Post, error) ListByAuthor(ctx context.Context, authorID, cursor int64, limit int) ([]*entity.Post, error) SoftDeletePost(ctx context.Context, userID, postID int64) (*entity.Post, error) ListAudience(ctx context.Context, postIDs []int64) (map[int64][]int64, error) ListLikes(ctx context.Context, postIDs []int64) (map[int64][]*entity.Like, error) AddLike(ctx context.Context, like *entity.Like) (created bool, err error) RemoveLike(ctx context.Context, postID, userID int64) error ListComments(ctx context.Context, postIDs []int64) (map[int64][]*entity.Comment, error) GetComment(ctx context.Context, id int64) (*entity.Comment, error) AddComment(ctx context.Context, c *entity.Comment) error SoftDeleteComment(ctx context.Context, id int64) error CreateNotices(ctx context.Context, rows []*entity.Notice) error ListNotices(ctx context.Context, userID, cursor int64, limit int) ([]*entity.Notice, error) MarkNoticesRead(ctx context.Context, userID, cursor int64) error GetSettings(ctx context.Context, userID int64) (*entity.Settings, error) ListSettings(ctx context.Context, userIDs []int64) (map[int64]*entity.Settings, error) UpsertSettings(ctx context.Context, s *entity.Settings) error AdvanceRead(ctx context.Context, userID, postID int64) error ListHides(ctx context.Context, userID int64) ([]*entity.Hide, error) HideHimIDs(ctx context.Context, userID int64) ([]int64, error) HideMeFromIDs(ctx context.Context, viewerID int64) ([]int64, error) UpsertHide(ctx context.Context, h *entity.Hide) error DeleteHide(ctx context.Context, userID, peerID int64) error ListAllByAuthor(ctx context.Context, authorID int64) ([]*entity.Post, error) PurgeUser(ctx context.Context, userID int64) error } // Friends is the friend graph used for visibility. Friend module implements it. type Friends interface { AreFriends(ctx context.Context, a, b int64) (bool, error) ListFriendIDs(ctx context.Context, userID int64) ([]int64, error) ListBlockedPeerIDs(ctx context.Context, userID int64) ([]int64, error) Relation(ctx context.Context, userID, peerID int64) (*friendentity.Relation, error) BlockedEither(ctx context.Context, a, b int64) (bool, error) } // Users loads profile cards. type Users interface { Get(ctx context.Context, id int64) (*userentity.User, error) } // Objects deletes Moments media. Nil skips GC. type Objects interface { Delete(ctx context.Context, key string) error } // IDGen issues Snowflake ids for posts, comments, and notices. type IDGen interface { NextID() (int64, error) } // Service is the Moments use-case layer (HTTP and TCP share it). type Service struct { repo Repository friends Friends users Users objects Objects ids IDGen burst *burst media media.Policy log *zap.Logger } func NewService(repo Repository, friends Friends, users Users, objects Objects, ids IDGen) *Service { return &Service{repo: repo, friends: friends, users: users, objects: objects, ids: ids, burst: newBurst(), log: zap.NewNop()} } // ConfigureMedia sets user-path media detection (client compresses; server checks declared meta). func (s *Service) ConfigureMedia(p media.Policy, log *zap.Logger) { if s == nil { return } s.media = p if log != nil { s.log = log } } func (s *Service) ready() bool { return s != nil && s.repo != nil && s.friends != nil && s.users != nil && s.ids != nil }