package entities import ( "time" "github.com/google/uuid" "github.com/rwadurian/mpc-system/services/account/domain/value_objects" ) // Account represents a user account with MPC-based authentication type Account struct { ID value_objects.AccountID Username string Email string Phone *string PublicKey []byte // MPC group public key KeygenSessionID uuid.UUID ThresholdN int ThresholdT int Status value_objects.AccountStatus CreatedAt time.Time UpdatedAt time.Time LastLoginAt *time.Time } // NewAccount creates a new Account func NewAccount( username string, email string, publicKey []byte, keygenSessionID uuid.UUID, thresholdN int, thresholdT int, ) *Account { now := time.Now().UTC() return &Account{ ID: value_objects.NewAccountID(), Username: username, Email: email, PublicKey: publicKey, KeygenSessionID: keygenSessionID, ThresholdN: thresholdN, ThresholdT: thresholdT, Status: value_objects.AccountStatusActive, CreatedAt: now, UpdatedAt: now, } } // SetPhone sets the phone number func (a *Account) SetPhone(phone string) { a.Phone = &phone a.UpdatedAt = time.Now().UTC() } // UpdateLastLogin updates the last login timestamp func (a *Account) UpdateLastLogin() { now := time.Now().UTC() a.LastLoginAt = &now a.UpdatedAt = now } // Suspend suspends the account func (a *Account) Suspend() error { if a.Status == value_objects.AccountStatusRecovering { return ErrAccountInRecovery } a.Status = value_objects.AccountStatusSuspended a.UpdatedAt = time.Now().UTC() return nil } // Lock locks the account func (a *Account) Lock() error { if a.Status == value_objects.AccountStatusRecovering { return ErrAccountInRecovery } a.Status = value_objects.AccountStatusLocked a.UpdatedAt = time.Now().UTC() return nil } // Activate activates the account func (a *Account) Activate() { a.Status = value_objects.AccountStatusActive a.UpdatedAt = time.Now().UTC() } // StartRecovery marks the account as recovering func (a *Account) StartRecovery() error { if !a.Status.CanInitiateRecovery() { return ErrCannotInitiateRecovery } a.Status = value_objects.AccountStatusRecovering a.UpdatedAt = time.Now().UTC() return nil } // CompleteRecovery completes the recovery process with new public key func (a *Account) CompleteRecovery(newPublicKey []byte, newKeygenSessionID uuid.UUID) { a.PublicKey = newPublicKey a.KeygenSessionID = newKeygenSessionID a.Status = value_objects.AccountStatusActive a.UpdatedAt = time.Now().UTC() } // CanLogin checks if the account can login func (a *Account) CanLogin() bool { return a.Status.CanLogin() } // IsActive checks if the account is active func (a *Account) IsActive() bool { return a.Status == value_objects.AccountStatusActive } // Validate validates the account data func (a *Account) Validate() error { if a.Username == "" { return ErrInvalidUsername } if a.Email == "" { return ErrInvalidEmail } if len(a.PublicKey) == 0 { return ErrInvalidPublicKey } if a.ThresholdT > a.ThresholdN || a.ThresholdT <= 0 { return ErrInvalidThreshold } return nil } // Account errors var ( ErrInvalidUsername = &AccountError{Code: "INVALID_USERNAME", Message: "username is required"} ErrInvalidEmail = &AccountError{Code: "INVALID_EMAIL", Message: "email is required"} ErrInvalidPublicKey = &AccountError{Code: "INVALID_PUBLIC_KEY", Message: "public key is required"} ErrInvalidThreshold = &AccountError{Code: "INVALID_THRESHOLD", Message: "invalid threshold configuration"} ErrAccountInRecovery = &AccountError{Code: "ACCOUNT_IN_RECOVERY", Message: "account is in recovery mode"} ErrCannotInitiateRecovery = &AccountError{Code: "CANNOT_INITIATE_RECOVERY", Message: "cannot initiate recovery in current state"} ErrAccountNotActive = &AccountError{Code: "ACCOUNT_NOT_ACTIVE", Message: "account is not active"} ErrAccountNotFound = &AccountError{Code: "ACCOUNT_NOT_FOUND", Message: "account not found"} ErrDuplicateUsername = &AccountError{Code: "DUPLICATE_USERNAME", Message: "username already exists"} ErrDuplicateEmail = &AccountError{Code: "DUPLICATE_EMAIL", Message: "email already exists"} ) // AccountError represents an account domain error type AccountError struct { Code string Message string } func (e *AccountError) Error() string { return e.Message }