// Package account defines the logical user-account entities owned directly by // User Service. package account import ( "fmt" "time" "galaxy/user/internal/domain/common" ) // UserAccount stores the current editable account state of one regular user. type UserAccount struct { // UserID identifies the durable regular-user account. UserID common.UserID // Email stores the normalized login/contact address of the account. Email common.Email // UserName stores the immutable auto-generated `player-` handle. UserName common.UserName // DisplayName stores the optional mutable free-text user-facing label. DisplayName common.DisplayName // PreferredLanguage stores the current declared language tag. PreferredLanguage common.LanguageTag // TimeZone stores the current declared time-zone name. TimeZone common.TimeZoneName // DeclaredCountry stores the latest effective declared-country value. The // zero value means the geo workflow has not synchronized any country yet. DeclaredCountry common.CountryCode // CreatedAt stores the account creation timestamp. CreatedAt time.Time // UpdatedAt stores the last account mutation timestamp. UpdatedAt time.Time // DeletedAt stores the soft-delete timestamp set by the `DeleteUser` // command. A nil value means the account is live. A non-nil value marks // the record as soft-deleted: external auth, self-service, admin-read, // and lobby-eligibility operations must reject subsequent access with // `subject_not_found`. DeletedAt *time.Time } // IsDeleted reports whether the account has been soft-deleted through the // `DeleteUser` command. func (record UserAccount) IsDeleted() bool { return record.DeletedAt != nil } // Validate reports whether UserAccount satisfies the Stage 21 structural // invariants, including the Stage 22 soft-delete rules. func (record UserAccount) Validate() error { if err := record.UserID.Validate(); err != nil { return fmt.Errorf("user account user id: %w", err) } if err := record.Email.Validate(); err != nil { return fmt.Errorf("user account email: %w", err) } if err := record.UserName.Validate(); err != nil { return fmt.Errorf("user account user name: %w", err) } if err := record.DisplayName.Validate(); err != nil { return fmt.Errorf("user account display name: %w", err) } if err := record.PreferredLanguage.Validate(); err != nil { return fmt.Errorf("user account preferred language: %w", err) } if err := record.TimeZone.Validate(); err != nil { return fmt.Errorf("user account time zone: %w", err) } if !record.DeclaredCountry.IsZero() { if err := record.DeclaredCountry.Validate(); err != nil { return fmt.Errorf("user account declared country: %w", err) } } if err := common.ValidateTimestamp("user account created at", record.CreatedAt); err != nil { return err } if err := common.ValidateTimestamp("user account updated at", record.UpdatedAt); err != nil { return err } if record.UpdatedAt.Before(record.CreatedAt) { return fmt.Errorf("user account updated at must not be before created at") } if record.DeletedAt != nil { if err := common.ValidateTimestamp("user account deleted at", *record.DeletedAt); err != nil { return err } if record.DeletedAt.Before(record.CreatedAt) { return fmt.Errorf("user account deleted at must not be before created at") } } return nil }