veza/veza-backend-api/internal/workers/analytics_job.go
okinrev b7955a680c P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.

Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.

Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).

Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.

Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 11:14:38 +01:00

90 lines
2.6 KiB
Go

package workers
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
)
// AnalyticsEventJob représente un job d'enregistrement d'événement analytics générique
type AnalyticsEventJob struct {
EventName string // Nom de l'événement (ex: "track_play", "user_login", "file_upload")
UserID *uuid.UUID // ID de l'utilisateur (nullable pour événements anonymes)
Payload map[string]interface{} // Données additionnelles de l'événement
}
// NewAnalyticsEventJob crée un nouveau job d'analytics générique
func NewAnalyticsEventJob(eventName string, userID *uuid.UUID, payload map[string]interface{}) *AnalyticsEventJob {
if payload == nil {
payload = make(map[string]interface{})
}
return &AnalyticsEventJob{
EventName: eventName,
UserID: userID,
Payload: payload,
}
}
// AnalyticsEvent représente un événement analytics en base de données
type AnalyticsEvent struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey"`
EventName string `gorm:"not null;index:idx_analytics_events_name"`
UserID *uuid.UUID `gorm:"type:uuid;index:idx_analytics_events_user_id"`
Payload string `gorm:"type:jsonb"` // Stocké en JSONB pour PostgreSQL
CreatedAt time.Time `gorm:"autoCreateTime;index:idx_analytics_events_created_at"`
}
// TableName définit le nom de la table pour GORM
func (AnalyticsEvent) TableName() string {
return "analytics_events"
}
// BeforeCreate hook GORM pour générer UUID si non défini
func (a *AnalyticsEvent) BeforeCreate(tx *gorm.DB) error {
if a.ID == uuid.Nil {
a.ID = uuid.New()
}
return nil
}
// Execute exécute le job d'analytics générique
func (j *AnalyticsEventJob) Execute(ctx context.Context, db *gorm.DB, logger *zap.Logger) error {
// Valider le nom de l'événement
if j.EventName == "" {
return fmt.Errorf("event name is required")
}
// Sérialiser le payload en JSON
payloadJSON, err := json.Marshal(j.Payload)
if err != nil {
return fmt.Errorf("failed to marshal payload: %w", err)
}
// Créer l'événement analytics
event := AnalyticsEvent{
EventName: j.EventName,
UserID: j.UserID,
Payload: string(payloadJSON),
CreatedAt: time.Now(),
}
// Enregistrer en base de données
if err := db.WithContext(ctx).Create(&event).Error; err != nil {
return fmt.Errorf("failed to save analytics event: %w", err)
}
logger.Info("Analytics event recorded",
zap.String("event_name", j.EventName),
zap.String("event_id", event.ID.String()),
zap.Any("user_id", j.UserID),
zap.Int("payload_size", len(payloadJSON)),
)
return nil
}