// Package invite defines user-service invitation facts and read models. package invite import ( "regexp" "strings" ) const ( // CodeStatusActive means a code can be used by new registrations. CodeStatusActive = "active" // CodeTypePrimary is the shareable per-user permanent invite code. CodeTypePrimary = "primary" // ProgressStatusPending means the invited user has not reached the configured recharge threshold. ProgressStatusPending = "pending" // ProgressStatusValid means the invited user has reached the threshold and counted once. ProgressStatusValid = "valid" // EventTypeUserInvited is emitted when an invitation relation is first bound. EventTypeUserInvited = "UserInvited" // EventTypeUserInviteBecameValid is emitted when recharge progress first crosses the policy threshold. EventTypeUserInviteBecameValid = "UserInviteBecameValid" // RechargeEventWalletRecorded is the wallet outbox event that invitation validity consumes. RechargeEventWalletRecorded = "WalletRechargeRecorded" // RechargeTypeCoinSellerTransfer is the current recharge fact produced by wallet-service coin seller transfer. RechargeTypeCoinSellerTransfer = "coin_seller_transfer" ) const ( // CodeMinLength keeps user-entered invite codes short enough for mobile manual entry. CodeMinLength = 6 // CodeMaxLength follows the current SQL VARCHAR boundary for invite code snapshots. CodeMaxLength = 64 ) var codePattern = regexp.MustCompile(`^[A-Z0-9]{6,64}$`) // Overview is the read model returned with user profile for my-page aggregation. type Overview struct { MyInviteCode string InviteEnabled bool InviteCount int64 ValidInviteCount int64 ValidInviteThresholdCoin int64 } // Binding is the result of one registration/onboarding invitation bind attempt. type Binding struct { Bound bool InviteCode string InviterUserID int64 } // BindCommand describes one optional invitation attribution write. type BindCommand struct { AppCode string InvitedUserID int64 InvitedRegionID int64 InviteCode string Source string RequestID string BoundAtMs int64 } // RechargeEvent is the wallet recharge fact consumed by invitation validity. type RechargeEvent struct { AppCode string EventID string EventType string TransactionID string CommandID string InvitedUserID int64 AssetType string RechargeCoinAmount int64 RechargeType string OccurredAtMs int64 PayloadJSON string } // RechargeApplyResult summarizes idempotent invitation recharge processing. type RechargeApplyResult struct { Consumed bool Skipped bool Valid bool Reason string } // NormalizeCode trims and uppercases user-provided invite code text. func NormalizeCode(code string) string { return strings.ToUpper(strings.TrimSpace(code)) } // ValidCode checks only syntax; ownership and active status are repository facts. func ValidCode(code string) bool { code = NormalizeCode(code) return len(code) >= CodeMinLength && len(code) <= CodeMaxLength && codePattern.MatchString(code) }