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 }