package activity import ( "context" "errors" "bookra/apps/backend/internal/db" "bookra/apps/backend/internal/domain" ) var ErrTenantMembership = errors.New("tenant membership not found") const defaultLimit = 50 const maxLimit = 100 type Service struct { repo db.Repository } func NewService(repo db.Repository) *Service { return &Service{repo: repo} } // List returns the tenant's recent activity, newest first. The feed is // tenant-scoped — every dashboard user sees the same audit trail. func (s *Service) List(ctx context.Context, principal domain.Principal, limit int) (domain.ActivityFeedResponse, error) { membership, err := s.repo.GetTenantMembershipBySubject(ctx, principal.Subject) if err != nil { return domain.ActivityFeedResponse{}, ErrTenantMembership } if limit <= 0 || limit > maxLimit { limit = defaultLimit } records, err := s.repo.ListActivityEvents(ctx, membership.Tenant.ID, limit) if err != nil { return domain.ActivityFeedResponse{}, err } events := make([]domain.ActivityEvent, 0, len(records)) for _, rec := range records { event := domain.ActivityEvent{ ID: rec.ID, ActorKind: rec.ActorKind, ActorName: rec.ActorName, Action: rec.Action, EntityType: rec.EntityType, Summary: rec.Summary, CreatedAt: rec.CreatedAt, } if rec.EntityID != nil { event.EntityID = *rec.EntityID } events = append(events, event) } return domain.ActivityFeedResponse{Events: events}, nil }