package user import ( "regexp" "strings" ) const ( // GlobalRegionCode 是没有命中任何显式国家映射时使用的兜底区域。 GlobalRegionCode = "GLOBAL" // RegionStatusActive 表示区域映射参与国家到区域的实时解析。 RegionStatusActive = "active" // RegionStatusDisabled 表示区域停止解析并释放 active 国家归属。 RegionStatusDisabled = "disabled" // RegionRebuildTaskStatusPending 表示历史用户区域快照等待后台重算。 RegionRebuildTaskStatusPending = "pending" // RegionRebuildTaskStatusRunning 表示任务已被某个 user-service 节点 claim。 RegionRebuildTaskStatusRunning = "running" // RegionRebuildTaskStatusCompleted 表示该 country 下历史用户已经按任务 revision 重算完成。 RegionRebuildTaskStatusCompleted = "completed" // RegionRebuildTaskStatusSkipped 表示任务 revision 已过期,不能覆盖更新映射。 RegionRebuildTaskStatusSkipped = "skipped" // RegionRebuildTaskStatusFailed 表示任务处理失败,等待人工或后续重试策略处理。 RegionRebuildTaskStatusFailed = "failed" ) var ( countryCodePattern = regexp.MustCompile(`^[A-Z]{2,3}$`) isoAlpha3Pattern = regexp.MustCompile(`^[A-Z]{3}$`) isoNumericPattern = regexp.MustCompile(`^[0-9]{3}$`) phoneCountryCodePattern = regexp.MustCompile(`^\+[1-9][0-9]{0,2}$`) shortRegionCodePattern = regexp.MustCompile(`^[A-Za-z0-9_]{2,32}$`) descriptiveRegionCodePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9 _-]{1,63}$`) retiredRegionCodes = map[string]struct{}{ "AUSTRALIA AND NEW ZEALAND": {}, "CARIBBEAN": {}, "MELANESIA": {}, "MICRONESIA": {}, "POLYNESIA": {}, "SOUTHERN AFRICA": {}, "UNSPECIFIED": {}, } ) // Country 是国家主数据;enabled 是唯一可用性开关,外部只提交 CountryCode。 type Country struct { AppCode string CountryID int64 CountryName string CountryCode string ISOAlpha3 string ISONumeric string CountryDisplayName string PhoneCountryCode string Flag string Enabled bool SortOrder int32 CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMs int64 UpdatedAtMs int64 } // Region 是业务区域主数据;Countries 只放 active 国家码快照。 type Region struct { AppCode string RegionID int64 RegionCode string Name string Status string Countries []string SortOrder int32 CreatedByUserID int64 UpdatedByUserID int64 CreatedAtMs int64 UpdatedAtMs int64 } // RegionCountryMapping 表示一个 active 或历史国家到区域归属记录。 type RegionCountryMapping struct { AppCode string RegionID int64 CountryCode string Status string CreatedAtMs int64 UpdatedAtMs int64 } // RegionChangeLog 是管理端区域配置审计,不记录用户隐私资料。 type RegionChangeLog struct { AppCode string RegionID int64 Operation string BeforeJSON string AfterJSON string OperatorUserID int64 RequestID string CreatedAtMs int64 } // UserRegionRebuildTask 表示按国家分页刷新 users.region_id 的后台任务。 type UserRegionRebuildTask struct { AppCode string TaskID int64 RegionID int64 CountryCode string TargetRegionID int64 MappingRevision int64 Status string CursorUserID int64 LockedBy string LockedUntilMs int64 AttemptCount int32 ErrorMessage string CreatedAtMs int64 UpdatedAtMs int64 } // RegionRebuildProcessResult 描述单次 worker 处理结果,便于测试和日志输出。 type RegionRebuildProcessResult struct { AppCode string TaskID int64 CountryCode string TargetRegionID int64 Status string ProcessedUsers int CursorUserID int64 NoTask bool } // CountryFilter 描述国家管理列表过滤条件;国家只支持 enabled 维度过滤。 type CountryFilter struct { AppCode string Enabled *bool } // RegionFilter 描述区域管理列表过滤条件。 type RegionFilter struct { AppCode string Status string } // UpdateCountryCommand 描述修改国家展示字段的事务输入,CountryCode 创建后不可变。 type UpdateCountryCommand struct { AppCode string CountryID int64 CountryName string ISOAlpha3 string ISONumeric string CountryDisplayName string PhoneCountryCode string Flag string SortOrder int32 OperatorUserID int64 RequestID string NowMs int64 } // UpdateRegionCommand 描述修改区域展示字段的事务输入,不修改 countries。 type UpdateRegionCommand struct { AppCode string RegionID int64 RegionCode string Name string SortOrder int32 OperatorUserID int64 RequestID string NowMs int64 } // ReplaceRegionCountriesCommand 描述原子替换区域 active 国家归属的事务输入。 type ReplaceRegionCountriesCommand struct { AppCode string RegionID int64 Countries []string OperatorUserID int64 RequestID string NowMs int64 } // NormalizeCountryCode 统一客户端和管理端提交的国家码形态。 func NormalizeCountryCode(code string) string { return strings.ToUpper(strings.TrimSpace(code)) } // ValidCountryCode 校验本系统允许的两到三位大写英文国家码。 func ValidCountryCode(code string) bool { return countryCodePattern.MatchString(code) } // NormalizeISOAlpha3 统一 ISO alpha-3 辅助展示字段形态;空值表示未配置。 func NormalizeISOAlpha3(code string) string { return strings.ToUpper(strings.TrimSpace(code)) } // ValidISOAlpha3 校验非空 ISO alpha-3 或明确 user-assigned 三字码。 func ValidISOAlpha3(code string) bool { return code == "" || isoAlpha3Pattern.MatchString(code) } // NormalizeISONumeric 统一 ISO numeric/M49 字符串形态,不能转整数以免破坏前导零。 func NormalizeISONumeric(code string) string { return strings.TrimSpace(code) } // ValidISONumeric 校验非空 numeric 必须是三位数字字符串。 func ValidISONumeric(code string) bool { return code == "" || isoNumericPattern.MatchString(code) } // NormalizePhoneCountryCode 统一 E.164 国家呼叫码字段,空值表示无可用电话元数据。 func NormalizePhoneCountryCode(code string) string { return strings.TrimSpace(code) } // ValidPhoneCountryCode 校验国家呼叫码,不做唯一性假设,因为多个国家可以共享 +1。 func ValidPhoneCountryCode(code string) bool { return code == "" || phoneCountryCodePattern.MatchString(code) } // NormalizeRegionCode 统一区域业务编码形态。 func NormalizeRegionCode(code string) string { code = strings.TrimSpace(code) if shortRegionCodePattern.MatchString(code) { // 手工业务短码继续统一大写;导入的 subregion 描述码保留原始大小写和空格。 return strings.ToUpper(code) } return strings.Join(strings.Fields(code), " ") } // ValidRegionCode 校验区域编码,避免自由文本进入唯一键和审计口径。 func ValidRegionCode(code string) bool { return shortRegionCodePattern.MatchString(code) || descriptiveRegionCodePattern.MatchString(code) } // IsGlobalRegionCode 判断区域是否是兜底 GLOBAL 区域。 func IsGlobalRegionCode(code string) bool { return NormalizeRegionCode(code) == GlobalRegionCode } // IsRetiredRegionCode 判断区域是否已从业务区域集合中移除。 func IsRetiredRegionCode(code string) bool { _, ok := retiredRegionCodes[strings.ToUpper(NormalizeRegionCode(code))] return ok }