veza/veza-backend-api/internal/core/distribution/models.go
senke a1000ce7fb style(backend): gofmt -w on 85 files (whitespace only)
backend-ci.yml's `test -z "$(gofmt -l .)"` strict gate (added in
13c21ac11) failed on a backlog of unformatted files. None of the
85 files in this commit had been edited since the gate was added
because no push touched veza-backend-api/** in between, so the
gate never fired until today's CI fixes triggered it.

The diff is exclusively whitespace alignment in struct literals
and trailing-space comments. `go build ./...` and the full test
suite (with VEZA_SKIP_INTEGRATION=1 -short) pass identically.
2026-04-14 12:22:14 +02:00

181 lines
7 KiB
Go

package distribution
import (
"encoding/json"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// DistributionStatus represents the overall status of a distribution submission
type DistributionStatus string
const (
StatusSubmitted DistributionStatus = "submitted"
StatusProcessing DistributionStatus = "processing"
StatusLive DistributionStatus = "live"
StatusRejected DistributionStatus = "rejected"
StatusRemoved DistributionStatus = "removed"
StatusFailed DistributionStatus = "failed"
)
// Platform represents a streaming platform
type Platform string
const (
PlatformSpotify Platform = "spotify"
PlatformAppleMusic Platform = "apple_music"
PlatformDeezer Platform = "deezer"
)
// AllPlatforms returns the list of supported platforms
func AllPlatforms() []Platform {
return []Platform{PlatformSpotify, PlatformAppleMusic, PlatformDeezer}
}
// ImportStatus represents the status of a royalty import
type ImportStatus string
const (
ImportPending ImportStatus = "pending"
ImportCompleted ImportStatus = "completed"
ImportFailed ImportStatus = "failed"
ImportPartial ImportStatus = "partial"
)
// PlatformStatus represents the distribution status on a single platform
type PlatformStatus struct {
Status string `json:"status"`
URL string `json:"url,omitempty"`
LiveDate *string `json:"live_date,omitempty"`
Error *string `json:"error,omitempty"`
}
// DistributionMetadata holds the metadata snapshot for a distribution submission
type DistributionMetadata struct {
ArtistName string `json:"artist_name"`
AlbumName string `json:"album_name"`
Genre string `json:"genre"`
ReleaseDate string `json:"release_date"`
FeaturingArtists []string `json:"featuring_artists,omitempty"`
TrackTitle string `json:"track_title"`
UPC string `json:"upc,omitempty"`
ISRC string `json:"isrc,omitempty"`
}
// TrackDistribution represents a distribution submission for a track
type TrackDistribution struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
TrackID uuid.UUID `gorm:"type:uuid;not null" json:"track_id"`
CreatorID uuid.UUID `gorm:"type:uuid;not null" json:"creator_id"`
Distributor string `gorm:"not null;size:50;default:'distrokid'" json:"distributor"`
SubmissionID string `gorm:"not null;size:255;uniqueIndex" json:"submission_id"`
SubmissionUPC string `gorm:"size:50" json:"submission_upc,omitempty"`
SubmissionISRC string `gorm:"size:50" json:"submission_isrc,omitempty"`
Metadata json.RawMessage `gorm:"type:jsonb;not null;default:'{}'" json:"metadata"`
CoverFilePath string `gorm:"size:512" json:"cover_file_path,omitempty"`
OverallStatus DistributionStatus `gorm:"not null;size:50;default:'submitted'" json:"overall_status"`
PlatformStatuses json.RawMessage `gorm:"type:jsonb;not null;default:'{}'" json:"platform_statuses"`
SubmittedAt time.Time `gorm:"not null" json:"submitted_at"`
FirstLiveAt *time.Time `json:"first_live_at,omitempty"`
LastStatusCheckAt *time.Time `json:"last_status_check_at,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
func (TrackDistribution) TableName() string {
return "track_distributions"
}
func (d *TrackDistribution) BeforeCreate(tx *gorm.DB) error {
if d.ID == uuid.Nil {
d.ID = uuid.New()
}
return nil
}
// GetPlatformStatuses unmarshals and returns the platform statuses map
func (d *TrackDistribution) GetPlatformStatuses() (map[Platform]PlatformStatus, error) {
result := make(map[Platform]PlatformStatus)
if len(d.PlatformStatuses) == 0 {
return result, nil
}
err := json.Unmarshal(d.PlatformStatuses, &result)
return result, err
}
// SetPlatformStatuses marshals and stores the platform statuses map
func (d *TrackDistribution) SetPlatformStatuses(statuses map[Platform]PlatformStatus) error {
data, err := json.Marshal(statuses)
if err != nil {
return err
}
d.PlatformStatuses = data
return nil
}
// GetMetadata unmarshals the metadata field
func (d *TrackDistribution) GetMetadata() (*DistributionMetadata, error) {
var meta DistributionMetadata
if len(d.Metadata) == 0 {
return &meta, nil
}
err := json.Unmarshal(d.Metadata, &meta)
return &meta, err
}
// StatusHistoryEntry represents a status change event
type StatusHistoryEntry struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
DistributionID uuid.UUID `gorm:"type:uuid;not null" json:"distribution_id"`
Platform string `gorm:"not null;size:50" json:"platform"`
OldStatus string `gorm:"size:50" json:"old_status,omitempty"`
NewStatus string `gorm:"not null;size:50" json:"new_status"`
Note string `gorm:"type:text" json:"note,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
}
func (StatusHistoryEntry) TableName() string {
return "track_distribution_status_history"
}
func (e *StatusHistoryEntry) BeforeCreate(tx *gorm.DB) error {
if e.ID == uuid.Nil {
e.ID = uuid.New()
}
return nil
}
// ExternalStreamingRoyalty represents monthly royalty data from an external platform
type ExternalStreamingRoyalty struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
TrackID uuid.UUID `gorm:"type:uuid;not null" json:"track_id"`
CreatorID uuid.UUID `gorm:"type:uuid;not null" json:"creator_id"`
ReportingPeriodStart time.Time `gorm:"type:date;not null" json:"reporting_period_start"`
ReportingPeriodEnd time.Time `gorm:"type:date;not null" json:"reporting_period_end"`
Platform string `gorm:"not null;size:50" json:"platform"`
TotalStreams int64 `gorm:"not null;default:0" json:"total_streams"`
TotalRevenueCents int64 `gorm:"not null;default:0" json:"total_revenue_cents"`
Currency string `gorm:"size:3;default:'USD'" json:"currency"`
StreamsBreakdown json.RawMessage `gorm:"type:jsonb" json:"streams_breakdown,omitempty"`
Distributor string `gorm:"not null;size:50;default:'distrokid'" json:"distributor"`
DistributorReportID string `gorm:"size:255" json:"distributor_report_id,omitempty"`
ImportStatus ImportStatus `gorm:"not null;size:50;default:'pending'" json:"import_status"`
ImportError string `gorm:"type:text" json:"import_error,omitempty"`
ImportedAt *time.Time `json:"imported_at,omitempty"`
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
}
func (ExternalStreamingRoyalty) TableName() string {
return "external_streaming_royalties"
}
func (r *ExternalStreamingRoyalty) BeforeCreate(tx *gorm.DB) error {
if r.ID == uuid.Nil {
r.ID = uuid.New()
}
return nil
}