veza/veza-backend-api/internal/services/job_service.go
senke 7846bbab28 fix(backend): remediation plan — tests, playback_analytics, job queue, gamification
Phase 1 - Backend tests:
- Add PlaybackAnalytics to AutoMigrate in setupTestTrackHandler
- Create migration 081_create_playback_analytics.sql for production
- PlaybackAnalyticsService: return ErrTrackNotFound for missing track
- RecordPlay handler: return 404 when track not found
- CreateShare: use RespondSuccess, fix services.ErrTrackNotFound/ErrForbidden
- GetTrackLikes, UnlikeTrack: use RespondSuccess for consistent response
- GetUserLikedTracks test: fix route /users/:id/likes and params
- GetSharedTrack_InvalidToken: set share service in test

Phase 4 - Job queue transcoding:
- Add EnqueueTranscodingJob to JobEnqueuer interface
- Add TypeTranscoding and processTranscodingJob (stub) in JobWorker
- MockJobEnqueuer: implement EnqueueTranscodingJob

Phase 5 - Gamification cleanup:
- Move api_manager.go to internal/api/archive/
- Add archive/README.md documenting archived modules
- Update TODOS_AUDIT.md and FEATURE_STATUS.md
2026-02-17 16:01:45 +01:00

102 lines
3.1 KiB
Go

package services
import (
"context"
"github.com/google/uuid"
"go.uber.org/zap"
)
// JobEnqueuer interface pour éviter le cycle d'importation
// BE-SVC-003: Implement background job queue
type JobEnqueuer interface {
EnqueueEmailJob(to, subject, body string)
EnqueueEmailJobWithTemplate(to, subject, templateName string, templateData map[string]interface{})
EnqueueThumbnailJob(inputPath, outputPath string, width, height int)
EnqueueAnalyticsJob(eventName string, userID *uuid.UUID, payload map[string]interface{})
EnqueueTranscodingJob(trackID uuid.UUID, inputPath, outputDir string)
}
// JobService gère les jobs en arrière-plan
// BE-SVC-003: Implement background job queue
type JobService struct {
logger *zap.Logger
jobEnqueuer JobEnqueuer
}
// Job types
const (
TypeEmailSend = "email:send"
TypeThumbnailGenerate = "thumbnail:generate"
TypeAnalyticsProcess = "analytics:process"
TypeWebhookDelivery = "webhook:delivery"
TypeTranscoding = "transcoding"
)
// EmailPayload représente les données pour l'envoi d'email
type EmailPayload struct {
To string
Subject string
Body string
}
// ThumbnailPayload représente les données pour la génération de miniatures
type ThumbnailPayload struct {
TrackID uint
FileID string
FilePath string
}
// NewJobService crée un nouveau service de jobs
func NewJobService(logger *zap.Logger) *JobService {
return &JobService{
logger: logger,
}
}
// SetJobEnqueuer définit le JobEnqueuer pour le service
// BE-SVC-003: Connect JobService to JobWorker
func (s *JobService) SetJobEnqueuer(jobEnqueuer JobEnqueuer) {
s.jobEnqueuer = jobEnqueuer
}
// EnqueueEmail enfile un job d'envoi d'email
// BE-SVC-003: Implement background job queue for email sending
func (s *JobService) EnqueueEmail(ctx context.Context, payload *EmailPayload) error {
if s.jobEnqueuer == nil {
s.logger.Warn("JobEnqueuer not set, email job not enqueued",
zap.String("to", payload.To),
zap.String("subject", payload.Subject))
return nil // Fail gracefully
}
s.logger.Info("Email job enqueued",
zap.String("to", payload.To),
zap.String("subject", payload.Subject))
// Enqueue via JobEnqueuer (JobWorker)
s.jobEnqueuer.EnqueueEmailJob(payload.To, payload.Subject, payload.Body)
return nil
}
// EnqueueThumbnail enfile un job de génération de miniature
// BE-SVC-003: Implement background job queue for thumbnail generation
func (s *JobService) EnqueueThumbnail(ctx context.Context, payload *ThumbnailPayload) error {
if s.jobEnqueuer == nil {
s.logger.Warn("JobEnqueuer not set, thumbnail job not enqueued",
zap.Uint("track_id", payload.TrackID))
return nil // Fail gracefully
}
s.logger.Info("Thumbnail job enqueued",
zap.Uint("track_id", payload.TrackID))
// Enqueue via JobEnqueuer (assuming default dimensions)
// Note: ThumbnailPayload uses uint for TrackID, but we need file paths
// This is a simplified version - actual implementation may need adjustment
if payload.FilePath != "" {
// Default thumbnail size
s.jobEnqueuer.EnqueueThumbnailJob(payload.FilePath, payload.FilePath+".thumb", 300, 300)
}
return nil
}