veza/veza-backend-api/internal/models/daily_track_stats.go
senke c50b7049b9 feat(v0.11.0): F381-F385 database migrations and models for creator analytics
Add daily_track_stats, geographic_play_stats, track_discovery_sources tables.
Add source and country_code columns to track_plays.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:21:01 +01:00

84 lines
3.1 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// DailyTrackStats represents daily aggregated playback statistics for a track
type DailyTrackStats struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
TrackID uuid.UUID `gorm:"type:uuid;not null;uniqueIndex:uq_daily_track_stats_track_date" json:"track_id"`
Date time.Time `gorm:"type:date;not null;uniqueIndex:uq_daily_track_stats_track_date" json:"date"`
TotalPlays int64 `gorm:"not null;default:0" json:"total_plays"`
UniqueListeners int64 `gorm:"not null;default:0" json:"unique_listeners"`
CompleteListens int64 `gorm:"not null;default:0" json:"complete_listens"`
TotalPlayTime int64 `gorm:"not null;default:0" json:"total_play_time"`
AvgCompletionRate float64 `gorm:"type:decimal(5,2);not null;default:0" json:"avg_completion_rate"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Track Track `gorm:"foreignKey:TrackID;constraint:OnDelete:CASCADE" json:"-"`
}
func (DailyTrackStats) TableName() string {
return "daily_track_stats"
}
func (m *DailyTrackStats) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// GeographicPlayStats represents aggregated geographic play data (anonymized)
type GeographicPlayStats struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
TrackID uuid.UUID `gorm:"type:uuid;not null" json:"track_id"`
CountryCode string `gorm:"size:2;not null" json:"country_code"`
Region string `gorm:"size:100;not null;default:''" json:"region"`
Date time.Time `gorm:"type:date;not null" json:"date"`
PlayCount int64 `gorm:"not null;default:0" json:"play_count"`
UniqueListeners int64 `gorm:"not null;default:0" json:"unique_listeners"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
Track Track `gorm:"foreignKey:TrackID;constraint:OnDelete:CASCADE" json:"-"`
}
func (GeographicPlayStats) TableName() string {
return "geographic_play_stats"
}
func (m *GeographicPlayStats) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}
// TrackDiscoverySource records how a user discovered a track
type TrackDiscoverySource struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
TrackID uuid.UUID `gorm:"type:uuid;not null" json:"track_id"`
UserID uuid.UUID `gorm:"type:uuid;not null" json:"user_id"`
Source string `gorm:"size:50;not null" json:"source"` // search, feed, share, profile, playlist, direct
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
Track Track `gorm:"foreignKey:TrackID;constraint:OnDelete:CASCADE" json:"-"`
User User `gorm:"foreignKey:UserID;constraint:OnDelete:CASCADE" json:"-"`
}
func (TrackDiscoverySource) TableName() string {
return "track_discovery_sources"
}
func (m *TrackDiscoverySource) BeforeCreate(tx *gorm.DB) error {
if m.ID == uuid.Nil {
m.ID = uuid.New()
}
return nil
}