// Package account defines the logical user-account entities owned directly by // User Service. package account import ( "fmt" "strings" "time" "galaxy/user/internal/domain/common" ) // RaceNameCanonicalKey stores the policy-produced reservation key used to // enforce replaceable race-name uniqueness. type RaceNameCanonicalKey string // String returns RaceNameCanonicalKey as its stored canonical string. func (key RaceNameCanonicalKey) String() string { return string(key) } // IsZero reports whether RaceNameCanonicalKey does not contain a usable value. func (key RaceNameCanonicalKey) IsZero() bool { return strings.TrimSpace(string(key)) == "" } // Validate reports whether RaceNameCanonicalKey is non-empty and trimmed. func (key RaceNameCanonicalKey) Validate() error { switch { case key.IsZero(): return fmt.Errorf("race name canonical key must not be empty") case strings.TrimSpace(string(key)) != string(key): return fmt.Errorf("race name canonical key must not contain surrounding whitespace") default: return nil } } // 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 // RaceName stores the original-casing user-facing race name. RaceName common.RaceName // 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 } // Validate reports whether UserAccount satisfies the frozen Stage 02 // structural invariants. 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.RaceName.Validate(); err != nil { return fmt.Errorf("user account race 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") } return nil } // RaceNameReservation stores the current uniqueness reservation for one // canonicalized race-name key. type RaceNameReservation struct { // CanonicalKey stores the policy-produced uniqueness key. CanonicalKey RaceNameCanonicalKey // UserID identifies the account that owns the reservation. UserID common.UserID // RaceName stores the original-casing name linked to the reservation. RaceName common.RaceName // ReservedAt stores when the reservation was acquired. ReservedAt time.Time } // Validate reports whether RaceNameReservation satisfies the frozen Stage 02 // structural invariants. func (record RaceNameReservation) Validate() error { if err := record.CanonicalKey.Validate(); err != nil { return fmt.Errorf("race name reservation canonical key: %w", err) } if err := record.UserID.Validate(); err != nil { return fmt.Errorf("race name reservation user id: %w", err) } if err := record.RaceName.Validate(); err != nil { return fmt.Errorf("race name reservation race name: %w", err) } if err := common.ValidateTimestamp("race name reservation reserved at", record.ReservedAt); err != nil { return err } return nil }