package entity import ( "fmt" "time" "github.com/genex/translate-service/internal/domain/vo" ) // AddressMapping is the aggregate root that maps an internal platform address // to an on-chain address for a given blockchain network. type AddressMapping struct { ID string `json:"id"` UserID string `json:"userId"` InternalAddress string `json:"internalAddress"` ChainAddress string `json:"chainAddress"` ChainType string `json:"chainType"` IsActive bool `json:"isActive"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } // NewAddressMapping is the factory method that creates a fully validated AddressMapping. // It enforces all domain invariants at creation time. func NewAddressMapping(id, userID, internalAddr, chainAddr, chainType string) (*AddressMapping, error) { if id == "" { return nil, fmt.Errorf("mapping ID must not be empty") } if userID == "" { return nil, fmt.Errorf("user ID must not be empty") } // Validate internal address via value object if _, err := vo.NewAddress(internalAddr); err != nil { return nil, fmt.Errorf("invalid internal address: %w", err) } // Validate chain address via value object if _, err := vo.NewAddress(chainAddr); err != nil { return nil, fmt.Errorf("invalid chain address: %w", err) } // Validate chain type via value object if _, err := vo.NewChainType(chainType); err != nil { return nil, err } now := time.Now() return &AddressMapping{ ID: id, UserID: userID, InternalAddress: internalAddr, ChainAddress: chainAddr, ChainType: chainType, IsActive: true, CreatedAt: now, UpdatedAt: now, }, nil } // Validate checks all domain invariants on an existing mapping. func (m *AddressMapping) Validate() error { if m.ID == "" { return fmt.Errorf("mapping ID must not be empty") } if m.UserID == "" { return fmt.Errorf("user ID must not be empty") } if _, err := vo.NewAddress(m.InternalAddress); err != nil { return fmt.Errorf("invalid internal address: %w", err) } if _, err := vo.NewAddress(m.ChainAddress); err != nil { return fmt.Errorf("invalid chain address: %w", err) } if _, err := vo.NewChainType(m.ChainType); err != nil { return err } return nil } // Deactivate marks the mapping as inactive. func (m *AddressMapping) Deactivate() { m.IsActive = false m.UpdatedAt = time.Now() } // Activate marks the mapping as active. func (m *AddressMapping) Activate() { m.IsActive = true m.UpdatedAt = time.Now() } // BelongsToUser checks whether this mapping belongs to the specified user. func (m *AddressMapping) BelongsToUser(userID string) bool { return m.UserID == userID }