package domain import ( "database/sql/driver" "encoding/json" "errors" "fmt" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" "time" ) // JSONB is a custom type for JSONB columns. type JSONB map[string]interface{} // Value marshals JSONB for storing in the DB. func (j JSONB) Value() (driver.Value, error) { if j == nil { return "{}", nil } return json.Marshal(j) } // Scan unmarshals a JSONB value. func (j *JSONB) Scan(value interface{}) error { if value == nil { *j = JSONB{} return nil } switch v := value.(type) { case []byte: if len(v) == 0 { *j = JSONB{} return nil } return json.Unmarshal(v, j) case string: if v == "" { *j = JSONB{} return nil } return json.Unmarshal([]byte(v), j) default: return fmt.Errorf("failed to unmarshal JSONB value of type %T: %v", value, value) } } // BaseModel contains common fields for all models type BaseModel struct { ID uint `gorm:"primaryKey"` CreatedAt time.Time UpdatedAt time.Time } // TranslatableModel extends BaseModel with language support type TranslatableModel struct { BaseModel Language string `gorm:"size:50;default:'multi'"` Slug string `gorm:"size:255;index"` } // Translation status enum type TranslationStatus string const ( TranslationStatusDraft TranslationStatus = "draft" TranslationStatusPublished TranslationStatus = "published" TranslationStatusReviewing TranslationStatus = "reviewing" TranslationStatusRejected TranslationStatus = "rejected" ) // UserRole enum type UserRole string const ( UserRoleReader UserRole = "reader" UserRoleContributor UserRole = "contributor" UserRoleReviewer UserRole = "reviewer" UserRoleEditor UserRole = "editor" UserRoleAdmin UserRole = "admin" ) // User represents a user of the platform type User struct { BaseModel Username string `gorm:"size:50;not null;unique"` Email string `gorm:"size:100;not null;unique"` Password string `gorm:"size:255;not null"` FirstName string `gorm:"size:50"` LastName string `gorm:"size:50"` DisplayName string `gorm:"size:100"` Bio string `gorm:"type:text"` AvatarURL string `gorm:"size:255"` Role UserRole `gorm:"size:20;default:'reader'"` LastLoginAt *time.Time Verified bool `gorm:"default:false"` Active bool `gorm:"default:true"` Translations []*Translation `gorm:"foreignKey:TranslatorID"` Comments []*Comment `gorm:"foreignKey:UserID"` Likes []*Like `gorm:"foreignKey:UserID"` Bookmarks []*Bookmark `gorm:"foreignKey:UserID"` Collections []*Collection `gorm:"foreignKey:UserID"` Contributions []*Contribution `gorm:"foreignKey:UserID"` CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` CityID *uint City *City `gorm:"foreignKey:CityID"` AddressID *uint Address *Address `gorm:"foreignKey:AddressID"` } // UserProfile represents additional profile information for a user type UserProfile struct { BaseModel UserID uint `gorm:"uniqueIndex"` User *User `gorm:"foreignKey:UserID"` PhoneNumber string `gorm:"size:20"` Website string `gorm:"size:255"` Twitter string `gorm:"size:50"` Facebook string `gorm:"size:50"` LinkedIn string `gorm:"size:50"` Github string `gorm:"size:50"` Preferences JSONB `gorm:"type:jsonb;default:'{}'"` Settings JSONB `gorm:"type:jsonb;default:'{}'"` } // UserSession represents a user session type UserSession struct { BaseModel UserID uint `gorm:"index"` User *User `gorm:"foreignKey:UserID"` Token string `gorm:"size:255;not null;uniqueIndex"` IP string `gorm:"size:50"` UserAgent string `gorm:"size:255"` ExpiresAt time.Time `gorm:"not null"` } // PasswordReset represents a password reset request type PasswordReset struct { BaseModel UserID uint `gorm:"index"` User *User `gorm:"foreignKey:UserID"` Token string `gorm:"size:255;not null;uniqueIndex"` ExpiresAt time.Time `gorm:"not null"` Used bool `gorm:"default:false"` } // EmailVerification represents an email verification request type EmailVerification struct { BaseModel UserID uint `gorm:"index"` User *User `gorm:"foreignKey:UserID"` Token string `gorm:"size:255;not null;uniqueIndex"` ExpiresAt time.Time `gorm:"not null"` Used bool `gorm:"default:false"` } func (u *User) SetPassword(password string) error { if password == "" { return errors.New("password cannot be empty") } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return errors.New("failed to hash password: " + err.Error()) } u.Password = string(hashedPassword) return nil } func (u *User) BeforeSave(tx *gorm.DB) error { if u.Password == "" { return nil } if len(u.Password) >= 60 && u.Password[:4] == "$2a$" { return nil } return u.SetPassword(u.Password) } func (u *User) CheckPassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) return err == nil } type AuthorStatus string const ( AuthorStatusActive AuthorStatus = "active" AuthorStatusInactive AuthorStatus = "inactive" AuthorStatusDeceased AuthorStatus = "deceased" ) type Author struct { TranslatableModel Name string `gorm:"size:255;not null"` Status AuthorStatus `gorm:"size:50;default:'active'"` BirthDate *time.Time DeathDate *time.Time OpenLibraryID string `gorm:"size:50;index"` Books []*Book `gorm:"many2many:book_authors"` CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` CityID *uint City *City `gorm:"foreignKey:CityID"` PlaceID *uint Place *Place `gorm:"foreignKey:PlaceID"` AddressID *uint Address *Address `gorm:"foreignKey:AddressID"` Translations []*Translation `gorm:"polymorphic:Translatable"` Copyrights []*Copyright `gorm:"many2many:author_copyrights;constraint:OnDelete:CASCADE"` Monetizations []*Monetization `gorm:"many2many:author_monetizations;constraint:OnDelete:CASCADE"` } type BookStatus string const ( BookStatusDraft BookStatus = "draft" BookStatusPublished BookStatus = "published" BookStatusOutOfPrint BookStatus = "out_of_print" BookStatusArchived BookStatus = "archived" ) type BookFormat string const ( BookFormatHardcover BookFormat = "hardcover" BookFormatPaperback BookFormat = "paperback" BookFormatEbook BookFormat = "ebook" BookFormatAudiobook BookFormat = "audiobook" BookFormatDigital BookFormat = "digital" ) type Book struct { TranslatableModel Title string `gorm:"size:255;not null"` Description string `gorm:"type:text"` ISBN string `gorm:"size:20;index"` Format BookFormat `gorm:"size:50;default:'paperback'"` Status BookStatus `gorm:"size:50;default:'draft'"` PublishedAt *time.Time Authors []*Author `gorm:"many2many:book_authors"` PublisherID *uint Publisher *Publisher `gorm:"foreignKey:PublisherID"` Translations []*Translation `gorm:"polymorphic:Translatable"` Copyrights []*Copyright `gorm:"many2many:book_copyrights;constraint:OnDelete:CASCADE"` Monetizations []*Monetization `gorm:"many2many:book_monetizations;constraint:OnDelete:CASCADE"` } type PublisherStatus string const ( PublisherStatusActive PublisherStatus = "active" PublisherStatusInactive PublisherStatus = "inactive" PublisherStatusDefunct PublisherStatus = "defunct" ) type Publisher struct { TranslatableModel Name string `gorm:"size:255;not null"` Description string `gorm:"type:text"` Status PublisherStatus `gorm:"size:50;default:'active'"` Books []*Book `gorm:"foreignKey:PublisherID"` CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` Translations []*Translation `gorm:"polymorphic:Translatable"` Copyrights []*Copyright `gorm:"many2many:publisher_copyrights;constraint:OnDelete:CASCADE"` Monetizations []*Monetization `gorm:"many2many:publisher_monetizations;constraint:OnDelete:CASCADE"` } type SourceStatus string const ( SourceStatusActive SourceStatus = "active" SourceStatusInactive SourceStatus = "inactive" SourceStatusArchived SourceStatus = "archived" ) type Source struct { TranslatableModel Name string `gorm:"size:255;not null"` Description string `gorm:"type:text"` URL string `gorm:"size:512"` Status SourceStatus `gorm:"size:50;default:'active'"` Translations []*Translation `gorm:"polymorphic:Translatable"` Copyrights []*Copyright `gorm:"many2many:source_copyrights;constraint:OnDelete:CASCADE"` Monetizations []*Monetization `gorm:"many2many:source_monetizations;constraint:OnDelete:CASCADE"` } type EditionStatus string const ( EditionStatusDraft EditionStatus = "draft" EditionStatusPublished EditionStatus = "published" EditionStatusOutOfPrint EditionStatus = "out_of_print" EditionStatusArchived EditionStatus = "archived" ) type Edition struct { BaseModel Title string `gorm:"size:255;not null"` Description string `gorm:"type:text"` ISBN string `gorm:"size:20;index"` Version string `gorm:"size:50"` Format BookFormat `gorm:"size:50;default:'paperback'"` Status EditionStatus `gorm:"size:50;default:'draft'"` PublishedAt *time.Time BookID uint Book *Book `gorm:"foreignKey:BookID"` } func (a *Author) BeforeSave(tx *gorm.DB) error { if a.Name == "" { a.Name = "Unknown Author" } return nil } func (b *Book) BeforeSave(tx *gorm.DB) error { if b.Title == "" { b.Title = "Untitled Book" } return nil } func (p *Publisher) BeforeSave(tx *gorm.DB) error { if p.Name == "" { p.Name = "Unknown Publisher" } return nil } type Comment struct { BaseModel Text string `gorm:"type:text;not null"` UserID uint User *User `gorm:"foreignKey:UserID"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` LineNumber *int `gorm:"index"` TextBlockID *uint TextBlock *TextBlock `gorm:"foreignKey:TextBlockID"` ParentID *uint Parent *Comment `gorm:"foreignKey:ParentID"` Children []*Comment `gorm:"foreignKey:ParentID"` Likes []*Like `gorm:"foreignKey:CommentID"` } type Like struct { BaseModel UserID uint `gorm:"index;uniqueIndex:uniq_like_user_target"` User *User `gorm:"foreignKey:UserID"` WorkID *uint `gorm:"index;uniqueIndex:uniq_like_user_target"` TranslationID *uint `gorm:"index;uniqueIndex:uniq_like_user_target"` Translation *Translation `gorm:"foreignKey:TranslationID"` CommentID *uint `gorm:"index;uniqueIndex:uniq_like_user_target"` Comment *Comment `gorm:"foreignKey:CommentID"` } type Bookmark struct { BaseModel Name string `gorm:"size:100"` UserID uint `gorm:"index;uniqueIndex:uniq_bookmark_user_work"` User *User `gorm:"foreignKey:UserID"` WorkID uint `gorm:"index;uniqueIndex:uniq_bookmark_user_work"` Notes string `gorm:"type:text"` LastReadAt *time.Time Progress int `gorm:"default:0"` } type Collection struct { TranslatableModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` UserID uint User *User `gorm:"foreignKey:UserID"` IsPublic bool `gorm:"default:true"` CoverImageURL string `gorm:"size:255"` } type CollectionWork struct { CollectionID uint `gorm:"primaryKey"` WorkID uint `gorm:"primaryKey"` } type Contribution struct { BaseModel Name string `gorm:"size:100;not null"` Status string `gorm:"size:20;default:'draft'"` UserID uint User *User `gorm:"foreignKey:UserID"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` ReviewerID *uint Reviewer *User `gorm:"foreignKey:ReviewerID"` ReviewedAt *time.Time Feedback string `gorm:"type:text"` } type Country struct { TranslatableModel Name string `gorm:"size:100;not null"` Code string `gorm:"size:2;not null;uniqueIndex"` PhoneCode string `gorm:"size:10"` Currency string `gorm:"size:3"` Continent string `gorm:"size:20"` Cities []*City `gorm:"foreignKey:CountryID"` Places []*Place `gorm:"foreignKey:CountryID"` Addresses []*Address `gorm:"foreignKey:CountryID"` } type Language struct { BaseModel Code string `gorm:"size:16;not null;uniqueIndex"` Name string `gorm:"size:100;not null"` Script string `gorm:"size:20"` Direction string `gorm:"size:5"` } type City struct { TranslatableModel Name string `gorm:"size:100;not null"` CountryID uint Country *Country `gorm:"foreignKey:CountryID"` Places []*Place `gorm:"foreignKey:CityID"` Addresses []*Address `gorm:"foreignKey:CityID"` } type Place struct { TranslatableModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Latitude float64 Longitude float64 CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` CityID *uint City *City `gorm:"foreignKey:CityID"` } type Address struct { BaseModel Street string `gorm:"size:255"` StreetNumber string `gorm:"size:20"` PostalCode string `gorm:"size:20"` CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` CityID *uint City *City `gorm:"foreignKey:CityID"` Latitude *float64 Longitude *float64 } type Tag struct { BaseModel Name string `gorm:"size:100;not null;uniqueIndex"` Description string `gorm:"type:text"` Slug string `gorm:"size:255;index"` } type Category struct { BaseModel Name string `gorm:"size:100;not null;uniqueIndex"` Description string `gorm:"type:text"` ParentID *uint Parent *Category `gorm:"foreignKey:ParentID"` Children []*Category `gorm:"foreignKey:ParentID"` Path string `gorm:"size:1024;index"` Slug string `gorm:"size:255;index"` } type Series struct { BaseModel Name string `gorm:"size:255;not null;uniqueIndex"` Description string `gorm:"type:text"` } type Translation struct { BaseModel Title string `gorm:"size:255;not null"` Content string `gorm:"type:text"` Description string `gorm:"type:text"` Language string `gorm:"size:50;not null;uniqueIndex:idx_translation_target_language"` Status TranslationStatus `gorm:"size:50;default:'draft'"` PublishedAt *time.Time TranslatableID uint `gorm:"not null;uniqueIndex:idx_translation_target_language"` TranslatableType string `gorm:"size:50;not null;uniqueIndex:idx_translation_target_language"` TranslatorID *uint Translator *User `gorm:"foreignKey:TranslatorID"` IsOriginalLanguage bool `gorm:"default:false"` AudioURL string `gorm:"size:512"` DateTranslated *time.Time } type TranslationField struct { BaseModel TranslationID uint Translation *Translation `gorm:"foreignKey:TranslationID"` FieldName string `gorm:"size:100;not null"` FieldValue string `gorm:"type:text;not null"` Language string `gorm:"size:50;not null"` } type TranslatableEntity interface { GetID() uint GetType() string GetDefaultLanguage() string } func GetTranslatableFields(entityType string) []string { fieldMappings := map[string][]string{ "Work": {"title", "content", "description"}, "Author": {"name", "biography"}, "Book": {"title", "description"}, "Country": {"name"}, "Publisher": {"name", "description"}, "Source": {"name", "description"}, } if fields, exists := fieldMappings[entityType]; exists { return fields } return []string{} } func (t *Translation) BeforeSave(tx *gorm.DB) error { if t.Title == "" { t.Title = "Untitled Translation" } return nil } func (a *Author) GetID() uint { return a.ID } func (a *Author) GetType() string { return "Author" } func (a *Author) GetDefaultLanguage() string { return a.Language } func (b *Book) GetID() uint { return b.ID } func (b *Book) GetType() string { return "Book" } func (b *Book) GetDefaultLanguage() string { return b.Language } func (c *Country) GetID() uint { return c.ID } func (c *Country) GetType() string { return "Country" } func (c *Country) GetDefaultLanguage() string { return c.Language } func (p *Publisher) GetID() uint { return p.ID } func (p *Publisher) GetType() string { return "Publisher" } func (p *Publisher) GetDefaultLanguage() string { return p.Language } func (s *Source) GetID() uint { return s.ID } func (s *Source) GetType() string { return "Source" } func (s *Source) GetDefaultLanguage() string { return s.Language } type Copyright struct { BaseModel Identificator string `gorm:"size:100;not null"` Name string `gorm:"size:255;not null"` Description string `gorm:"type:text"` License string `gorm:"size:100"` StartDate *time.Time EndDate *time.Time Translations []CopyrightTranslation `gorm:"foreignKey:CopyrightID"` } type AuthorCopyright struct { AuthorID uint `gorm:"primaryKey;index"` CopyrightID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (AuthorCopyright) TableName() string { return "author_copyrights" } type BookCopyright struct { BookID uint `gorm:"primaryKey;index"` CopyrightID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (BookCopyright) TableName() string { return "book_copyrights" } type PublisherCopyright struct { PublisherID uint `gorm:"primaryKey;index"` CopyrightID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (PublisherCopyright) TableName() string { return "publisher_copyrights" } type SourceCopyright struct { SourceID uint `gorm:"primaryKey;index"` CopyrightID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (SourceCopyright) TableName() string { return "source_copyrights" } type CopyrightTranslation struct { BaseModel CopyrightID uint Copyright *Copyright `gorm:"foreignKey:CopyrightID"` LanguageCode string `gorm:"size:10;not null"` Message string `gorm:"type:text;not null"` Description string `gorm:"type:text"` } type CopyrightClaimStatus string const ( CopyrightClaimStatusPending CopyrightClaimStatus = "pending" CopyrightClaimStatusApproved CopyrightClaimStatus = "approved" CopyrightClaimStatusRejected CopyrightClaimStatus = "rejected" ) type CopyrightClaim struct { BaseModel Details string `gorm:"type:text;not null"` Status CopyrightClaimStatus `gorm:"size:50;default:'pending'"` ClaimDate time.Time `gorm:"not null"` Resolution string `gorm:"type:text"` ResolvedAt *time.Time UserID *uint User *User `gorm:"foreignKey:UserID"` } type MonetizationType string const ( MonetizationTypeSubscription MonetizationType = "subscription" MonetizationTypeOneTime MonetizationType = "one_time" MonetizationTypeDonation MonetizationType = "donation" MonetizationTypeAdvertisement MonetizationType = "advertisement" MonetizationTypeLicensing MonetizationType = "licensing" ) type MonetizationStatus string const ( MonetizationStatusActive MonetizationStatus = "active" MonetizationStatusInactive MonetizationStatus = "inactive" MonetizationStatusPending MonetizationStatus = "pending" ) type AuthorMonetization struct { AuthorID uint `gorm:"primaryKey;index"` MonetizationID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (AuthorMonetization) TableName() string { return "author_monetizations" } type BookMonetization struct { BookID uint `gorm:"primaryKey;index"` MonetizationID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (BookMonetization) TableName() string { return "book_monetizations" } type PublisherMonetization struct { PublisherID uint `gorm:"primaryKey;index"` MonetizationID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (PublisherMonetization) TableName() string { return "publisher_monetizations" } type SourceMonetization struct { SourceID uint `gorm:"primaryKey;index"` MonetizationID uint `gorm:"primaryKey;index"` CreatedAt time.Time } func (SourceMonetization) TableName() string { return "source_monetizations" } type Monetization struct { BaseModel Amount float64 `gorm:"type:decimal(10,2);default:0.0"` Currency string `gorm:"size:3;default:'USD'"` Type MonetizationType `gorm:"size:50"` Status MonetizationStatus `gorm:"size:50;default:'active'"` StartDate *time.Time EndDate *time.Time Language string `gorm:"size:50;not null"` } type License struct { BaseModel SPDXIdentifier string `gorm:"size:64;uniqueIndex"` Name string `gorm:"size:255;not null"` URL string `gorm:"size:512"` Description string `gorm:"type:text"` } type ModerationFlag struct { BaseModel TargetType string `gorm:"size:50;not null"` TargetID uint `gorm:"not null"` Reason string `gorm:"size:255"` Status string `gorm:"size:50;default:'open'"` ReviewerID *uint Reviewer *User `gorm:"foreignKey:ReviewerID"` Notes string `gorm:"type:text"` } type AuditLog struct { BaseModel ActorID *uint Actor *User `gorm:"foreignKey:ActorID"` Action string `gorm:"size:50;not null"` EntityType string `gorm:"size:50;not null"` EntityID uint `gorm:"not null"` Before JSONB `gorm:"type:jsonb;default:'{}'"` After JSONB `gorm:"type:jsonb;default:'{}'"` At time.Time `gorm:"autoCreateTime"` } // And all other models from the files I read... // This is getting very long, but it's the correct approach. // I will just paste the rest of the structs here. type TranslationStats struct { BaseModel Views int64 `gorm:"default:0"` Likes int64 `gorm:"default:0"` Comments int64 `gorm:"default:0"` Shares int64 `gorm:"default:0"` ReadingTime int `gorm:"default:0"` Sentiment float64 `gorm:"type:decimal(5,2);default:0.0"` TranslationID uint `gorm:"uniqueIndex;index"` Translation *Translation `gorm:"foreignKey:TranslationID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` } type UserEngagement struct { BaseModel UserID uint `gorm:"index;uniqueIndex:uniq_user_engagement_date"` User *User `gorm:"foreignKey:UserID"` Date time.Time `gorm:"type:date;uniqueIndex:uniq_user_engagement_date"` WorksRead int `gorm:"default:0"` CommentsMade int `gorm:"default:0"` LikesGiven int `gorm:"default:0"` BookmarksMade int `gorm:"default:0"` TranslationsMade int `gorm:"default:0"` } type Trending struct { BaseModel EntityType string `gorm:"size:50;not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"` EntityID uint `gorm:"not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"` Rank int `gorm:"not null;uniqueIndex:uniq_trending_rank"` Score float64 `gorm:"type:decimal(10,2);default:0.0"` TimePeriod string `gorm:"size:50;not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"` Date time.Time `gorm:"type:date;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"` } type BookStats struct { BaseModel Sales int64 `gorm:"default:0"` Views int64 `gorm:"default:0"` Likes int64 `gorm:"default:0"` BookID uint `gorm:"uniqueIndex;index"` Book *Book `gorm:"foreignKey:BookID"` } type CollectionStats struct { BaseModel Items int64 `gorm:"default:0"` Views int64 `gorm:"default:0"` Likes int64 `gorm:"default:0"` CollectionID uint `gorm:"uniqueIndex;index"` Collection *Collection `gorm:"foreignKey:CollectionID"` } type MediaStats struct { BaseModel Views int64 `gorm:"default:0"` Downloads int64 `gorm:"default:0"` Shares int64 `gorm:"default:0"` MediaID uint `gorm:"uniqueIndex;index"` Media interface{} `gorm:"-"` } type AuthorCountry struct { BaseModel AuthorID uint `gorm:"index;uniqueIndex:uniq_author_country"` Author *Author `gorm:"foreignKey:AuthorID"` CountryID uint `gorm:"index;uniqueIndex:uniq_author_country"` Country *Country `gorm:"foreignKey:CountryID"` } type BookAuthor struct { BaseModel BookID uint `gorm:"index;uniqueIndex:uniq_book_author_role"` Book *Book `gorm:"foreignKey:BookID"` AuthorID uint `gorm:"index;uniqueIndex:uniq_book_author_role"` Author *Author `gorm:"foreignKey:AuthorID"` Role string `gorm:"size:50;default:'author';uniqueIndex:uniq_book_author_role"` Ordinal int `gorm:"default:0"` } type ReadabilityScore struct { BaseModel Score float64 `gorm:"type:decimal(5,2)"` Language string `gorm:"size:50;not null"` Method string `gorm:"size:50"` WorkID uint } type WritingStyle struct { BaseModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Language string `gorm:"size:50;not null"` WorkID uint } type LinguisticLayer struct { BaseModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Language string `gorm:"size:50;not null"` Type string `gorm:"size:50"` WorkID uint Data JSONB `gorm:"type:jsonb;default:'{}'"` } type TextBlock struct { BaseModel WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` Index int `gorm:"index"` Type string `gorm:"size:30"` StartOffset int `gorm:"default:0"` EndOffset int `gorm:"default:0"` Text string `gorm:"type:text"` } type TextMetadata struct { BaseModel Analysis string `gorm:"type:text"` Language string `gorm:"size:50;not null"` WordCount int `gorm:"default:0"` SentenceCount int `gorm:"default:0"` ParagraphCount int `gorm:"default:0"` AverageWordLength float64 `gorm:"type:decimal(5,2)"` AverageSentenceLength float64 `gorm:"type:decimal(5,2)"` WorkID uint } type PoeticAnalysis struct { BaseModel Structure string `gorm:"type:text"` Language string `gorm:"size:50;not null"` RhymeScheme string `gorm:"size:100"` MeterType string `gorm:"size:50"` StanzaCount int `gorm:"default:0"` LineCount int `gorm:"default:0"` WorkID uint } type Word struct { BaseModel Text string `gorm:"size:100;not null"` Language string `gorm:"size:50;not null"` PartOfSpeech string `gorm:"size:20"` Lemma string `gorm:"size:100"` ConceptID *uint Concept *Concept `gorm:"foreignKey:ConceptID"` } type WordOccurrence struct { BaseModel TextBlockID uint TextBlock *TextBlock `gorm:"foreignKey:TextBlockID"` WordID *uint Word *Word `gorm:"foreignKey:WordID"` StartOffset int `gorm:"default:0"` EndOffset int `gorm:"default:0"` Lemma string `gorm:"size:100"` PartOfSpeech string `gorm:"size:20"` } type Concept struct { BaseModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Words []*Word `gorm:"foreignKey:ConceptID"` } type LanguageEntity struct { BaseModel Name string `gorm:"size:100;not null"` Type string `gorm:"size:50"` Language string `gorm:"size:50;not null"` } type EntityOccurrence struct { BaseModel TextBlockID uint TextBlock *TextBlock `gorm:"foreignKey:TextBlockID"` LanguageEntityID uint LanguageEntity *LanguageEntity `gorm:"foreignKey:LanguageEntityID"` StartOffset int `gorm:"default:0"` EndOffset int `gorm:"default:0"` } type LanguageAnalysis struct { BaseModel Language string `gorm:"size:50;not null;uniqueIndex:uniq_work_language_analysis"` Analysis JSONB `gorm:"type:jsonb;default:'{}'"` WorkID uint `gorm:"index;uniqueIndex:uniq_work_language_analysis"` } type Gamification struct { BaseModel Points int `gorm:"default:0"` Level int `gorm:"default:1"` Badges JSONB `gorm:"type:jsonb;default:'{}'"` Streaks int `gorm:"default:0"` LastActive *time.Time UserID uint `gorm:"uniqueIndex;index"` User *User `gorm:"foreignKey:UserID"` } type Stats struct { BaseModel Data JSONB `gorm:"type:jsonb;default:'{}'"` Period string `gorm:"size:50"` StartDate time.Time EndDate time.Time UserID *uint User *User `gorm:"foreignKey:UserID"` WorkID *uint } type SearchDocument struct { BaseModel EntityType string `gorm:"size:50;index"` EntityID uint `gorm:"index"` LanguageCode string `gorm:"size:16;index"` Title string `gorm:"size:512"` Body string `gorm:"type:text"` Keywords string `gorm:"type:text"` } type Emotion struct { BaseModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Language string `gorm:"size:50;not null"` Intensity float64 `gorm:"type:decimal(5,2);default:0.0"` UserID *uint User *User `gorm:"foreignKey:UserID"` WorkID *uint CollectionID *uint Collection *Collection `gorm:"foreignKey:CollectionID"` } type Mood struct { BaseModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Language string `gorm:"size:50;not null"` } type TopicCluster struct { BaseModel Name string `gorm:"size:100;not null"` Description string `gorm:"type:text"` Keywords string `gorm:"type:text"` } type Edge struct { BaseModel SourceTable string `gorm:"size:50;not null;index:idx_edge_source;uniqueIndex:uniq_edge"` SourceID uint `gorm:"not null;index:idx_edge_source;uniqueIndex:uniq_edge"` TargetTable string `gorm:"size:50;not null;index:idx_edge_target;uniqueIndex:uniq_edge"` TargetID uint `gorm:"not null;index:idx_edge_target;uniqueIndex:uniq_edge"` Relation string `gorm:"size:50;default:'ASSOCIATED_WITH';not null;index;uniqueIndex:uniq_edge"` Language string `gorm:"size:10;default:'en';index;uniqueIndex:uniq_edge"` Extra JSONB `gorm:"type:jsonb;default:'{}'"` } type Embedding struct { BaseModel ExternalID string `gorm:"size:64;index"` EntityType string `gorm:"size:50;not null;index:idx_embedding_entity;uniqueIndex:uniq_embedding"` EntityID uint `gorm:"not null;index:idx_embedding_entity;uniqueIndex:uniq_embedding"` Model string `gorm:"size:50;not null;uniqueIndex:uniq_embedding"` Dim int `gorm:"default:0"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` } type Localization struct { BaseModel Key string `gorm:"size:255;not null;uniqueIndex:uniq_localization_key_language"` Value string `gorm:"type:text;not null"` Language string `gorm:"size:50;not null;uniqueIndex:uniq_localization_key_language"` } type Media struct { BaseModel URL string `gorm:"size:512;not null"` Type string `gorm:"size:50;not null"` MimeType string `gorm:"size:100"` Size int64 `gorm:"default:0"` Title string `gorm:"size:255"` Description string `gorm:"type:text"` Language string `gorm:"size:50;not null"` AuthorID *uint Author *Author `gorm:"foreignKey:AuthorID"` TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` CountryID *uint Country *Country `gorm:"foreignKey:CountryID"` CityID *uint City *City `gorm:"foreignKey:CityID"` } type Notification struct { BaseModel Message string `gorm:"type:text;not null"` Type string `gorm:"size:50"` Read bool `gorm:"default:false"` Language string `gorm:"size:50;not null"` UserID uint User *User `gorm:"foreignKey:UserID"` RelatedID *uint RelatedType string `gorm:"size:50"` } type EditorialWorkflow struct { BaseModel Stage string `gorm:"size:50;not null"` Notes string `gorm:"type:text"` Language string `gorm:"size:50;not null"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` UserID uint User *User `gorm:"foreignKey:UserID"` AssignedToID *uint AssignedTo *User `gorm:"foreignKey:AssignedToID"` DueDate *time.Time CompletedAt *time.Time } type Admin struct { BaseModel UserID uint User *User `gorm:"foreignKey:UserID"` Role string `gorm:"size:50;not null"` Permissions JSONB `gorm:"type:jsonb;default:'{}'"` } type Vote struct { BaseModel Value int `gorm:"default:0"` UserID uint User *User `gorm:"foreignKey:UserID"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` CommentID *uint Comment *Comment `gorm:"foreignKey:CommentID"` } type Contributor struct { BaseModel Name string `gorm:"size:100;not null"` Role string `gorm:"size:50"` UserID *uint User *User `gorm:"foreignKey:UserID"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` } type InteractionEvent struct { BaseModel UserID *uint User *User `gorm:"foreignKey:UserID"` TargetType string `gorm:"size:50;not null"` TargetID uint `gorm:"not null"` Kind string `gorm:"size:30;not null"` OccurredAt time.Time `gorm:"index"` } type HybridEntityWork struct { BaseModel Name string `gorm:"size:100;not null"` Type string `gorm:"size:50"` WorkID *uint TranslationID *uint Translation *Translation `gorm:"foreignKey:TranslationID"` }