Browse Source

feat: 自定义验证

gms 1 month ago
parent
commit
385888aa33

+ 1674 - 0
kuban/api/validate/business_rules.pb.go

@@ -0,0 +1,1674 @@
+// Copyright 2025 Kuban Technologies
+//
+// 业务规则库 - 针对中国业务场景的预定义验证规则
+// 提供开箱即用的常用业务验证
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.6-modify
+// 	protoc        v6.31.1
+// source: kuban/api/validate/business_rules.proto
+
+package validate
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	_ "google.golang.org/protobuf/types/descriptorpb"
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// 手机运营商枚举
+type MobileOperator int32
+
+const (
+	MobileOperator_MOBILE_OPERATOR_UNSPECIFIED    MobileOperator = 0
+	MobileOperator_MOBILE_OPERATOR_CHINA_MOBILE   MobileOperator = 1 // 中国移动
+	MobileOperator_MOBILE_OPERATOR_CHINA_UNICOM   MobileOperator = 2 // 中国联通
+	MobileOperator_MOBILE_OPERATOR_CHINA_TELECOM  MobileOperator = 3 // 中国电信
+	MobileOperator_MOBILE_OPERATOR_CHINA_BROADNET MobileOperator = 4 // 中国广电
+)
+
+// Enum value maps for MobileOperator.
+var (
+	MobileOperator_name = map[int32]string{
+		0: "MOBILE_OPERATOR_UNSPECIFIED",
+		1: "MOBILE_OPERATOR_CHINA_MOBILE",
+		2: "MOBILE_OPERATOR_CHINA_UNICOM",
+		3: "MOBILE_OPERATOR_CHINA_TELECOM",
+		4: "MOBILE_OPERATOR_CHINA_BROADNET",
+	}
+	MobileOperator_value = map[string]int32{
+		"MOBILE_OPERATOR_UNSPECIFIED":    0,
+		"MOBILE_OPERATOR_CHINA_MOBILE":   1,
+		"MOBILE_OPERATOR_CHINA_UNICOM":   2,
+		"MOBILE_OPERATOR_CHINA_TELECOM":  3,
+		"MOBILE_OPERATOR_CHINA_BROADNET": 4,
+	}
+)
+
+func (x MobileOperator) Enum() *MobileOperator {
+	p := new(MobileOperator)
+	*p = x
+	return p
+}
+
+func (x MobileOperator) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (MobileOperator) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_business_rules_proto_enumTypes[0].Descriptor()
+}
+
+func (MobileOperator) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_business_rules_proto_enumTypes[0]
+}
+
+func (x MobileOperator) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use MobileOperator.Descriptor instead.
+func (MobileOperator) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{0}
+}
+
+// 身份证类型
+type IdCardType int32
+
+const (
+	IdCardType_ID_CARD_TYPE_UNSPECIFIED IdCardType = 0
+	IdCardType_ID_CARD_TYPE_18_DIGIT    IdCardType = 1 // 18位身份证
+	IdCardType_ID_CARD_TYPE_15_DIGIT    IdCardType = 2 // 15位身份证(旧版)
+)
+
+// Enum value maps for IdCardType.
+var (
+	IdCardType_name = map[int32]string{
+		0: "ID_CARD_TYPE_UNSPECIFIED",
+		1: "ID_CARD_TYPE_18_DIGIT",
+		2: "ID_CARD_TYPE_15_DIGIT",
+	}
+	IdCardType_value = map[string]int32{
+		"ID_CARD_TYPE_UNSPECIFIED": 0,
+		"ID_CARD_TYPE_18_DIGIT":    1,
+		"ID_CARD_TYPE_15_DIGIT":    2,
+	}
+)
+
+func (x IdCardType) Enum() *IdCardType {
+	p := new(IdCardType)
+	*p = x
+	return p
+}
+
+func (x IdCardType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (IdCardType) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_business_rules_proto_enumTypes[1].Descriptor()
+}
+
+func (IdCardType) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_business_rules_proto_enumTypes[1]
+}
+
+func (x IdCardType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use IdCardType.Descriptor instead.
+func (IdCardType) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{1}
+}
+
+// 性别枚举
+type Gender int32
+
+const (
+	Gender_GENDER_UNSPECIFIED Gender = 0
+	Gender_GENDER_MALE        Gender = 1 // 男性
+	Gender_GENDER_FEMALE      Gender = 2 // 女性
+)
+
+// Enum value maps for Gender.
+var (
+	Gender_name = map[int32]string{
+		0: "GENDER_UNSPECIFIED",
+		1: "GENDER_MALE",
+		2: "GENDER_FEMALE",
+	}
+	Gender_value = map[string]int32{
+		"GENDER_UNSPECIFIED": 0,
+		"GENDER_MALE":        1,
+		"GENDER_FEMALE":      2,
+	}
+)
+
+func (x Gender) Enum() *Gender {
+	p := new(Gender)
+	*p = x
+	return p
+}
+
+func (x Gender) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Gender) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_business_rules_proto_enumTypes[2].Descriptor()
+}
+
+func (Gender) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_business_rules_proto_enumTypes[2]
+}
+
+func (x Gender) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Gender.Descriptor instead.
+func (Gender) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{2}
+}
+
+// 机构类型
+type OrganizationType int32
+
+const (
+	OrganizationType_ORGANIZATION_TYPE_UNSPECIFIED  OrganizationType = 0
+	OrganizationType_ORGANIZATION_TYPE_ENTERPRISE   OrganizationType = 1 // 企业
+	OrganizationType_ORGANIZATION_TYPE_INSTITUTION  OrganizationType = 2 // 事业单位
+	OrganizationType_ORGANIZATION_TYPE_SOCIAL_GROUP OrganizationType = 3 // 社会团体
+	OrganizationType_ORGANIZATION_TYPE_GOVERNMENT   OrganizationType = 9 // 机关
+)
+
+// Enum value maps for OrganizationType.
+var (
+	OrganizationType_name = map[int32]string{
+		0: "ORGANIZATION_TYPE_UNSPECIFIED",
+		1: "ORGANIZATION_TYPE_ENTERPRISE",
+		2: "ORGANIZATION_TYPE_INSTITUTION",
+		3: "ORGANIZATION_TYPE_SOCIAL_GROUP",
+		9: "ORGANIZATION_TYPE_GOVERNMENT",
+	}
+	OrganizationType_value = map[string]int32{
+		"ORGANIZATION_TYPE_UNSPECIFIED":  0,
+		"ORGANIZATION_TYPE_ENTERPRISE":   1,
+		"ORGANIZATION_TYPE_INSTITUTION":  2,
+		"ORGANIZATION_TYPE_SOCIAL_GROUP": 3,
+		"ORGANIZATION_TYPE_GOVERNMENT":   9,
+	}
+)
+
+func (x OrganizationType) Enum() *OrganizationType {
+	p := new(OrganizationType)
+	*p = x
+	return p
+}
+
+func (x OrganizationType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (OrganizationType) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_business_rules_proto_enumTypes[3].Descriptor()
+}
+
+func (OrganizationType) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_business_rules_proto_enumTypes[3]
+}
+
+func (x OrganizationType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use OrganizationType.Descriptor instead.
+func (OrganizationType) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{3}
+}
+
+// 银行卡类型
+type BankCardType int32
+
+const (
+	BankCardType_BANK_CARD_TYPE_UNSPECIFIED BankCardType = 0
+	BankCardType_BANK_CARD_TYPE_DEBIT       BankCardType = 1 // 借记卡
+	BankCardType_BANK_CARD_TYPE_CREDIT      BankCardType = 2 // 信用卡
+)
+
+// Enum value maps for BankCardType.
+var (
+	BankCardType_name = map[int32]string{
+		0: "BANK_CARD_TYPE_UNSPECIFIED",
+		1: "BANK_CARD_TYPE_DEBIT",
+		2: "BANK_CARD_TYPE_CREDIT",
+	}
+	BankCardType_value = map[string]int32{
+		"BANK_CARD_TYPE_UNSPECIFIED": 0,
+		"BANK_CARD_TYPE_DEBIT":       1,
+		"BANK_CARD_TYPE_CREDIT":      2,
+	}
+)
+
+func (x BankCardType) Enum() *BankCardType {
+	p := new(BankCardType)
+	*p = x
+	return p
+}
+
+func (x BankCardType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BankCardType) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_business_rules_proto_enumTypes[4].Descriptor()
+}
+
+func (BankCardType) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_business_rules_proto_enumTypes[4]
+}
+
+func (x BankCardType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use BankCardType.Descriptor instead.
+func (BankCardType) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{4}
+}
+
+// 中国手机号验证规则
+type ChineseMobileRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否启用验证
+	Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled"`
+	// 允许的运营商
+	AllowedOperators []MobileOperator `protobuf:"varint,2,rep,packed,name=allowed_operators,json=allowedOperators,proto3,enum=kuban.api.validate.MobileOperator" json:"allowed_operators"`
+	// 是否允许虚拟运营商号码
+	AllowVirtual bool `protobuf:"varint,3,opt,name=allow_virtual,json=allowVirtual,proto3" json:"allow_virtual"`
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,4,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ChineseMobileRules) Reset() {
+	*x = ChineseMobileRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ChineseMobileRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChineseMobileRules) ProtoMessage() {}
+
+func (x *ChineseMobileRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChineseMobileRules.ProtoReflect.Descriptor instead.
+func (*ChineseMobileRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ChineseMobileRules) GetEnabled() bool {
+	if x != nil {
+		return x.Enabled
+	}
+	return false
+}
+
+func (x *ChineseMobileRules) GetAllowedOperators() []MobileOperator {
+	if x != nil {
+		return x.AllowedOperators
+	}
+	return nil
+}
+
+func (x *ChineseMobileRules) GetAllowVirtual() bool {
+	if x != nil {
+		return x.AllowVirtual
+	}
+	return false
+}
+
+func (x *ChineseMobileRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 中国身份证验证规则
+type ChineseIdCardRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否启用验证
+	Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled"`
+	// 是否验证校验位
+	VerifyChecksum bool `protobuf:"varint,2,opt,name=verify_checksum,json=verifyChecksum,proto3" json:"verify_checksum"`
+	// 是否验证出生日期有效性
+	VerifyBirthDate bool `protobuf:"varint,3,opt,name=verify_birth_date,json=verifyBirthDate,proto3" json:"verify_birth_date"`
+	// 是否验证地区码有效性
+	VerifyAreaCode bool `protobuf:"varint,4,opt,name=verify_area_code,json=verifyAreaCode,proto3" json:"verify_area_code"`
+	// 允许的身份证类型
+	AllowedTypes []IdCardType `protobuf:"varint,5,rep,packed,name=allowed_types,json=allowedTypes,proto3,enum=kuban.api.validate.IdCardType" json:"allowed_types"`
+	// 年龄范围限制
+	MinAge *int32 `protobuf:"varint,6,opt,name=min_age,json=minAge,proto3,oneof" json:"min_age"`
+	MaxAge *int32 `protobuf:"varint,7,opt,name=max_age,json=maxAge,proto3,oneof" json:"max_age"`
+	// 性别限制
+	RequiredGender *Gender `protobuf:"varint,8,opt,name=required_gender,json=requiredGender,proto3,enum=kuban.api.validate.Gender,oneof" json:"required_gender"`
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,9,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ChineseIdCardRules) Reset() {
+	*x = ChineseIdCardRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ChineseIdCardRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChineseIdCardRules) ProtoMessage() {}
+
+func (x *ChineseIdCardRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChineseIdCardRules.ProtoReflect.Descriptor instead.
+func (*ChineseIdCardRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ChineseIdCardRules) GetEnabled() bool {
+	if x != nil {
+		return x.Enabled
+	}
+	return false
+}
+
+func (x *ChineseIdCardRules) GetVerifyChecksum() bool {
+	if x != nil {
+		return x.VerifyChecksum
+	}
+	return false
+}
+
+func (x *ChineseIdCardRules) GetVerifyBirthDate() bool {
+	if x != nil {
+		return x.VerifyBirthDate
+	}
+	return false
+}
+
+func (x *ChineseIdCardRules) GetVerifyAreaCode() bool {
+	if x != nil {
+		return x.VerifyAreaCode
+	}
+	return false
+}
+
+func (x *ChineseIdCardRules) GetAllowedTypes() []IdCardType {
+	if x != nil {
+		return x.AllowedTypes
+	}
+	return nil
+}
+
+func (x *ChineseIdCardRules) GetMinAge() int32 {
+	if x != nil && x.MinAge != nil {
+		return *x.MinAge
+	}
+	return 0
+}
+
+func (x *ChineseIdCardRules) GetMaxAge() int32 {
+	if x != nil && x.MaxAge != nil {
+		return *x.MaxAge
+	}
+	return 0
+}
+
+func (x *ChineseIdCardRules) GetRequiredGender() Gender {
+	if x != nil && x.RequiredGender != nil {
+		return *x.RequiredGender
+	}
+	return Gender_GENDER_UNSPECIFIED
+}
+
+func (x *ChineseIdCardRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 统一社会信用代码验证规则
+type UnifiedSocialCreditCodeRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否启用验证
+	Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled"`
+	// 是否验证校验位
+	VerifyChecksum bool `protobuf:"varint,2,opt,name=verify_checksum,json=verifyChecksum,proto3" json:"verify_checksum"`
+	// 允许的机构类型
+	AllowedTypes []OrganizationType `protobuf:"varint,3,rep,packed,name=allowed_types,json=allowedTypes,proto3,enum=kuban.api.validate.OrganizationType" json:"allowed_types"`
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,4,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *UnifiedSocialCreditCodeRules) Reset() {
+	*x = UnifiedSocialCreditCodeRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *UnifiedSocialCreditCodeRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnifiedSocialCreditCodeRules) ProtoMessage() {}
+
+func (x *UnifiedSocialCreditCodeRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnifiedSocialCreditCodeRules.ProtoReflect.Descriptor instead.
+func (*UnifiedSocialCreditCodeRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *UnifiedSocialCreditCodeRules) GetEnabled() bool {
+	if x != nil {
+		return x.Enabled
+	}
+	return false
+}
+
+func (x *UnifiedSocialCreditCodeRules) GetVerifyChecksum() bool {
+	if x != nil {
+		return x.VerifyChecksum
+	}
+	return false
+}
+
+func (x *UnifiedSocialCreditCodeRules) GetAllowedTypes() []OrganizationType {
+	if x != nil {
+		return x.AllowedTypes
+	}
+	return nil
+}
+
+func (x *UnifiedSocialCreditCodeRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 银行卡号验证规则
+type BankCardRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否启用验证
+	Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled"`
+	// 是否使用 Luhn 算法验证
+	VerifyLuhn bool `protobuf:"varint,2,opt,name=verify_luhn,json=verifyLuhn,proto3" json:"verify_luhn"`
+	// 允许的卡类型
+	AllowedTypes []BankCardType `protobuf:"varint,3,rep,packed,name=allowed_types,json=allowedTypes,proto3,enum=kuban.api.validate.BankCardType" json:"allowed_types"`
+	// 允许的银行
+	AllowedBanks []string `protobuf:"bytes,4,rep,name=allowed_banks,json=allowedBanks,proto3" json:"allowed_banks"` // 银行代码列表
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,5,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BankCardRules) Reset() {
+	*x = BankCardRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BankCardRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BankCardRules) ProtoMessage() {}
+
+func (x *BankCardRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BankCardRules.ProtoReflect.Descriptor instead.
+func (*BankCardRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *BankCardRules) GetEnabled() bool {
+	if x != nil {
+		return x.Enabled
+	}
+	return false
+}
+
+func (x *BankCardRules) GetVerifyLuhn() bool {
+	if x != nil {
+		return x.VerifyLuhn
+	}
+	return false
+}
+
+func (x *BankCardRules) GetAllowedTypes() []BankCardType {
+	if x != nil {
+		return x.AllowedTypes
+	}
+	return nil
+}
+
+func (x *BankCardRules) GetAllowedBanks() []string {
+	if x != nil {
+		return x.AllowedBanks
+	}
+	return nil
+}
+
+func (x *BankCardRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 中文姓名验证规则
+type ChineseNameRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否启用验证
+	Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled"`
+	// 最小长度(字符数)
+	MinLength *uint32 `protobuf:"varint,2,opt,name=min_length,json=minLength,proto3,oneof" json:"min_length"`
+	// 最大长度(字符数)
+	MaxLength *uint32 `protobuf:"varint,3,opt,name=max_length,json=maxLength,proto3,oneof" json:"max_length"`
+	// 是否允许少数民族姓名(可能包含·等特殊字符)
+	AllowEthnicMinority bool `protobuf:"varint,4,opt,name=allow_ethnic_minority,json=allowEthnicMinority,proto3" json:"allow_ethnic_minority"`
+	// 是否允许英文名
+	AllowEnglish bool `protobuf:"varint,5,opt,name=allow_english,json=allowEnglish,proto3" json:"allow_english"`
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,6,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ChineseNameRules) Reset() {
+	*x = ChineseNameRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ChineseNameRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChineseNameRules) ProtoMessage() {}
+
+func (x *ChineseNameRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChineseNameRules.ProtoReflect.Descriptor instead.
+func (*ChineseNameRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ChineseNameRules) GetEnabled() bool {
+	if x != nil {
+		return x.Enabled
+	}
+	return false
+}
+
+func (x *ChineseNameRules) GetMinLength() uint32 {
+	if x != nil && x.MinLength != nil {
+		return *x.MinLength
+	}
+	return 0
+}
+
+func (x *ChineseNameRules) GetMaxLength() uint32 {
+	if x != nil && x.MaxLength != nil {
+		return *x.MaxLength
+	}
+	return 0
+}
+
+func (x *ChineseNameRules) GetAllowEthnicMinority() bool {
+	if x != nil {
+		return x.AllowEthnicMinority
+	}
+	return false
+}
+
+func (x *ChineseNameRules) GetAllowEnglish() bool {
+	if x != nil {
+		return x.AllowEnglish
+	}
+	return false
+}
+
+func (x *ChineseNameRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 邮政编码验证规则
+type PostcodeRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否启用验证
+	Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled"`
+	// 国家/地区代码(默认为中国 CN)
+	CountryCode string `protobuf:"bytes,2,opt,name=country_code,json=countryCode,proto3" json:"country_code"`
+	// 允许的省份代码(中国邮编前两位)
+	AllowedProvinces []string `protobuf:"bytes,3,rep,name=allowed_provinces,json=allowedProvinces,proto3" json:"allowed_provinces"`
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,4,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *PostcodeRules) Reset() {
+	*x = PostcodeRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *PostcodeRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PostcodeRules) ProtoMessage() {}
+
+func (x *PostcodeRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PostcodeRules.ProtoReflect.Descriptor instead.
+func (*PostcodeRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *PostcodeRules) GetEnabled() bool {
+	if x != nil {
+		return x.Enabled
+	}
+	return false
+}
+
+func (x *PostcodeRules) GetCountryCode() string {
+	if x != nil {
+		return x.CountryCode
+	}
+	return ""
+}
+
+func (x *PostcodeRules) GetAllowedProvinces() []string {
+	if x != nil {
+		return x.AllowedProvinces
+	}
+	return nil
+}
+
+func (x *PostcodeRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 用户注册验证规则
+type UserRegistrationRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 用户名规则
+	Username *StringRules `protobuf:"bytes,1,opt,name=username,proto3" json:"username"`
+	// 手机号规则
+	Mobile *ChineseMobileRules `protobuf:"bytes,2,opt,name=mobile,proto3" json:"mobile"`
+	// 邮箱规则
+	Email *StringRules `protobuf:"bytes,3,opt,name=email,proto3" json:"email"`
+	// 密码规则
+	Password *PasswordRules `protobuf:"bytes,4,opt,name=password,proto3" json:"password"`
+	// 真实姓名规则(可选)
+	RealName *ChineseNameRules `protobuf:"bytes,5,opt,name=real_name,json=realName,proto3" json:"real_name"`
+	// 身份证规则(可选)
+	IdCard        *ChineseIdCardRules `protobuf:"bytes,6,opt,name=id_card,json=idCard,proto3" json:"id_card"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *UserRegistrationRules) Reset() {
+	*x = UserRegistrationRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *UserRegistrationRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UserRegistrationRules) ProtoMessage() {}
+
+func (x *UserRegistrationRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UserRegistrationRules.ProtoReflect.Descriptor instead.
+func (*UserRegistrationRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *UserRegistrationRules) GetUsername() *StringRules {
+	if x != nil {
+		return x.Username
+	}
+	return nil
+}
+
+func (x *UserRegistrationRules) GetMobile() *ChineseMobileRules {
+	if x != nil {
+		return x.Mobile
+	}
+	return nil
+}
+
+func (x *UserRegistrationRules) GetEmail() *StringRules {
+	if x != nil {
+		return x.Email
+	}
+	return nil
+}
+
+func (x *UserRegistrationRules) GetPassword() *PasswordRules {
+	if x != nil {
+		return x.Password
+	}
+	return nil
+}
+
+func (x *UserRegistrationRules) GetRealName() *ChineseNameRules {
+	if x != nil {
+		return x.RealName
+	}
+	return nil
+}
+
+func (x *UserRegistrationRules) GetIdCard() *ChineseIdCardRules {
+	if x != nil {
+		return x.IdCard
+	}
+	return nil
+}
+
+// 密码强度验证规则
+type PasswordRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 最小长度
+	MinLength uint32 `protobuf:"varint,1,opt,name=min_length,json=minLength,proto3" json:"min_length"`
+	// 最大长度
+	MaxLength uint32 `protobuf:"varint,2,opt,name=max_length,json=maxLength,proto3" json:"max_length"`
+	// 是否要求包含大写字母
+	RequireUppercase bool `protobuf:"varint,3,opt,name=require_uppercase,json=requireUppercase,proto3" json:"require_uppercase"`
+	// 是否要求包含小写字母
+	RequireLowercase bool `protobuf:"varint,4,opt,name=require_lowercase,json=requireLowercase,proto3" json:"require_lowercase"`
+	// 是否要求包含数字
+	RequireDigit bool `protobuf:"varint,5,opt,name=require_digit,json=requireDigit,proto3" json:"require_digit"`
+	// 是否要求包含特殊字符
+	RequireSpecial bool `protobuf:"varint,6,opt,name=require_special,json=requireSpecial,proto3" json:"require_special"`
+	// 特殊字符集合(默认: !@#$%^&*()_+-=[]{}|;:,.<>?)
+	SpecialChars string `protobuf:"bytes,7,opt,name=special_chars,json=specialChars,proto3" json:"special_chars"`
+	// 是否禁止常见弱密码
+	RejectCommonWeak bool `protobuf:"varint,8,opt,name=reject_common_weak,json=rejectCommonWeak,proto3" json:"reject_common_weak"`
+	// 自定义错误消息
+	ErrorMessage  string `protobuf:"bytes,9,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *PasswordRules) Reset() {
+	*x = PasswordRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *PasswordRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PasswordRules) ProtoMessage() {}
+
+func (x *PasswordRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PasswordRules.ProtoReflect.Descriptor instead.
+func (*PasswordRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *PasswordRules) GetMinLength() uint32 {
+	if x != nil {
+		return x.MinLength
+	}
+	return 0
+}
+
+func (x *PasswordRules) GetMaxLength() uint32 {
+	if x != nil {
+		return x.MaxLength
+	}
+	return 0
+}
+
+func (x *PasswordRules) GetRequireUppercase() bool {
+	if x != nil {
+		return x.RequireUppercase
+	}
+	return false
+}
+
+func (x *PasswordRules) GetRequireLowercase() bool {
+	if x != nil {
+		return x.RequireLowercase
+	}
+	return false
+}
+
+func (x *PasswordRules) GetRequireDigit() bool {
+	if x != nil {
+		return x.RequireDigit
+	}
+	return false
+}
+
+func (x *PasswordRules) GetRequireSpecial() bool {
+	if x != nil {
+		return x.RequireSpecial
+	}
+	return false
+}
+
+func (x *PasswordRules) GetSpecialChars() string {
+	if x != nil {
+		return x.SpecialChars
+	}
+	return ""
+}
+
+func (x *PasswordRules) GetRejectCommonWeak() bool {
+	if x != nil {
+		return x.RejectCommonWeak
+	}
+	return false
+}
+
+func (x *PasswordRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+// 企业信息验证规则
+type EnterpriseInfoRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 企业名称规则
+	CompanyName *StringRules `protobuf:"bytes,1,opt,name=company_name,json=companyName,proto3" json:"company_name"`
+	// 统一社会信用代码规则
+	Uscc *UnifiedSocialCreditCodeRules `protobuf:"bytes,2,opt,name=uscc,proto3" json:"uscc"`
+	// 法人姓名规则
+	LegalPersonName *ChineseNameRules `protobuf:"bytes,3,opt,name=legal_person_name,json=legalPersonName,proto3" json:"legal_person_name"`
+	// 注册资本范围
+	MinRegisteredCapital *int64 `protobuf:"varint,4,opt,name=min_registered_capital,json=minRegisteredCapital,proto3,oneof" json:"min_registered_capital"`
+	MaxRegisteredCapital *int64 `protobuf:"varint,5,opt,name=max_registered_capital,json=maxRegisteredCapital,proto3,oneof" json:"max_registered_capital"`
+	// 营业执照号码(旧格式)
+	BusinessLicense *StringRules `protobuf:"bytes,6,opt,name=business_license,json=businessLicense,proto3" json:"business_license"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *EnterpriseInfoRules) Reset() {
+	*x = EnterpriseInfoRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *EnterpriseInfoRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EnterpriseInfoRules) ProtoMessage() {}
+
+func (x *EnterpriseInfoRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EnterpriseInfoRules.ProtoReflect.Descriptor instead.
+func (*EnterpriseInfoRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *EnterpriseInfoRules) GetCompanyName() *StringRules {
+	if x != nil {
+		return x.CompanyName
+	}
+	return nil
+}
+
+func (x *EnterpriseInfoRules) GetUscc() *UnifiedSocialCreditCodeRules {
+	if x != nil {
+		return x.Uscc
+	}
+	return nil
+}
+
+func (x *EnterpriseInfoRules) GetLegalPersonName() *ChineseNameRules {
+	if x != nil {
+		return x.LegalPersonName
+	}
+	return nil
+}
+
+func (x *EnterpriseInfoRules) GetMinRegisteredCapital() int64 {
+	if x != nil && x.MinRegisteredCapital != nil {
+		return *x.MinRegisteredCapital
+	}
+	return 0
+}
+
+func (x *EnterpriseInfoRules) GetMaxRegisteredCapital() int64 {
+	if x != nil && x.MaxRegisteredCapital != nil {
+		return *x.MaxRegisteredCapital
+	}
+	return 0
+}
+
+func (x *EnterpriseInfoRules) GetBusinessLicense() *StringRules {
+	if x != nil {
+		return x.BusinessLicense
+	}
+	return nil
+}
+
+// 地址验证规则
+type AddressRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 省份
+	Province *StringRules `protobuf:"bytes,1,opt,name=province,proto3" json:"province"`
+	// 城市
+	City *StringRules `protobuf:"bytes,2,opt,name=city,proto3" json:"city"`
+	// 区县
+	District *StringRules `protobuf:"bytes,3,opt,name=district,proto3" json:"district"`
+	// 详细地址
+	Detail *StringRules `protobuf:"bytes,4,opt,name=detail,proto3" json:"detail"`
+	// 邮政编码
+	Postcode *PostcodeRules `protobuf:"bytes,5,opt,name=postcode,proto3" json:"postcode"`
+	// 是否要求完整地址
+	RequireComplete bool `protobuf:"varint,6,opt,name=require_complete,json=requireComplete,proto3" json:"require_complete"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *AddressRules) Reset() {
+	*x = AddressRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AddressRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddressRules) ProtoMessage() {}
+
+func (x *AddressRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddressRules.ProtoReflect.Descriptor instead.
+func (*AddressRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *AddressRules) GetProvince() *StringRules {
+	if x != nil {
+		return x.Province
+	}
+	return nil
+}
+
+func (x *AddressRules) GetCity() *StringRules {
+	if x != nil {
+		return x.City
+	}
+	return nil
+}
+
+func (x *AddressRules) GetDistrict() *StringRules {
+	if x != nil {
+		return x.District
+	}
+	return nil
+}
+
+func (x *AddressRules) GetDetail() *StringRules {
+	if x != nil {
+		return x.Detail
+	}
+	return nil
+}
+
+func (x *AddressRules) GetPostcode() *PostcodeRules {
+	if x != nil {
+		return x.Postcode
+	}
+	return nil
+}
+
+func (x *AddressRules) GetRequireComplete() bool {
+	if x != nil {
+		return x.RequireComplete
+	}
+	return false
+}
+
+// 金融交易验证规则
+type FinancialTransactionRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 交易金额范围
+	MinAmount *float64 `protobuf:"fixed64,1,opt,name=min_amount,json=minAmount,proto3,oneof" json:"min_amount"`
+	MaxAmount *float64 `protobuf:"fixed64,2,opt,name=max_amount,json=maxAmount,proto3,oneof" json:"max_amount"`
+	// 银行卡号验证
+	BankCard *BankCardRules `protobuf:"bytes,3,opt,name=bank_card,json=bankCard,proto3" json:"bank_card"`
+	// 交易密码规则
+	TransactionPassword *PasswordRules `protobuf:"bytes,4,opt,name=transaction_password,json=transactionPassword,proto3" json:"transaction_password"`
+	// 是否要求二次确认
+	RequireConfirmation bool `protobuf:"varint,5,opt,name=require_confirmation,json=requireConfirmation,proto3" json:"require_confirmation"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *FinancialTransactionRules) Reset() {
+	*x = FinancialTransactionRules{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *FinancialTransactionRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FinancialTransactionRules) ProtoMessage() {}
+
+func (x *FinancialTransactionRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FinancialTransactionRules.ProtoReflect.Descriptor instead.
+func (*FinancialTransactionRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *FinancialTransactionRules) GetMinAmount() float64 {
+	if x != nil && x.MinAmount != nil {
+		return *x.MinAmount
+	}
+	return 0
+}
+
+func (x *FinancialTransactionRules) GetMaxAmount() float64 {
+	if x != nil && x.MaxAmount != nil {
+		return *x.MaxAmount
+	}
+	return 0
+}
+
+func (x *FinancialTransactionRules) GetBankCard() *BankCardRules {
+	if x != nil {
+		return x.BankCard
+	}
+	return nil
+}
+
+func (x *FinancialTransactionRules) GetTransactionPassword() *PasswordRules {
+	if x != nil {
+		return x.TransactionPassword
+	}
+	return nil
+}
+
+func (x *FinancialTransactionRules) GetRequireConfirmation() bool {
+	if x != nil {
+		return x.RequireConfirmation
+	}
+	return false
+}
+
+// 验证错误详情
+type ValidationError struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 字段路径
+	FieldPath string `protobuf:"bytes,1,opt,name=field_path,json=fieldPath,proto3" json:"field_path"`
+	// 规则 ID
+	RuleId string `protobuf:"bytes,2,opt,name=rule_id,json=ruleId,proto3" json:"rule_id"`
+	// 错误消息(中文)
+	Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message"`
+	// 错误消息(英文)
+	MessageEn string `protobuf:"bytes,4,opt,name=message_en,json=messageEn,proto3" json:"message_en"`
+	// 失败的值
+	Value string `protobuf:"bytes,5,opt,name=value,proto3" json:"value"`
+	// 附加信息
+	Metadata      map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ValidationError) Reset() {
+	*x = ValidationError{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidationError) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidationError) ProtoMessage() {}
+
+func (x *ValidationError) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidationError.ProtoReflect.Descriptor instead.
+func (*ValidationError) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *ValidationError) GetFieldPath() string {
+	if x != nil {
+		return x.FieldPath
+	}
+	return ""
+}
+
+func (x *ValidationError) GetRuleId() string {
+	if x != nil {
+		return x.RuleId
+	}
+	return ""
+}
+
+func (x *ValidationError) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *ValidationError) GetMessageEn() string {
+	if x != nil {
+		return x.MessageEn
+	}
+	return ""
+}
+
+func (x *ValidationError) GetValue() string {
+	if x != nil {
+		return x.Value
+	}
+	return ""
+}
+
+func (x *ValidationError) GetMetadata() map[string]string {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+// 批量验证结果
+type ValidationResult struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否验证通过
+	Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid"`
+	// 错误列表
+	Errors []*ValidationError `protobuf:"bytes,2,rep,name=errors,proto3" json:"errors"`
+	// 警告列表(非阻塞性)
+	Warnings []*ValidationError `protobuf:"bytes,3,rep,name=warnings,proto3" json:"warnings"`
+	// 验证组
+	Group         string `protobuf:"bytes,4,opt,name=group,proto3" json:"group"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ValidationResult) Reset() {
+	*x = ValidationResult{}
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidationResult) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidationResult) ProtoMessage() {}
+
+func (x *ValidationResult) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_business_rules_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidationResult.ProtoReflect.Descriptor instead.
+func (*ValidationResult) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_business_rules_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *ValidationResult) GetValid() bool {
+	if x != nil {
+		return x.Valid
+	}
+	return false
+}
+
+func (x *ValidationResult) GetErrors() []*ValidationError {
+	if x != nil {
+		return x.Errors
+	}
+	return nil
+}
+
+func (x *ValidationResult) GetWarnings() []*ValidationError {
+	if x != nil {
+		return x.Warnings
+	}
+	return nil
+}
+
+func (x *ValidationResult) GetGroup() string {
+	if x != nil {
+		return x.Group
+	}
+	return ""
+}
+
+var File_kuban_api_validate_business_rules_proto protoreflect.FileDescriptor
+
+const file_kuban_api_validate_business_rules_proto_rawDesc = "" +
+	"\n" +
+	"'kuban/api/validate/business_rules.proto\x12\x12kuban.api.validate\x1a google/protobuf/descriptor.proto\x1a!kuban/api/validate/validate.proto\"\xc9\x01\n" +
+	"\x12ChineseMobileRules\x12\x18\n" +
+	"\aenabled\x18\x01 \x01(\bR\aenabled\x12O\n" +
+	"\x11allowed_operators\x18\x02 \x03(\x0e2\".kuban.api.validate.MobileOperatorR\x10allowedOperators\x12#\n" +
+	"\rallow_virtual\x18\x03 \x01(\bR\fallowVirtual\x12#\n" +
+	"\rerror_message\x18\x04 \x01(\tR\ferrorMessage\"\xc9\x03\n" +
+	"\x12ChineseIdCardRules\x12\x18\n" +
+	"\aenabled\x18\x01 \x01(\bR\aenabled\x12'\n" +
+	"\x0fverify_checksum\x18\x02 \x01(\bR\x0everifyChecksum\x12*\n" +
+	"\x11verify_birth_date\x18\x03 \x01(\bR\x0fverifyBirthDate\x12(\n" +
+	"\x10verify_area_code\x18\x04 \x01(\bR\x0everifyAreaCode\x12C\n" +
+	"\rallowed_types\x18\x05 \x03(\x0e2\x1e.kuban.api.validate.IdCardTypeR\fallowedTypes\x12\x1c\n" +
+	"\amin_age\x18\x06 \x01(\x05H\x00R\x06minAge\x88\x01\x01\x12\x1c\n" +
+	"\amax_age\x18\a \x01(\x05H\x01R\x06maxAge\x88\x01\x01\x12H\n" +
+	"\x0frequired_gender\x18\b \x01(\x0e2\x1a.kuban.api.validate.GenderH\x02R\x0erequiredGender\x88\x01\x01\x12#\n" +
+	"\rerror_message\x18\t \x01(\tR\ferrorMessageB\n" +
+	"\n" +
+	"\b_min_ageB\n" +
+	"\n" +
+	"\b_max_ageB\x12\n" +
+	"\x10_required_gender\"\xd1\x01\n" +
+	"\x1cUnifiedSocialCreditCodeRules\x12\x18\n" +
+	"\aenabled\x18\x01 \x01(\bR\aenabled\x12'\n" +
+	"\x0fverify_checksum\x18\x02 \x01(\bR\x0everifyChecksum\x12I\n" +
+	"\rallowed_types\x18\x03 \x03(\x0e2$.kuban.api.validate.OrganizationTypeR\fallowedTypes\x12#\n" +
+	"\rerror_message\x18\x04 \x01(\tR\ferrorMessage\"\xdb\x01\n" +
+	"\rBankCardRules\x12\x18\n" +
+	"\aenabled\x18\x01 \x01(\bR\aenabled\x12\x1f\n" +
+	"\vverify_luhn\x18\x02 \x01(\bR\n" +
+	"verifyLuhn\x12E\n" +
+	"\rallowed_types\x18\x03 \x03(\x0e2 .kuban.api.validate.BankCardTypeR\fallowedTypes\x12#\n" +
+	"\rallowed_banks\x18\x04 \x03(\tR\fallowedBanks\x12#\n" +
+	"\rerror_message\x18\x05 \x01(\tR\ferrorMessage\"\x90\x02\n" +
+	"\x10ChineseNameRules\x12\x18\n" +
+	"\aenabled\x18\x01 \x01(\bR\aenabled\x12\"\n" +
+	"\n" +
+	"min_length\x18\x02 \x01(\rH\x00R\tminLength\x88\x01\x01\x12\"\n" +
+	"\n" +
+	"max_length\x18\x03 \x01(\rH\x01R\tmaxLength\x88\x01\x01\x122\n" +
+	"\x15allow_ethnic_minority\x18\x04 \x01(\bR\x13allowEthnicMinority\x12#\n" +
+	"\rallow_english\x18\x05 \x01(\bR\fallowEnglish\x12#\n" +
+	"\rerror_message\x18\x06 \x01(\tR\ferrorMessageB\r\n" +
+	"\v_min_lengthB\r\n" +
+	"\v_max_length\"\x9e\x01\n" +
+	"\rPostcodeRules\x12\x18\n" +
+	"\aenabled\x18\x01 \x01(\bR\aenabled\x12!\n" +
+	"\fcountry_code\x18\x02 \x01(\tR\vcountryCode\x12+\n" +
+	"\x11allowed_provinces\x18\x03 \x03(\tR\x10allowedProvinces\x12#\n" +
+	"\rerror_message\x18\x04 \x01(\tR\ferrorMessage\"\x8e\x03\n" +
+	"\x15UserRegistrationRules\x12;\n" +
+	"\busername\x18\x01 \x01(\v2\x1f.kuban.api.validate.StringRulesR\busername\x12>\n" +
+	"\x06mobile\x18\x02 \x01(\v2&.kuban.api.validate.ChineseMobileRulesR\x06mobile\x125\n" +
+	"\x05email\x18\x03 \x01(\v2\x1f.kuban.api.validate.StringRulesR\x05email\x12=\n" +
+	"\bpassword\x18\x04 \x01(\v2!.kuban.api.validate.PasswordRulesR\bpassword\x12A\n" +
+	"\treal_name\x18\x05 \x01(\v2$.kuban.api.validate.ChineseNameRulesR\brealName\x12?\n" +
+	"\aid_card\x18\x06 \x01(\v2&.kuban.api.validate.ChineseIdCardRulesR\x06idCard\"\xed\x02\n" +
+	"\rPasswordRules\x12\x1d\n" +
+	"\n" +
+	"min_length\x18\x01 \x01(\rR\tminLength\x12\x1d\n" +
+	"\n" +
+	"max_length\x18\x02 \x01(\rR\tmaxLength\x12+\n" +
+	"\x11require_uppercase\x18\x03 \x01(\bR\x10requireUppercase\x12+\n" +
+	"\x11require_lowercase\x18\x04 \x01(\bR\x10requireLowercase\x12#\n" +
+	"\rrequire_digit\x18\x05 \x01(\bR\frequireDigit\x12'\n" +
+	"\x0frequire_special\x18\x06 \x01(\bR\x0erequireSpecial\x12#\n" +
+	"\rspecial_chars\x18\a \x01(\tR\fspecialChars\x12,\n" +
+	"\x12reject_common_weak\x18\b \x01(\bR\x10rejectCommonWeak\x12#\n" +
+	"\rerror_message\x18\t \x01(\tR\ferrorMessage\"\xe9\x03\n" +
+	"\x13EnterpriseInfoRules\x12B\n" +
+	"\fcompany_name\x18\x01 \x01(\v2\x1f.kuban.api.validate.StringRulesR\vcompanyName\x12D\n" +
+	"\x04uscc\x18\x02 \x01(\v20.kuban.api.validate.UnifiedSocialCreditCodeRulesR\x04uscc\x12P\n" +
+	"\x11legal_person_name\x18\x03 \x01(\v2$.kuban.api.validate.ChineseNameRulesR\x0flegalPersonName\x129\n" +
+	"\x16min_registered_capital\x18\x04 \x01(\x03H\x00R\x14minRegisteredCapital\x88\x01\x01\x129\n" +
+	"\x16max_registered_capital\x18\x05 \x01(\x03H\x01R\x14maxRegisteredCapital\x88\x01\x01\x12J\n" +
+	"\x10business_license\x18\x06 \x01(\v2\x1f.kuban.api.validate.StringRulesR\x0fbusinessLicenseB\x19\n" +
+	"\x17_min_registered_capitalB\x19\n" +
+	"\x17_max_registered_capital\"\xe0\x02\n" +
+	"\fAddressRules\x12;\n" +
+	"\bprovince\x18\x01 \x01(\v2\x1f.kuban.api.validate.StringRulesR\bprovince\x123\n" +
+	"\x04city\x18\x02 \x01(\v2\x1f.kuban.api.validate.StringRulesR\x04city\x12;\n" +
+	"\bdistrict\x18\x03 \x01(\v2\x1f.kuban.api.validate.StringRulesR\bdistrict\x127\n" +
+	"\x06detail\x18\x04 \x01(\v2\x1f.kuban.api.validate.StringRulesR\x06detail\x12=\n" +
+	"\bpostcode\x18\x05 \x01(\v2!.kuban.api.validate.PostcodeRulesR\bpostcode\x12)\n" +
+	"\x10require_complete\x18\x06 \x01(\bR\x0frequireComplete\"\xca\x02\n" +
+	"\x19FinancialTransactionRules\x12\"\n" +
+	"\n" +
+	"min_amount\x18\x01 \x01(\x01H\x00R\tminAmount\x88\x01\x01\x12\"\n" +
+	"\n" +
+	"max_amount\x18\x02 \x01(\x01H\x01R\tmaxAmount\x88\x01\x01\x12>\n" +
+	"\tbank_card\x18\x03 \x01(\v2!.kuban.api.validate.BankCardRulesR\bbankCard\x12T\n" +
+	"\x14transaction_password\x18\x04 \x01(\v2!.kuban.api.validate.PasswordRulesR\x13transactionPassword\x121\n" +
+	"\x14require_confirmation\x18\x05 \x01(\bR\x13requireConfirmationB\r\n" +
+	"\v_min_amountB\r\n" +
+	"\v_max_amount\"\xa4\x02\n" +
+	"\x0fValidationError\x12\x1d\n" +
+	"\n" +
+	"field_path\x18\x01 \x01(\tR\tfieldPath\x12\x17\n" +
+	"\arule_id\x18\x02 \x01(\tR\x06ruleId\x12\x18\n" +
+	"\amessage\x18\x03 \x01(\tR\amessage\x12\x1d\n" +
+	"\n" +
+	"message_en\x18\x04 \x01(\tR\tmessageEn\x12\x14\n" +
+	"\x05value\x18\x05 \x01(\tR\x05value\x12M\n" +
+	"\bmetadata\x18\x06 \x03(\v21.kuban.api.validate.ValidationError.MetadataEntryR\bmetadata\x1a;\n" +
+	"\rMetadataEntry\x12\x10\n" +
+	"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+	"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xbc\x01\n" +
+	"\x10ValidationResult\x12\x14\n" +
+	"\x05valid\x18\x01 \x01(\bR\x05valid\x12;\n" +
+	"\x06errors\x18\x02 \x03(\v2#.kuban.api.validate.ValidationErrorR\x06errors\x12?\n" +
+	"\bwarnings\x18\x03 \x03(\v2#.kuban.api.validate.ValidationErrorR\bwarnings\x12\x14\n" +
+	"\x05group\x18\x04 \x01(\tR\x05group*\xbc\x01\n" +
+	"\x0eMobileOperator\x12\x1f\n" +
+	"\x1bMOBILE_OPERATOR_UNSPECIFIED\x10\x00\x12 \n" +
+	"\x1cMOBILE_OPERATOR_CHINA_MOBILE\x10\x01\x12 \n" +
+	"\x1cMOBILE_OPERATOR_CHINA_UNICOM\x10\x02\x12!\n" +
+	"\x1dMOBILE_OPERATOR_CHINA_TELECOM\x10\x03\x12\"\n" +
+	"\x1eMOBILE_OPERATOR_CHINA_BROADNET\x10\x04*`\n" +
+	"\n" +
+	"IdCardType\x12\x1c\n" +
+	"\x18ID_CARD_TYPE_UNSPECIFIED\x10\x00\x12\x19\n" +
+	"\x15ID_CARD_TYPE_18_DIGIT\x10\x01\x12\x19\n" +
+	"\x15ID_CARD_TYPE_15_DIGIT\x10\x02*D\n" +
+	"\x06Gender\x12\x16\n" +
+	"\x12GENDER_UNSPECIFIED\x10\x00\x12\x0f\n" +
+	"\vGENDER_MALE\x10\x01\x12\x11\n" +
+	"\rGENDER_FEMALE\x10\x02*\xc0\x01\n" +
+	"\x10OrganizationType\x12!\n" +
+	"\x1dORGANIZATION_TYPE_UNSPECIFIED\x10\x00\x12 \n" +
+	"\x1cORGANIZATION_TYPE_ENTERPRISE\x10\x01\x12!\n" +
+	"\x1dORGANIZATION_TYPE_INSTITUTION\x10\x02\x12\"\n" +
+	"\x1eORGANIZATION_TYPE_SOCIAL_GROUP\x10\x03\x12 \n" +
+	"\x1cORGANIZATION_TYPE_GOVERNMENT\x10\t*c\n" +
+	"\fBankCardType\x12\x1e\n" +
+	"\x1aBANK_CARD_TYPE_UNSPECIFIED\x10\x00\x12\x18\n" +
+	"\x14BANK_CARD_TYPE_DEBIT\x10\x01\x12\x19\n" +
+	"\x15BANK_CARD_TYPE_CREDIT\x10\x02B=Z;git.ikuban.com/server/kubanapis/kuban/api/validate;validateb\x06proto3"
+
+var (
+	file_kuban_api_validate_business_rules_proto_rawDescOnce sync.Once
+	file_kuban_api_validate_business_rules_proto_rawDescData []byte
+)
+
+func file_kuban_api_validate_business_rules_proto_rawDescGZIP() []byte {
+	file_kuban_api_validate_business_rules_proto_rawDescOnce.Do(func() {
+		file_kuban_api_validate_business_rules_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_kuban_api_validate_business_rules_proto_rawDesc), len(file_kuban_api_validate_business_rules_proto_rawDesc)))
+	})
+	return file_kuban_api_validate_business_rules_proto_rawDescData
+}
+
+var file_kuban_api_validate_business_rules_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
+var file_kuban_api_validate_business_rules_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
+var file_kuban_api_validate_business_rules_proto_goTypes = []any{
+	(MobileOperator)(0),                  // 0: kuban.api.validate.MobileOperator
+	(IdCardType)(0),                      // 1: kuban.api.validate.IdCardType
+	(Gender)(0),                          // 2: kuban.api.validate.Gender
+	(OrganizationType)(0),                // 3: kuban.api.validate.OrganizationType
+	(BankCardType)(0),                    // 4: kuban.api.validate.BankCardType
+	(*ChineseMobileRules)(nil),           // 5: kuban.api.validate.ChineseMobileRules
+	(*ChineseIdCardRules)(nil),           // 6: kuban.api.validate.ChineseIdCardRules
+	(*UnifiedSocialCreditCodeRules)(nil), // 7: kuban.api.validate.UnifiedSocialCreditCodeRules
+	(*BankCardRules)(nil),                // 8: kuban.api.validate.BankCardRules
+	(*ChineseNameRules)(nil),             // 9: kuban.api.validate.ChineseNameRules
+	(*PostcodeRules)(nil),                // 10: kuban.api.validate.PostcodeRules
+	(*UserRegistrationRules)(nil),        // 11: kuban.api.validate.UserRegistrationRules
+	(*PasswordRules)(nil),                // 12: kuban.api.validate.PasswordRules
+	(*EnterpriseInfoRules)(nil),          // 13: kuban.api.validate.EnterpriseInfoRules
+	(*AddressRules)(nil),                 // 14: kuban.api.validate.AddressRules
+	(*FinancialTransactionRules)(nil),    // 15: kuban.api.validate.FinancialTransactionRules
+	(*ValidationError)(nil),              // 16: kuban.api.validate.ValidationError
+	(*ValidationResult)(nil),             // 17: kuban.api.validate.ValidationResult
+	nil,                                  // 18: kuban.api.validate.ValidationError.MetadataEntry
+	(*StringRules)(nil),                  // 19: kuban.api.validate.StringRules
+}
+var file_kuban_api_validate_business_rules_proto_depIdxs = []int32{
+	0,  // 0: kuban.api.validate.ChineseMobileRules.allowed_operators:type_name -> kuban.api.validate.MobileOperator
+	1,  // 1: kuban.api.validate.ChineseIdCardRules.allowed_types:type_name -> kuban.api.validate.IdCardType
+	2,  // 2: kuban.api.validate.ChineseIdCardRules.required_gender:type_name -> kuban.api.validate.Gender
+	3,  // 3: kuban.api.validate.UnifiedSocialCreditCodeRules.allowed_types:type_name -> kuban.api.validate.OrganizationType
+	4,  // 4: kuban.api.validate.BankCardRules.allowed_types:type_name -> kuban.api.validate.BankCardType
+	19, // 5: kuban.api.validate.UserRegistrationRules.username:type_name -> kuban.api.validate.StringRules
+	5,  // 6: kuban.api.validate.UserRegistrationRules.mobile:type_name -> kuban.api.validate.ChineseMobileRules
+	19, // 7: kuban.api.validate.UserRegistrationRules.email:type_name -> kuban.api.validate.StringRules
+	12, // 8: kuban.api.validate.UserRegistrationRules.password:type_name -> kuban.api.validate.PasswordRules
+	9,  // 9: kuban.api.validate.UserRegistrationRules.real_name:type_name -> kuban.api.validate.ChineseNameRules
+	6,  // 10: kuban.api.validate.UserRegistrationRules.id_card:type_name -> kuban.api.validate.ChineseIdCardRules
+	19, // 11: kuban.api.validate.EnterpriseInfoRules.company_name:type_name -> kuban.api.validate.StringRules
+	7,  // 12: kuban.api.validate.EnterpriseInfoRules.uscc:type_name -> kuban.api.validate.UnifiedSocialCreditCodeRules
+	9,  // 13: kuban.api.validate.EnterpriseInfoRules.legal_person_name:type_name -> kuban.api.validate.ChineseNameRules
+	19, // 14: kuban.api.validate.EnterpriseInfoRules.business_license:type_name -> kuban.api.validate.StringRules
+	19, // 15: kuban.api.validate.AddressRules.province:type_name -> kuban.api.validate.StringRules
+	19, // 16: kuban.api.validate.AddressRules.city:type_name -> kuban.api.validate.StringRules
+	19, // 17: kuban.api.validate.AddressRules.district:type_name -> kuban.api.validate.StringRules
+	19, // 18: kuban.api.validate.AddressRules.detail:type_name -> kuban.api.validate.StringRules
+	10, // 19: kuban.api.validate.AddressRules.postcode:type_name -> kuban.api.validate.PostcodeRules
+	8,  // 20: kuban.api.validate.FinancialTransactionRules.bank_card:type_name -> kuban.api.validate.BankCardRules
+	12, // 21: kuban.api.validate.FinancialTransactionRules.transaction_password:type_name -> kuban.api.validate.PasswordRules
+	18, // 22: kuban.api.validate.ValidationError.metadata:type_name -> kuban.api.validate.ValidationError.MetadataEntry
+	16, // 23: kuban.api.validate.ValidationResult.errors:type_name -> kuban.api.validate.ValidationError
+	16, // 24: kuban.api.validate.ValidationResult.warnings:type_name -> kuban.api.validate.ValidationError
+	25, // [25:25] is the sub-list for method output_type
+	25, // [25:25] is the sub-list for method input_type
+	25, // [25:25] is the sub-list for extension type_name
+	25, // [25:25] is the sub-list for extension extendee
+	0,  // [0:25] is the sub-list for field type_name
+}
+
+func init() { file_kuban_api_validate_business_rules_proto_init() }
+func file_kuban_api_validate_business_rules_proto_init() {
+	if File_kuban_api_validate_business_rules_proto != nil {
+		return
+	}
+	file_kuban_api_validate_validate_proto_init()
+	file_kuban_api_validate_business_rules_proto_msgTypes[1].OneofWrappers = []any{}
+	file_kuban_api_validate_business_rules_proto_msgTypes[4].OneofWrappers = []any{}
+	file_kuban_api_validate_business_rules_proto_msgTypes[8].OneofWrappers = []any{}
+	file_kuban_api_validate_business_rules_proto_msgTypes[10].OneofWrappers = []any{}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_kuban_api_validate_business_rules_proto_rawDesc), len(file_kuban_api_validate_business_rules_proto_rawDesc)),
+			NumEnums:      5,
+			NumMessages:   14,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_kuban_api_validate_business_rules_proto_goTypes,
+		DependencyIndexes: file_kuban_api_validate_business_rules_proto_depIdxs,
+		EnumInfos:         file_kuban_api_validate_business_rules_proto_enumTypes,
+		MessageInfos:      file_kuban_api_validate_business_rules_proto_msgTypes,
+	}.Build()
+	File_kuban_api_validate_business_rules_proto = out.File
+	file_kuban_api_validate_business_rules_proto_goTypes = nil
+	file_kuban_api_validate_business_rules_proto_depIdxs = nil
+}

+ 1466 - 0
kuban/api/validate/rule_groups.pb.go

@@ -0,0 +1,1466 @@
+// Copyright 2025 Kuban Technologies
+//
+// 规则分组管理 - 支持场景化验证
+// 允许在不同业务场景下应用不同的验证规则集
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.6-modify
+// 	protoc        v6.31.1
+// source: kuban/api/validate/rule_groups.proto
+
+package validate
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	_ "google.golang.org/protobuf/types/descriptorpb"
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// 常用验证组定义
+type CommonValidationGroup int32
+
+const (
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_UNSPECIFIED CommonValidationGroup = 0
+	// CRUD 操作组
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_CREATE CommonValidationGroup = 1 // 创建场景
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_UPDATE CommonValidationGroup = 2 // 更新场景
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_PATCH  CommonValidationGroup = 3 // 部分更新场景
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_DELETE CommonValidationGroup = 4 // 删除场景
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_QUERY  CommonValidationGroup = 5 // 查询场景
+	// 严格程度组
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_STRICT CommonValidationGroup = 10 // 严格模式
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_NORMAL CommonValidationGroup = 11 // 标准模式
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_LOOSE  CommonValidationGroup = 12 // 宽松模式
+	// 用户场景组
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_REGISTER        CommonValidationGroup = 20 // 用户注册
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_LOGIN           CommonValidationGroup = 21 // 用户登录
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_PROFILE         CommonValidationGroup = 22 // 个人资料
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_CHANGE_PASSWORD CommonValidationGroup = 23 // 修改密码
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_RESET_PASSWORD  CommonValidationGroup = 24 // 重置密码
+	// 审核场景组
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_DRAFT   CommonValidationGroup = 30 // 草稿
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_SUBMIT  CommonValidationGroup = 31 // 提交审核
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_APPROVE CommonValidationGroup = 32 // 审核通过
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_REJECT  CommonValidationGroup = 33 // 审核拒绝
+	// 实名认证场景
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_REAL_NAME_AUTH    CommonValidationGroup = 40 // 实名认证
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_ENTERPRISE_AUTH   CommonValidationGroup = 41 // 企业认证
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_BANK_CARD_BINDING CommonValidationGroup = 42 // 银行卡绑定
+	// 安全场景组
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_SENSITIVE_OP CommonValidationGroup = 50 // 敏感操作
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_FINANCIAL    CommonValidationGroup = 51 // 金融交易
+	CommonValidationGroup_COMMON_VALIDATION_GROUP_ADMIN        CommonValidationGroup = 52 // 管理员操作
+)
+
+// Enum value maps for CommonValidationGroup.
+var (
+	CommonValidationGroup_name = map[int32]string{
+		0:  "COMMON_VALIDATION_GROUP_UNSPECIFIED",
+		1:  "COMMON_VALIDATION_GROUP_CREATE",
+		2:  "COMMON_VALIDATION_GROUP_UPDATE",
+		3:  "COMMON_VALIDATION_GROUP_PATCH",
+		4:  "COMMON_VALIDATION_GROUP_DELETE",
+		5:  "COMMON_VALIDATION_GROUP_QUERY",
+		10: "COMMON_VALIDATION_GROUP_STRICT",
+		11: "COMMON_VALIDATION_GROUP_NORMAL",
+		12: "COMMON_VALIDATION_GROUP_LOOSE",
+		20: "COMMON_VALIDATION_GROUP_REGISTER",
+		21: "COMMON_VALIDATION_GROUP_LOGIN",
+		22: "COMMON_VALIDATION_GROUP_PROFILE",
+		23: "COMMON_VALIDATION_GROUP_CHANGE_PASSWORD",
+		24: "COMMON_VALIDATION_GROUP_RESET_PASSWORD",
+		30: "COMMON_VALIDATION_GROUP_DRAFT",
+		31: "COMMON_VALIDATION_GROUP_SUBMIT",
+		32: "COMMON_VALIDATION_GROUP_APPROVE",
+		33: "COMMON_VALIDATION_GROUP_REJECT",
+		40: "COMMON_VALIDATION_GROUP_REAL_NAME_AUTH",
+		41: "COMMON_VALIDATION_GROUP_ENTERPRISE_AUTH",
+		42: "COMMON_VALIDATION_GROUP_BANK_CARD_BINDING",
+		50: "COMMON_VALIDATION_GROUP_SENSITIVE_OP",
+		51: "COMMON_VALIDATION_GROUP_FINANCIAL",
+		52: "COMMON_VALIDATION_GROUP_ADMIN",
+	}
+	CommonValidationGroup_value = map[string]int32{
+		"COMMON_VALIDATION_GROUP_UNSPECIFIED":       0,
+		"COMMON_VALIDATION_GROUP_CREATE":            1,
+		"COMMON_VALIDATION_GROUP_UPDATE":            2,
+		"COMMON_VALIDATION_GROUP_PATCH":             3,
+		"COMMON_VALIDATION_GROUP_DELETE":            4,
+		"COMMON_VALIDATION_GROUP_QUERY":             5,
+		"COMMON_VALIDATION_GROUP_STRICT":            10,
+		"COMMON_VALIDATION_GROUP_NORMAL":            11,
+		"COMMON_VALIDATION_GROUP_LOOSE":             12,
+		"COMMON_VALIDATION_GROUP_REGISTER":          20,
+		"COMMON_VALIDATION_GROUP_LOGIN":             21,
+		"COMMON_VALIDATION_GROUP_PROFILE":           22,
+		"COMMON_VALIDATION_GROUP_CHANGE_PASSWORD":   23,
+		"COMMON_VALIDATION_GROUP_RESET_PASSWORD":    24,
+		"COMMON_VALIDATION_GROUP_DRAFT":             30,
+		"COMMON_VALIDATION_GROUP_SUBMIT":            31,
+		"COMMON_VALIDATION_GROUP_APPROVE":           32,
+		"COMMON_VALIDATION_GROUP_REJECT":            33,
+		"COMMON_VALIDATION_GROUP_REAL_NAME_AUTH":    40,
+		"COMMON_VALIDATION_GROUP_ENTERPRISE_AUTH":   41,
+		"COMMON_VALIDATION_GROUP_BANK_CARD_BINDING": 42,
+		"COMMON_VALIDATION_GROUP_SENSITIVE_OP":      50,
+		"COMMON_VALIDATION_GROUP_FINANCIAL":         51,
+		"COMMON_VALIDATION_GROUP_ADMIN":             52,
+	}
+)
+
+func (x CommonValidationGroup) Enum() *CommonValidationGroup {
+	p := new(CommonValidationGroup)
+	*p = x
+	return p
+}
+
+func (x CommonValidationGroup) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CommonValidationGroup) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_rule_groups_proto_enumTypes[0].Descriptor()
+}
+
+func (CommonValidationGroup) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_rule_groups_proto_enumTypes[0]
+}
+
+func (x CommonValidationGroup) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CommonValidationGroup.Descriptor instead.
+func (CommonValidationGroup) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{0}
+}
+
+// 请求来源
+type RequestSource int32
+
+const (
+	RequestSource_REQUEST_SOURCE_UNSPECIFIED RequestSource = 0
+	RequestSource_REQUEST_SOURCE_WEB         RequestSource = 1 // Web 端
+	RequestSource_REQUEST_SOURCE_MOBILE      RequestSource = 2 // 移动端
+	RequestSource_REQUEST_SOURCE_API         RequestSource = 3 // API 调用
+	RequestSource_REQUEST_SOURCE_INTERNAL    RequestSource = 4 // 内部调用
+	RequestSource_REQUEST_SOURCE_BATCH       RequestSource = 5 // 批量处理
+)
+
+// Enum value maps for RequestSource.
+var (
+	RequestSource_name = map[int32]string{
+		0: "REQUEST_SOURCE_UNSPECIFIED",
+		1: "REQUEST_SOURCE_WEB",
+		2: "REQUEST_SOURCE_MOBILE",
+		3: "REQUEST_SOURCE_API",
+		4: "REQUEST_SOURCE_INTERNAL",
+		5: "REQUEST_SOURCE_BATCH",
+	}
+	RequestSource_value = map[string]int32{
+		"REQUEST_SOURCE_UNSPECIFIED": 0,
+		"REQUEST_SOURCE_WEB":         1,
+		"REQUEST_SOURCE_MOBILE":      2,
+		"REQUEST_SOURCE_API":         3,
+		"REQUEST_SOURCE_INTERNAL":    4,
+		"REQUEST_SOURCE_BATCH":       5,
+	}
+)
+
+func (x RequestSource) Enum() *RequestSource {
+	p := new(RequestSource)
+	*p = x
+	return p
+}
+
+func (x RequestSource) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (RequestSource) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_rule_groups_proto_enumTypes[1].Descriptor()
+}
+
+func (RequestSource) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_rule_groups_proto_enumTypes[1]
+}
+
+func (x RequestSource) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use RequestSource.Descriptor instead.
+func (RequestSource) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{1}
+}
+
+// 验证模式
+type ValidationMode int32
+
+const (
+	ValidationMode_VALIDATION_MODE_UNSPECIFIED   ValidationMode = 0
+	ValidationMode_VALIDATION_MODE_ALL           ValidationMode = 1 // 验证所有规则
+	ValidationMode_VALIDATION_MODE_REQUIRED_ONLY ValidationMode = 2 // 仅验证必填项
+	ValidationMode_VALIDATION_MODE_CHANGED_ONLY  ValidationMode = 3 // 仅验证修改的字段
+	ValidationMode_VALIDATION_MODE_CUSTOM        ValidationMode = 4 // 自定义(根据组选择)
+)
+
+// Enum value maps for ValidationMode.
+var (
+	ValidationMode_name = map[int32]string{
+		0: "VALIDATION_MODE_UNSPECIFIED",
+		1: "VALIDATION_MODE_ALL",
+		2: "VALIDATION_MODE_REQUIRED_ONLY",
+		3: "VALIDATION_MODE_CHANGED_ONLY",
+		4: "VALIDATION_MODE_CUSTOM",
+	}
+	ValidationMode_value = map[string]int32{
+		"VALIDATION_MODE_UNSPECIFIED":   0,
+		"VALIDATION_MODE_ALL":           1,
+		"VALIDATION_MODE_REQUIRED_ONLY": 2,
+		"VALIDATION_MODE_CHANGED_ONLY":  3,
+		"VALIDATION_MODE_CUSTOM":        4,
+	}
+)
+
+func (x ValidationMode) Enum() *ValidationMode {
+	p := new(ValidationMode)
+	*p = x
+	return p
+}
+
+func (x ValidationMode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ValidationMode) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_rule_groups_proto_enumTypes[2].Descriptor()
+}
+
+func (ValidationMode) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_rule_groups_proto_enumTypes[2]
+}
+
+func (x ValidationMode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use ValidationMode.Descriptor instead.
+func (ValidationMode) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{2}
+}
+
+// 组合类型
+type CompositeType int32
+
+const (
+	CompositeType_COMPOSITE_TYPE_UNSPECIFIED CompositeType = 0
+	CompositeType_COMPOSITE_TYPE_AND         CompositeType = 1 // 所有规则都必须通过
+	CompositeType_COMPOSITE_TYPE_OR          CompositeType = 2 // 至少一个规则通过
+	CompositeType_COMPOSITE_TYPE_XOR         CompositeType = 3 // 恰好一个规则通过
+	CompositeType_COMPOSITE_TYPE_NOT         CompositeType = 4 // 规则不能通过
+)
+
+// Enum value maps for CompositeType.
+var (
+	CompositeType_name = map[int32]string{
+		0: "COMPOSITE_TYPE_UNSPECIFIED",
+		1: "COMPOSITE_TYPE_AND",
+		2: "COMPOSITE_TYPE_OR",
+		3: "COMPOSITE_TYPE_XOR",
+		4: "COMPOSITE_TYPE_NOT",
+	}
+	CompositeType_value = map[string]int32{
+		"COMPOSITE_TYPE_UNSPECIFIED": 0,
+		"COMPOSITE_TYPE_AND":         1,
+		"COMPOSITE_TYPE_OR":          2,
+		"COMPOSITE_TYPE_XOR":         3,
+		"COMPOSITE_TYPE_NOT":         4,
+	}
+)
+
+func (x CompositeType) Enum() *CompositeType {
+	p := new(CompositeType)
+	*p = x
+	return p
+}
+
+func (x CompositeType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CompositeType) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_rule_groups_proto_enumTypes[3].Descriptor()
+}
+
+func (CompositeType) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_rule_groups_proto_enumTypes[3]
+}
+
+func (x CompositeType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CompositeType.Descriptor instead.
+func (CompositeType) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{3}
+}
+
+// 默认行为
+type DefaultBehavior int32
+
+const (
+	DefaultBehavior_DEFAULT_BEHAVIOR_UNSPECIFIED DefaultBehavior = 0
+	DefaultBehavior_DEFAULT_BEHAVIOR_SKIP        DefaultBehavior = 1 // 跳过验证
+	DefaultBehavior_DEFAULT_BEHAVIOR_APPLY       DefaultBehavior = 2 // 应用验证
+	DefaultBehavior_DEFAULT_BEHAVIOR_FAIL        DefaultBehavior = 3 // 验证失败
+)
+
+// Enum value maps for DefaultBehavior.
+var (
+	DefaultBehavior_name = map[int32]string{
+		0: "DEFAULT_BEHAVIOR_UNSPECIFIED",
+		1: "DEFAULT_BEHAVIOR_SKIP",
+		2: "DEFAULT_BEHAVIOR_APPLY",
+		3: "DEFAULT_BEHAVIOR_FAIL",
+	}
+	DefaultBehavior_value = map[string]int32{
+		"DEFAULT_BEHAVIOR_UNSPECIFIED": 0,
+		"DEFAULT_BEHAVIOR_SKIP":        1,
+		"DEFAULT_BEHAVIOR_APPLY":       2,
+		"DEFAULT_BEHAVIOR_FAIL":        3,
+	}
+)
+
+func (x DefaultBehavior) Enum() *DefaultBehavior {
+	p := new(DefaultBehavior)
+	*p = x
+	return p
+}
+
+func (x DefaultBehavior) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (DefaultBehavior) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_rule_groups_proto_enumTypes[4].Descriptor()
+}
+
+func (DefaultBehavior) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_rule_groups_proto_enumTypes[4]
+}
+
+func (x DefaultBehavior) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use DefaultBehavior.Descriptor instead.
+func (DefaultBehavior) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{4}
+}
+
+// 规则集类别
+type RuleSetCategory int32
+
+const (
+	RuleSetCategory_RULE_SET_CATEGORY_UNSPECIFIED     RuleSetCategory = 0
+	RuleSetCategory_RULE_SET_CATEGORY_USER_MANAGEMENT RuleSetCategory = 1  // 用户管理
+	RuleSetCategory_RULE_SET_CATEGORY_FINANCIAL       RuleSetCategory = 2  // 金融
+	RuleSetCategory_RULE_SET_CATEGORY_ECOMMERCE       RuleSetCategory = 3  // 电商
+	RuleSetCategory_RULE_SET_CATEGORY_CONTENT         RuleSetCategory = 4  // 内容管理
+	RuleSetCategory_RULE_SET_CATEGORY_GOVERNMENT      RuleSetCategory = 5  // 政务
+	RuleSetCategory_RULE_SET_CATEGORY_HEALTHCARE      RuleSetCategory = 6  // 医疗
+	RuleSetCategory_RULE_SET_CATEGORY_EDUCATION       RuleSetCategory = 7  // 教育
+	RuleSetCategory_RULE_SET_CATEGORY_GENERAL         RuleSetCategory = 99 // 通用
+)
+
+// Enum value maps for RuleSetCategory.
+var (
+	RuleSetCategory_name = map[int32]string{
+		0:  "RULE_SET_CATEGORY_UNSPECIFIED",
+		1:  "RULE_SET_CATEGORY_USER_MANAGEMENT",
+		2:  "RULE_SET_CATEGORY_FINANCIAL",
+		3:  "RULE_SET_CATEGORY_ECOMMERCE",
+		4:  "RULE_SET_CATEGORY_CONTENT",
+		5:  "RULE_SET_CATEGORY_GOVERNMENT",
+		6:  "RULE_SET_CATEGORY_HEALTHCARE",
+		7:  "RULE_SET_CATEGORY_EDUCATION",
+		99: "RULE_SET_CATEGORY_GENERAL",
+	}
+	RuleSetCategory_value = map[string]int32{
+		"RULE_SET_CATEGORY_UNSPECIFIED":     0,
+		"RULE_SET_CATEGORY_USER_MANAGEMENT": 1,
+		"RULE_SET_CATEGORY_FINANCIAL":       2,
+		"RULE_SET_CATEGORY_ECOMMERCE":       3,
+		"RULE_SET_CATEGORY_CONTENT":         4,
+		"RULE_SET_CATEGORY_GOVERNMENT":      5,
+		"RULE_SET_CATEGORY_HEALTHCARE":      6,
+		"RULE_SET_CATEGORY_EDUCATION":       7,
+		"RULE_SET_CATEGORY_GENERAL":         99,
+	}
+)
+
+func (x RuleSetCategory) Enum() *RuleSetCategory {
+	p := new(RuleSetCategory)
+	*p = x
+	return p
+}
+
+func (x RuleSetCategory) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (RuleSetCategory) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_rule_groups_proto_enumTypes[5].Descriptor()
+}
+
+func (RuleSetCategory) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_rule_groups_proto_enumTypes[5]
+}
+
+func (x RuleSetCategory) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use RuleSetCategory.Descriptor instead.
+func (RuleSetCategory) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{5}
+}
+
+// 验证组 - 用于场景化验证
+//
+// 使用示例:
+// ```proto
+//
+//	message User {
+//	  string name = 1 [
+//	    (kuban.api.validate.field).string = { min_len: 2, max_len: 50 },
+//	    (kuban.api.validate.field).groups = ["create", "update"]
+//	  ];
+//
+//	  string password = 2 [
+//	    (kuban.api.validate.field).string = { min_len: 8 },
+//	    (kuban.api.validate.field).groups = ["create", "change_password"]
+//	  ];
+//	}
+//
+// ```
+type ValidationGroup struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 组名称(唯一标识)
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name"`
+	// 组显示名称(中文)
+	DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name"`
+	// 组显示名称(英文)
+	DisplayNameEn string `protobuf:"bytes,3,opt,name=display_name_en,json=displayNameEn,proto3" json:"display_name_en"`
+	// 组描述
+	Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description"`
+	// 是否为默认组(默认启用)
+	IsDefault bool `protobuf:"varint,5,opt,name=is_default,json=isDefault,proto3" json:"is_default"`
+	// 优先级(数字越大优先级越高)
+	Priority int32 `protobuf:"varint,6,opt,name=priority,proto3" json:"priority"`
+	// 父组(用于继承规则)
+	ParentGroup string `protobuf:"bytes,7,opt,name=parent_group,json=parentGroup,proto3" json:"parent_group"`
+	// 互斥组(不能同时激活的组)
+	ExclusiveGroups []string `protobuf:"bytes,8,rep,name=exclusive_groups,json=exclusiveGroups,proto3" json:"exclusive_groups"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *ValidationGroup) Reset() {
+	*x = ValidationGroup{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidationGroup) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidationGroup) ProtoMessage() {}
+
+func (x *ValidationGroup) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidationGroup.ProtoReflect.Descriptor instead.
+func (*ValidationGroup) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ValidationGroup) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *ValidationGroup) GetDisplayName() string {
+	if x != nil {
+		return x.DisplayName
+	}
+	return ""
+}
+
+func (x *ValidationGroup) GetDisplayNameEn() string {
+	if x != nil {
+		return x.DisplayNameEn
+	}
+	return ""
+}
+
+func (x *ValidationGroup) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *ValidationGroup) GetIsDefault() bool {
+	if x != nil {
+		return x.IsDefault
+	}
+	return false
+}
+
+func (x *ValidationGroup) GetPriority() int32 {
+	if x != nil {
+		return x.Priority
+	}
+	return 0
+}
+
+func (x *ValidationGroup) GetParentGroup() string {
+	if x != nil {
+		return x.ParentGroup
+	}
+	return ""
+}
+
+func (x *ValidationGroup) GetExclusiveGroups() []string {
+	if x != nil {
+		return x.ExclusiveGroups
+	}
+	return nil
+}
+
+// 验证上下文 - 运行时传递给验证器的上下文信息
+type ValidationContext struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 激活的验证组
+	ActiveGroups []string `protobuf:"bytes,1,rep,name=active_groups,json=activeGroups,proto3" json:"active_groups"`
+	// 用户角色
+	UserRoles []string `protobuf:"bytes,2,rep,name=user_roles,json=userRoles,proto3" json:"user_roles"`
+	// 用户权限
+	UserPermissions []string `protobuf:"bytes,3,rep,name=user_permissions,json=userPermissions,proto3" json:"user_permissions"`
+	// 租户 ID(多租户场景)
+	TenantId string `protobuf:"bytes,4,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id"`
+	// 请求来源
+	Source RequestSource `protobuf:"varint,5,opt,name=source,proto3,enum=kuban.api.validate.RequestSource" json:"source"`
+	// 是否为管理员操作
+	IsAdmin bool `protobuf:"varint,6,opt,name=is_admin,json=isAdmin,proto3" json:"is_admin"`
+	// 自定义元数据
+	Metadata map[string]string `protobuf:"bytes,7,rep,name=metadata,proto3" json:"metadata" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	// 验证时间戳
+	Timestamp int64 `protobuf:"varint,8,opt,name=timestamp,proto3" json:"timestamp"`
+	// 语言偏好(用于错误消息)
+	Language      string `protobuf:"bytes,9,opt,name=language,proto3" json:"language"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ValidationContext) Reset() {
+	*x = ValidationContext{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidationContext) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidationContext) ProtoMessage() {}
+
+func (x *ValidationContext) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidationContext.ProtoReflect.Descriptor instead.
+func (*ValidationContext) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ValidationContext) GetActiveGroups() []string {
+	if x != nil {
+		return x.ActiveGroups
+	}
+	return nil
+}
+
+func (x *ValidationContext) GetUserRoles() []string {
+	if x != nil {
+		return x.UserRoles
+	}
+	return nil
+}
+
+func (x *ValidationContext) GetUserPermissions() []string {
+	if x != nil {
+		return x.UserPermissions
+	}
+	return nil
+}
+
+func (x *ValidationContext) GetTenantId() string {
+	if x != nil {
+		return x.TenantId
+	}
+	return ""
+}
+
+func (x *ValidationContext) GetSource() RequestSource {
+	if x != nil {
+		return x.Source
+	}
+	return RequestSource_REQUEST_SOURCE_UNSPECIFIED
+}
+
+func (x *ValidationContext) GetIsAdmin() bool {
+	if x != nil {
+		return x.IsAdmin
+	}
+	return false
+}
+
+func (x *ValidationContext) GetMetadata() map[string]string {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+func (x *ValidationContext) GetTimestamp() int64 {
+	if x != nil {
+		return x.Timestamp
+	}
+	return 0
+}
+
+func (x *ValidationContext) GetLanguage() string {
+	if x != nil {
+		return x.Language
+	}
+	return ""
+}
+
+// 验证策略 - 控制验证行为
+type ValidationStrategy struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 验证模式
+	Mode ValidationMode `protobuf:"varint,1,opt,name=mode,proto3,enum=kuban.api.validate.ValidationMode" json:"mode"`
+	// 是否快速失败(遇到第一个错误就停止)
+	FailFast bool `protobuf:"varint,2,opt,name=fail_fast,json=failFast,proto3" json:"fail_fast"`
+	// 是否收集警告(非阻塞性错误)
+	CollectWarnings bool `protobuf:"varint,3,opt,name=collect_warnings,json=collectWarnings,proto3" json:"collect_warnings"`
+	// 最大错误数(超过后停止验证)
+	MaxErrors int32 `protobuf:"varint,4,opt,name=max_errors,json=maxErrors,proto3" json:"max_errors"`
+	// 验证超时(毫秒)
+	TimeoutMs int64 `protobuf:"varint,5,opt,name=timeout_ms,json=timeoutMs,proto3" json:"timeout_ms"`
+	// 是否启用缓存
+	EnableCache bool `protobuf:"varint,6,opt,name=enable_cache,json=enableCache,proto3" json:"enable_cache"`
+	// 缓存 TTL(秒)
+	CacheTtlSeconds int32 `protobuf:"varint,7,opt,name=cache_ttl_seconds,json=cacheTtlSeconds,proto3" json:"cache_ttl_seconds"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *ValidationStrategy) Reset() {
+	*x = ValidationStrategy{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidationStrategy) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidationStrategy) ProtoMessage() {}
+
+func (x *ValidationStrategy) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidationStrategy.ProtoReflect.Descriptor instead.
+func (*ValidationStrategy) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ValidationStrategy) GetMode() ValidationMode {
+	if x != nil {
+		return x.Mode
+	}
+	return ValidationMode_VALIDATION_MODE_UNSPECIFIED
+}
+
+func (x *ValidationStrategy) GetFailFast() bool {
+	if x != nil {
+		return x.FailFast
+	}
+	return false
+}
+
+func (x *ValidationStrategy) GetCollectWarnings() bool {
+	if x != nil {
+		return x.CollectWarnings
+	}
+	return false
+}
+
+func (x *ValidationStrategy) GetMaxErrors() int32 {
+	if x != nil {
+		return x.MaxErrors
+	}
+	return 0
+}
+
+func (x *ValidationStrategy) GetTimeoutMs() int64 {
+	if x != nil {
+		return x.TimeoutMs
+	}
+	return 0
+}
+
+func (x *ValidationStrategy) GetEnableCache() bool {
+	if x != nil {
+		return x.EnableCache
+	}
+	return false
+}
+
+func (x *ValidationStrategy) GetCacheTtlSeconds() int32 {
+	if x != nil {
+		return x.CacheTtlSeconds
+	}
+	return 0
+}
+
+// 组合验证规则 - 支持复杂的验证逻辑组合
+type CompositeRule struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 规则组合类型
+	Type CompositeType `protobuf:"varint,1,opt,name=type,proto3,enum=kuban.api.validate.CompositeType" json:"type"`
+	// 子规则列表
+	Rules []*RuleRef `protobuf:"bytes,2,rep,name=rules,proto3" json:"rules"`
+	// 错误消息
+	Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message"`
+	// 错误消息(英文)
+	MessageEn     string `protobuf:"bytes,4,opt,name=message_en,json=messageEn,proto3" json:"message_en"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *CompositeRule) Reset() {
+	*x = CompositeRule{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *CompositeRule) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CompositeRule) ProtoMessage() {}
+
+func (x *CompositeRule) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CompositeRule.ProtoReflect.Descriptor instead.
+func (*CompositeRule) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *CompositeRule) GetType() CompositeType {
+	if x != nil {
+		return x.Type
+	}
+	return CompositeType_COMPOSITE_TYPE_UNSPECIFIED
+}
+
+func (x *CompositeRule) GetRules() []*RuleRef {
+	if x != nil {
+		return x.Rules
+	}
+	return nil
+}
+
+func (x *CompositeRule) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *CompositeRule) GetMessageEn() string {
+	if x != nil {
+		return x.MessageEn
+	}
+	return ""
+}
+
+// 规则引用
+type RuleRef struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 规则 ID
+	RuleId string `protobuf:"bytes,1,opt,name=rule_id,json=ruleId,proto3" json:"rule_id"`
+	// 规则权重(用于优先级排序)
+	Weight int32 `protobuf:"varint,2,opt,name=weight,proto3" json:"weight"`
+	// 是否为可选规则
+	Optional      bool `protobuf:"varint,3,opt,name=optional,proto3" json:"optional"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *RuleRef) Reset() {
+	*x = RuleRef{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *RuleRef) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RuleRef) ProtoMessage() {}
+
+func (x *RuleRef) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RuleRef.ProtoReflect.Descriptor instead.
+func (*RuleRef) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *RuleRef) GetRuleId() string {
+	if x != nil {
+		return x.RuleId
+	}
+	return ""
+}
+
+func (x *RuleRef) GetWeight() int32 {
+	if x != nil {
+		return x.Weight
+	}
+	return 0
+}
+
+func (x *RuleRef) GetOptional() bool {
+	if x != nil {
+		return x.Optional
+	}
+	return false
+}
+
+// 条件验证规则 - 根据条件决定是否应用规则
+type ConditionalRule struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 条件表达式(CEL)
+	Condition string `protobuf:"bytes,1,opt,name=condition,proto3" json:"condition"`
+	// 条件为真时应用的规则
+	WhenTrue []*RuleRef `protobuf:"bytes,2,rep,name=when_true,json=whenTrue,proto3" json:"when_true"`
+	// 条件为假时应用的规则
+	WhenFalse []*RuleRef `protobuf:"bytes,3,rep,name=when_false,json=whenFalse,proto3" json:"when_false"`
+	// 条件评估失败时的默认行为
+	OnError       DefaultBehavior `protobuf:"varint,4,opt,name=on_error,json=onError,proto3,enum=kuban.api.validate.DefaultBehavior" json:"on_error"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ConditionalRule) Reset() {
+	*x = ConditionalRule{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ConditionalRule) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ConditionalRule) ProtoMessage() {}
+
+func (x *ConditionalRule) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ConditionalRule.ProtoReflect.Descriptor instead.
+func (*ConditionalRule) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ConditionalRule) GetCondition() string {
+	if x != nil {
+		return x.Condition
+	}
+	return ""
+}
+
+func (x *ConditionalRule) GetWhenTrue() []*RuleRef {
+	if x != nil {
+		return x.WhenTrue
+	}
+	return nil
+}
+
+func (x *ConditionalRule) GetWhenFalse() []*RuleRef {
+	if x != nil {
+		return x.WhenFalse
+	}
+	return nil
+}
+
+func (x *ConditionalRule) GetOnError() DefaultBehavior {
+	if x != nil {
+		return x.OnError
+	}
+	return DefaultBehavior_DEFAULT_BEHAVIOR_UNSPECIFIED
+}
+
+// 验证规则集 - 预定义的规则组合,可复用
+type ValidationRuleSet struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 规则集 ID
+	Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"`
+	// 规则集名称
+	Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"`
+	// 规则集描述
+	Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description"`
+	// 规则集版本
+	Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version"`
+	// 包含的验证组
+	Groups []string `protobuf:"bytes,5,rep,name=groups,proto3" json:"groups"`
+	// 包含的规则
+	Rules []*RuleRef `protobuf:"bytes,6,rep,name=rules,proto3" json:"rules"`
+	// 验证策略
+	Strategy *ValidationStrategy `protobuf:"bytes,7,opt,name=strategy,proto3" json:"strategy"`
+	// 是否为内置规则集
+	Builtin bool `protobuf:"varint,8,opt,name=builtin,proto3" json:"builtin"`
+	// 创建时间
+	CreatedAt int64 `protobuf:"varint,9,opt,name=created_at,json=createdAt,proto3" json:"created_at"`
+	// 更新时间
+	UpdatedAt int64 `protobuf:"varint,10,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at"`
+	// 创建者
+	CreatedBy     string `protobuf:"bytes,11,opt,name=created_by,json=createdBy,proto3" json:"created_by"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ValidationRuleSet) Reset() {
+	*x = ValidationRuleSet{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ValidationRuleSet) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ValidationRuleSet) ProtoMessage() {}
+
+func (x *ValidationRuleSet) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ValidationRuleSet.ProtoReflect.Descriptor instead.
+func (*ValidationRuleSet) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ValidationRuleSet) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *ValidationRuleSet) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *ValidationRuleSet) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *ValidationRuleSet) GetVersion() string {
+	if x != nil {
+		return x.Version
+	}
+	return ""
+}
+
+func (x *ValidationRuleSet) GetGroups() []string {
+	if x != nil {
+		return x.Groups
+	}
+	return nil
+}
+
+func (x *ValidationRuleSet) GetRules() []*RuleRef {
+	if x != nil {
+		return x.Rules
+	}
+	return nil
+}
+
+func (x *ValidationRuleSet) GetStrategy() *ValidationStrategy {
+	if x != nil {
+		return x.Strategy
+	}
+	return nil
+}
+
+func (x *ValidationRuleSet) GetBuiltin() bool {
+	if x != nil {
+		return x.Builtin
+	}
+	return false
+}
+
+func (x *ValidationRuleSet) GetCreatedAt() int64 {
+	if x != nil {
+		return x.CreatedAt
+	}
+	return 0
+}
+
+func (x *ValidationRuleSet) GetUpdatedAt() int64 {
+	if x != nil {
+		return x.UpdatedAt
+	}
+	return 0
+}
+
+func (x *ValidationRuleSet) GetCreatedBy() string {
+	if x != nil {
+		return x.CreatedBy
+	}
+	return ""
+}
+
+// 规则集模板 - 用于快速创建常见场景的验证规则
+type RuleSetTemplate struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 模板 ID
+	Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"`
+	// 模板名称
+	Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"`
+	// 模板描述
+	Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description"`
+	// 适用场景
+	Scenarios []string `protobuf:"bytes,4,rep,name=scenarios,proto3" json:"scenarios"`
+	// 模板类别
+	Categories []string `protobuf:"bytes,5,rep,name=categories,proto3" json:"categories"`
+	// 规则集定义
+	RuleSet *ValidationRuleSet `protobuf:"bytes,6,opt,name=rule_set,json=ruleSet,proto3" json:"rule_set"`
+	// 使用示例
+	UsageExample string `protobuf:"bytes,7,opt,name=usage_example,json=usageExample,proto3" json:"usage_example"`
+	// 下载次数
+	DownloadCount int64 `protobuf:"varint,8,opt,name=download_count,json=downloadCount,proto3" json:"download_count"`
+	// 评分
+	Rating        float32 `protobuf:"fixed32,9,opt,name=rating,proto3" json:"rating"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *RuleSetTemplate) Reset() {
+	*x = RuleSetTemplate{}
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *RuleSetTemplate) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RuleSetTemplate) ProtoMessage() {}
+
+func (x *RuleSetTemplate) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_rule_groups_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RuleSetTemplate.ProtoReflect.Descriptor instead.
+func (*RuleSetTemplate) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_rule_groups_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *RuleSetTemplate) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *RuleSetTemplate) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *RuleSetTemplate) GetDescription() string {
+	if x != nil {
+		return x.Description
+	}
+	return ""
+}
+
+func (x *RuleSetTemplate) GetScenarios() []string {
+	if x != nil {
+		return x.Scenarios
+	}
+	return nil
+}
+
+func (x *RuleSetTemplate) GetCategories() []string {
+	if x != nil {
+		return x.Categories
+	}
+	return nil
+}
+
+func (x *RuleSetTemplate) GetRuleSet() *ValidationRuleSet {
+	if x != nil {
+		return x.RuleSet
+	}
+	return nil
+}
+
+func (x *RuleSetTemplate) GetUsageExample() string {
+	if x != nil {
+		return x.UsageExample
+	}
+	return ""
+}
+
+func (x *RuleSetTemplate) GetDownloadCount() int64 {
+	if x != nil {
+		return x.DownloadCount
+	}
+	return 0
+}
+
+func (x *RuleSetTemplate) GetRating() float32 {
+	if x != nil {
+		return x.Rating
+	}
+	return 0
+}
+
+var File_kuban_api_validate_rule_groups_proto protoreflect.FileDescriptor
+
+const file_kuban_api_validate_rule_groups_proto_rawDesc = "" +
+	"\n" +
+	"$kuban/api/validate/rule_groups.proto\x12\x12kuban.api.validate\x1a google/protobuf/descriptor.proto\"\x9b\x02\n" +
+	"\x0fValidationGroup\x12\x12\n" +
+	"\x04name\x18\x01 \x01(\tR\x04name\x12!\n" +
+	"\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12&\n" +
+	"\x0fdisplay_name_en\x18\x03 \x01(\tR\rdisplayNameEn\x12 \n" +
+	"\vdescription\x18\x04 \x01(\tR\vdescription\x12\x1d\n" +
+	"\n" +
+	"is_default\x18\x05 \x01(\bR\tisDefault\x12\x1a\n" +
+	"\bpriority\x18\x06 \x01(\x05R\bpriority\x12!\n" +
+	"\fparent_group\x18\a \x01(\tR\vparentGroup\x12)\n" +
+	"\x10exclusive_groups\x18\b \x03(\tR\x0fexclusiveGroups\"\xbd\x03\n" +
+	"\x11ValidationContext\x12#\n" +
+	"\ractive_groups\x18\x01 \x03(\tR\factiveGroups\x12\x1d\n" +
+	"\n" +
+	"user_roles\x18\x02 \x03(\tR\tuserRoles\x12)\n" +
+	"\x10user_permissions\x18\x03 \x03(\tR\x0fuserPermissions\x12\x1b\n" +
+	"\ttenant_id\x18\x04 \x01(\tR\btenantId\x129\n" +
+	"\x06source\x18\x05 \x01(\x0e2!.kuban.api.validate.RequestSourceR\x06source\x12\x19\n" +
+	"\bis_admin\x18\x06 \x01(\bR\aisAdmin\x12O\n" +
+	"\bmetadata\x18\a \x03(\v23.kuban.api.validate.ValidationContext.MetadataEntryR\bmetadata\x12\x1c\n" +
+	"\ttimestamp\x18\b \x01(\x03R\ttimestamp\x12\x1a\n" +
+	"\blanguage\x18\t \x01(\tR\blanguage\x1a;\n" +
+	"\rMetadataEntry\x12\x10\n" +
+	"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+	"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xa1\x02\n" +
+	"\x12ValidationStrategy\x126\n" +
+	"\x04mode\x18\x01 \x01(\x0e2\".kuban.api.validate.ValidationModeR\x04mode\x12\x1b\n" +
+	"\tfail_fast\x18\x02 \x01(\bR\bfailFast\x12)\n" +
+	"\x10collect_warnings\x18\x03 \x01(\bR\x0fcollectWarnings\x12\x1d\n" +
+	"\n" +
+	"max_errors\x18\x04 \x01(\x05R\tmaxErrors\x12\x1d\n" +
+	"\n" +
+	"timeout_ms\x18\x05 \x01(\x03R\ttimeoutMs\x12!\n" +
+	"\fenable_cache\x18\x06 \x01(\bR\venableCache\x12*\n" +
+	"\x11cache_ttl_seconds\x18\a \x01(\x05R\x0fcacheTtlSeconds\"\xb2\x01\n" +
+	"\rCompositeRule\x125\n" +
+	"\x04type\x18\x01 \x01(\x0e2!.kuban.api.validate.CompositeTypeR\x04type\x121\n" +
+	"\x05rules\x18\x02 \x03(\v2\x1b.kuban.api.validate.RuleRefR\x05rules\x12\x18\n" +
+	"\amessage\x18\x03 \x01(\tR\amessage\x12\x1d\n" +
+	"\n" +
+	"message_en\x18\x04 \x01(\tR\tmessageEn\"V\n" +
+	"\aRuleRef\x12\x17\n" +
+	"\arule_id\x18\x01 \x01(\tR\x06ruleId\x12\x16\n" +
+	"\x06weight\x18\x02 \x01(\x05R\x06weight\x12\x1a\n" +
+	"\boptional\x18\x03 \x01(\bR\boptional\"\xe5\x01\n" +
+	"\x0fConditionalRule\x12\x1c\n" +
+	"\tcondition\x18\x01 \x01(\tR\tcondition\x128\n" +
+	"\twhen_true\x18\x02 \x03(\v2\x1b.kuban.api.validate.RuleRefR\bwhenTrue\x12:\n" +
+	"\n" +
+	"when_false\x18\x03 \x03(\v2\x1b.kuban.api.validate.RuleRefR\twhenFalse\x12>\n" +
+	"\bon_error\x18\x04 \x01(\x0e2#.kuban.api.validate.DefaultBehaviorR\aonError\"\xf9\x02\n" +
+	"\x11ValidationRuleSet\x12\x0e\n" +
+	"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
+	"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
+	"\vdescription\x18\x03 \x01(\tR\vdescription\x12\x18\n" +
+	"\aversion\x18\x04 \x01(\tR\aversion\x12\x16\n" +
+	"\x06groups\x18\x05 \x03(\tR\x06groups\x121\n" +
+	"\x05rules\x18\x06 \x03(\v2\x1b.kuban.api.validate.RuleRefR\x05rules\x12B\n" +
+	"\bstrategy\x18\a \x01(\v2&.kuban.api.validate.ValidationStrategyR\bstrategy\x12\x18\n" +
+	"\abuiltin\x18\b \x01(\bR\abuiltin\x12\x1d\n" +
+	"\n" +
+	"created_at\x18\t \x01(\x03R\tcreatedAt\x12\x1d\n" +
+	"\n" +
+	"updated_at\x18\n" +
+	" \x01(\x03R\tupdatedAt\x12\x1d\n" +
+	"\n" +
+	"created_by\x18\v \x01(\tR\tcreatedBy\"\xbb\x02\n" +
+	"\x0fRuleSetTemplate\x12\x0e\n" +
+	"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
+	"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
+	"\vdescription\x18\x03 \x01(\tR\vdescription\x12\x1c\n" +
+	"\tscenarios\x18\x04 \x03(\tR\tscenarios\x12\x1e\n" +
+	"\n" +
+	"categories\x18\x05 \x03(\tR\n" +
+	"categories\x12@\n" +
+	"\brule_set\x18\x06 \x01(\v2%.kuban.api.validate.ValidationRuleSetR\aruleSet\x12#\n" +
+	"\rusage_example\x18\a \x01(\tR\fusageExample\x12%\n" +
+	"\x0edownload_count\x18\b \x01(\x03R\rdownloadCount\x12\x16\n" +
+	"\x06rating\x18\t \x01(\x02R\x06rating*\xb0\a\n" +
+	"\x15CommonValidationGroup\x12'\n" +
+	"#COMMON_VALIDATION_GROUP_UNSPECIFIED\x10\x00\x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_CREATE\x10\x01\x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_UPDATE\x10\x02\x12!\n" +
+	"\x1dCOMMON_VALIDATION_GROUP_PATCH\x10\x03\x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_DELETE\x10\x04\x12!\n" +
+	"\x1dCOMMON_VALIDATION_GROUP_QUERY\x10\x05\x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_STRICT\x10\n" +
+	"\x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_NORMAL\x10\v\x12!\n" +
+	"\x1dCOMMON_VALIDATION_GROUP_LOOSE\x10\f\x12$\n" +
+	" COMMON_VALIDATION_GROUP_REGISTER\x10\x14\x12!\n" +
+	"\x1dCOMMON_VALIDATION_GROUP_LOGIN\x10\x15\x12#\n" +
+	"\x1fCOMMON_VALIDATION_GROUP_PROFILE\x10\x16\x12+\n" +
+	"'COMMON_VALIDATION_GROUP_CHANGE_PASSWORD\x10\x17\x12*\n" +
+	"&COMMON_VALIDATION_GROUP_RESET_PASSWORD\x10\x18\x12!\n" +
+	"\x1dCOMMON_VALIDATION_GROUP_DRAFT\x10\x1e\x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_SUBMIT\x10\x1f\x12#\n" +
+	"\x1fCOMMON_VALIDATION_GROUP_APPROVE\x10 \x12\"\n" +
+	"\x1eCOMMON_VALIDATION_GROUP_REJECT\x10!\x12*\n" +
+	"&COMMON_VALIDATION_GROUP_REAL_NAME_AUTH\x10(\x12+\n" +
+	"'COMMON_VALIDATION_GROUP_ENTERPRISE_AUTH\x10)\x12-\n" +
+	")COMMON_VALIDATION_GROUP_BANK_CARD_BINDING\x10*\x12(\n" +
+	"$COMMON_VALIDATION_GROUP_SENSITIVE_OP\x102\x12%\n" +
+	"!COMMON_VALIDATION_GROUP_FINANCIAL\x103\x12!\n" +
+	"\x1dCOMMON_VALIDATION_GROUP_ADMIN\x104*\xb1\x01\n" +
+	"\rRequestSource\x12\x1e\n" +
+	"\x1aREQUEST_SOURCE_UNSPECIFIED\x10\x00\x12\x16\n" +
+	"\x12REQUEST_SOURCE_WEB\x10\x01\x12\x19\n" +
+	"\x15REQUEST_SOURCE_MOBILE\x10\x02\x12\x16\n" +
+	"\x12REQUEST_SOURCE_API\x10\x03\x12\x1b\n" +
+	"\x17REQUEST_SOURCE_INTERNAL\x10\x04\x12\x18\n" +
+	"\x14REQUEST_SOURCE_BATCH\x10\x05*\xab\x01\n" +
+	"\x0eValidationMode\x12\x1f\n" +
+	"\x1bVALIDATION_MODE_UNSPECIFIED\x10\x00\x12\x17\n" +
+	"\x13VALIDATION_MODE_ALL\x10\x01\x12!\n" +
+	"\x1dVALIDATION_MODE_REQUIRED_ONLY\x10\x02\x12 \n" +
+	"\x1cVALIDATION_MODE_CHANGED_ONLY\x10\x03\x12\x1a\n" +
+	"\x16VALIDATION_MODE_CUSTOM\x10\x04*\x8e\x01\n" +
+	"\rCompositeType\x12\x1e\n" +
+	"\x1aCOMPOSITE_TYPE_UNSPECIFIED\x10\x00\x12\x16\n" +
+	"\x12COMPOSITE_TYPE_AND\x10\x01\x12\x15\n" +
+	"\x11COMPOSITE_TYPE_OR\x10\x02\x12\x16\n" +
+	"\x12COMPOSITE_TYPE_XOR\x10\x03\x12\x16\n" +
+	"\x12COMPOSITE_TYPE_NOT\x10\x04*\x85\x01\n" +
+	"\x0fDefaultBehavior\x12 \n" +
+	"\x1cDEFAULT_BEHAVIOR_UNSPECIFIED\x10\x00\x12\x19\n" +
+	"\x15DEFAULT_BEHAVIOR_SKIP\x10\x01\x12\x1a\n" +
+	"\x16DEFAULT_BEHAVIOR_APPLY\x10\x02\x12\x19\n" +
+	"\x15DEFAULT_BEHAVIOR_FAIL\x10\x03*\xc0\x02\n" +
+	"\x0fRuleSetCategory\x12!\n" +
+	"\x1dRULE_SET_CATEGORY_UNSPECIFIED\x10\x00\x12%\n" +
+	"!RULE_SET_CATEGORY_USER_MANAGEMENT\x10\x01\x12\x1f\n" +
+	"\x1bRULE_SET_CATEGORY_FINANCIAL\x10\x02\x12\x1f\n" +
+	"\x1bRULE_SET_CATEGORY_ECOMMERCE\x10\x03\x12\x1d\n" +
+	"\x19RULE_SET_CATEGORY_CONTENT\x10\x04\x12 \n" +
+	"\x1cRULE_SET_CATEGORY_GOVERNMENT\x10\x05\x12 \n" +
+	"\x1cRULE_SET_CATEGORY_HEALTHCARE\x10\x06\x12\x1f\n" +
+	"\x1bRULE_SET_CATEGORY_EDUCATION\x10\a\x12\x1d\n" +
+	"\x19RULE_SET_CATEGORY_GENERAL\x10cB=Z;git.ikuban.com/server/kubanapis/kuban/api/validate;validateb\x06proto3"
+
+var (
+	file_kuban_api_validate_rule_groups_proto_rawDescOnce sync.Once
+	file_kuban_api_validate_rule_groups_proto_rawDescData []byte
+)
+
+func file_kuban_api_validate_rule_groups_proto_rawDescGZIP() []byte {
+	file_kuban_api_validate_rule_groups_proto_rawDescOnce.Do(func() {
+		file_kuban_api_validate_rule_groups_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_kuban_api_validate_rule_groups_proto_rawDesc), len(file_kuban_api_validate_rule_groups_proto_rawDesc)))
+	})
+	return file_kuban_api_validate_rule_groups_proto_rawDescData
+}
+
+var file_kuban_api_validate_rule_groups_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
+var file_kuban_api_validate_rule_groups_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
+var file_kuban_api_validate_rule_groups_proto_goTypes = []any{
+	(CommonValidationGroup)(0), // 0: kuban.api.validate.CommonValidationGroup
+	(RequestSource)(0),         // 1: kuban.api.validate.RequestSource
+	(ValidationMode)(0),        // 2: kuban.api.validate.ValidationMode
+	(CompositeType)(0),         // 3: kuban.api.validate.CompositeType
+	(DefaultBehavior)(0),       // 4: kuban.api.validate.DefaultBehavior
+	(RuleSetCategory)(0),       // 5: kuban.api.validate.RuleSetCategory
+	(*ValidationGroup)(nil),    // 6: kuban.api.validate.ValidationGroup
+	(*ValidationContext)(nil),  // 7: kuban.api.validate.ValidationContext
+	(*ValidationStrategy)(nil), // 8: kuban.api.validate.ValidationStrategy
+	(*CompositeRule)(nil),      // 9: kuban.api.validate.CompositeRule
+	(*RuleRef)(nil),            // 10: kuban.api.validate.RuleRef
+	(*ConditionalRule)(nil),    // 11: kuban.api.validate.ConditionalRule
+	(*ValidationRuleSet)(nil),  // 12: kuban.api.validate.ValidationRuleSet
+	(*RuleSetTemplate)(nil),    // 13: kuban.api.validate.RuleSetTemplate
+	nil,                        // 14: kuban.api.validate.ValidationContext.MetadataEntry
+}
+var file_kuban_api_validate_rule_groups_proto_depIdxs = []int32{
+	1,  // 0: kuban.api.validate.ValidationContext.source:type_name -> kuban.api.validate.RequestSource
+	14, // 1: kuban.api.validate.ValidationContext.metadata:type_name -> kuban.api.validate.ValidationContext.MetadataEntry
+	2,  // 2: kuban.api.validate.ValidationStrategy.mode:type_name -> kuban.api.validate.ValidationMode
+	3,  // 3: kuban.api.validate.CompositeRule.type:type_name -> kuban.api.validate.CompositeType
+	10, // 4: kuban.api.validate.CompositeRule.rules:type_name -> kuban.api.validate.RuleRef
+	10, // 5: kuban.api.validate.ConditionalRule.when_true:type_name -> kuban.api.validate.RuleRef
+	10, // 6: kuban.api.validate.ConditionalRule.when_false:type_name -> kuban.api.validate.RuleRef
+	4,  // 7: kuban.api.validate.ConditionalRule.on_error:type_name -> kuban.api.validate.DefaultBehavior
+	10, // 8: kuban.api.validate.ValidationRuleSet.rules:type_name -> kuban.api.validate.RuleRef
+	8,  // 9: kuban.api.validate.ValidationRuleSet.strategy:type_name -> kuban.api.validate.ValidationStrategy
+	12, // 10: kuban.api.validate.RuleSetTemplate.rule_set:type_name -> kuban.api.validate.ValidationRuleSet
+	11, // [11:11] is the sub-list for method output_type
+	11, // [11:11] is the sub-list for method input_type
+	11, // [11:11] is the sub-list for extension type_name
+	11, // [11:11] is the sub-list for extension extendee
+	0,  // [0:11] is the sub-list for field type_name
+}
+
+func init() { file_kuban_api_validate_rule_groups_proto_init() }
+func file_kuban_api_validate_rule_groups_proto_init() {
+	if File_kuban_api_validate_rule_groups_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_kuban_api_validate_rule_groups_proto_rawDesc), len(file_kuban_api_validate_rule_groups_proto_rawDesc)),
+			NumEnums:      6,
+			NumMessages:   9,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_kuban_api_validate_rule_groups_proto_goTypes,
+		DependencyIndexes: file_kuban_api_validate_rule_groups_proto_depIdxs,
+		EnumInfos:         file_kuban_api_validate_rule_groups_proto_enumTypes,
+		MessageInfos:      file_kuban_api_validate_rule_groups_proto_msgTypes,
+	}.Build()
+	File_kuban_api_validate_rule_groups_proto = out.File
+	file_kuban_api_validate_rule_groups_proto_goTypes = nil
+	file_kuban_api_validate_rule_groups_proto_depIdxs = nil
+}

+ 3617 - 0
kuban/api/validate/validate.pb.go

@@ -0,0 +1,3617 @@
+// Copyright 2025 Kuban Technologies
+//
+// 自定义字段验证框架 - 基于 buf/validate 优化设计
+// 提供简化的 API、中文支持和业务规则集成
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.6-modify
+// 	protoc        v6.31.1
+// source: kuban/api/validate/validate.proto
+
+package validate
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	descriptorpb "google.golang.org/protobuf/types/descriptorpb"
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// 忽略策略
+type IgnoreRule int32
+
+const (
+	// 未指定 - 默认行为(字段未设置时不验证)
+	IgnoreRule_IGNORE_UNSPECIFIED IgnoreRule = 0
+	// 字段为零值时忽略验证
+	IgnoreRule_IGNORE_IF_ZERO IgnoreRule = 1
+	// 始终忽略验证
+	IgnoreRule_IGNORE_ALWAYS IgnoreRule = 2
+	// 从不忽略验证(即使未设置也验证)
+	IgnoreRule_IGNORE_NEVER IgnoreRule = 3
+)
+
+// Enum value maps for IgnoreRule.
+var (
+	IgnoreRule_name = map[int32]string{
+		0: "IGNORE_UNSPECIFIED",
+		1: "IGNORE_IF_ZERO",
+		2: "IGNORE_ALWAYS",
+		3: "IGNORE_NEVER",
+	}
+	IgnoreRule_value = map[string]int32{
+		"IGNORE_UNSPECIFIED": 0,
+		"IGNORE_IF_ZERO":     1,
+		"IGNORE_ALWAYS":      2,
+		"IGNORE_NEVER":       3,
+	}
+)
+
+func (x IgnoreRule) Enum() *IgnoreRule {
+	p := new(IgnoreRule)
+	*p = x
+	return p
+}
+
+func (x IgnoreRule) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (IgnoreRule) Descriptor() protoreflect.EnumDescriptor {
+	return file_kuban_api_validate_validate_proto_enumTypes[0].Descriptor()
+}
+
+func (IgnoreRule) Type() protoreflect.EnumType {
+	return &file_kuban_api_validate_validate_proto_enumTypes[0]
+}
+
+func (x IgnoreRule) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use IgnoreRule.Descriptor instead.
+func (IgnoreRule) EnumDescriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{0}
+}
+
+// CEL 验证规则
+// 使用 Common Expression Language 编写自定义验证逻辑
+type Rule struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 规则唯一标识符
+	Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"`
+	// 错误消息(中文)
+	Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message"`
+	// 错误消息(英文) - 可选,用于国际化
+	MessageEn string `protobuf:"bytes,3,opt,name=message_en,json=messageEn,proto3" json:"message_en"`
+	// CEL 表达式 - 返回 true 表示验证通过
+	Expression    string `protobuf:"bytes,4,opt,name=expression,proto3" json:"expression"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Rule) Reset() {
+	*x = Rule{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Rule) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Rule) ProtoMessage() {}
+
+func (x *Rule) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Rule.ProtoReflect.Descriptor instead.
+func (*Rule) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Rule) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *Rule) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *Rule) GetMessageEn() string {
+	if x != nil {
+		return x.MessageEn
+	}
+	return ""
+}
+
+func (x *Rule) GetExpression() string {
+	if x != nil {
+		return x.Expression
+	}
+	return ""
+}
+
+// 消息级别验证规则
+type MessageRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// CEL 自定义规则列表
+	Cel []*Rule `protobuf:"bytes,1,rep,name=cel,proto3" json:"cel"`
+	// 是否禁用所有字段验证
+	Disabled bool `protobuf:"varint,2,opt,name=disabled,proto3" json:"disabled"`
+	// 验证组 - 用于分组验证
+	Groups        []string `protobuf:"bytes,3,rep,name=groups,proto3" json:"groups"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *MessageRules) Reset() {
+	*x = MessageRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *MessageRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MessageRules) ProtoMessage() {}
+
+func (x *MessageRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MessageRules.ProtoReflect.Descriptor instead.
+func (*MessageRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *MessageRules) GetCel() []*Rule {
+	if x != nil {
+		return x.Cel
+	}
+	return nil
+}
+
+func (x *MessageRules) GetDisabled() bool {
+	if x != nil {
+		return x.Disabled
+	}
+	return false
+}
+
+func (x *MessageRules) GetGroups() []string {
+	if x != nil {
+		return x.Groups
+	}
+	return nil
+}
+
+// Oneof 验证规则
+type OneofRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 是否必须选择一个字段
+	Required      bool `protobuf:"varint,1,opt,name=required,proto3" json:"required"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *OneofRules) Reset() {
+	*x = OneofRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OneofRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OneofRules) ProtoMessage() {}
+
+func (x *OneofRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OneofRules.ProtoReflect.Descriptor instead.
+func (*OneofRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *OneofRules) GetRequired() bool {
+	if x != nil {
+		return x.Required
+	}
+	return false
+}
+
+// 字段级别验证规则
+type FieldRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// CEL 自定义规则列表
+	Cel []*Rule `protobuf:"bytes,1,rep,name=cel,proto3" json:"cel"`
+	// 字段是否必填 (Proto3 不需要 optional 关键字)
+	Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required"`
+	// 忽略策略
+	Ignore IgnoreRule `protobuf:"varint,3,opt,name=ignore,proto3,enum=kuban.api.validate.IgnoreRule" json:"ignore"`
+	// 验证组 - 只在指定组中验证
+	Groups []string `protobuf:"bytes,4,rep,name=groups,proto3" json:"groups"`
+	// 通用错误消息(中文) - 覆盖所有验证规则的默认消息
+	ErrorMessage string `protobuf:"bytes,5,opt,name=error_message,json=errorMessage,proto3" json:"error_message"`
+	// 通用错误消息(英文)
+	ErrorMessageEn string `protobuf:"bytes,6,opt,name=error_message_en,json=errorMessageEn,proto3" json:"error_message_en"`
+	// required 验证专用错误消息(中文)
+	RequiredMessage string `protobuf:"bytes,7,opt,name=required_message,json=requiredMessage,proto3" json:"required_message"`
+	// required 验证专用错误消息(英文)
+	RequiredMessageEn string `protobuf:"bytes,8,opt,name=required_message_en,json=requiredMessageEn,proto3" json:"required_message_en"`
+	// 类型特定的验证规则
+	//
+	// Types that are valid to be assigned to Type:
+	//
+	//	*FieldRules_Float
+	//	*FieldRules_Double
+	//	*FieldRules_Int32
+	//	*FieldRules_Int64
+	//	*FieldRules_Uint32
+	//	*FieldRules_Uint64
+	//	*FieldRules_Sint32
+	//	*FieldRules_Sint64
+	//	*FieldRules_Fixed32
+	//	*FieldRules_Fixed64
+	//	*FieldRules_Sfixed32
+	//	*FieldRules_Sfixed64
+	//	*FieldRules_Bool
+	//	*FieldRules_String_
+	//	*FieldRules_Bytes
+	//	*FieldRules_Enum
+	//	*FieldRules_Repeated
+	//	*FieldRules_Map
+	//	*FieldRules_Duration
+	//	*FieldRules_Timestamp
+	Type          isFieldRules_Type `protobuf_oneof:"type"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *FieldRules) Reset() {
+	*x = FieldRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *FieldRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FieldRules) ProtoMessage() {}
+
+func (x *FieldRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FieldRules.ProtoReflect.Descriptor instead.
+func (*FieldRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *FieldRules) GetCel() []*Rule {
+	if x != nil {
+		return x.Cel
+	}
+	return nil
+}
+
+func (x *FieldRules) GetRequired() bool {
+	if x != nil {
+		return x.Required
+	}
+	return false
+}
+
+func (x *FieldRules) GetIgnore() IgnoreRule {
+	if x != nil {
+		return x.Ignore
+	}
+	return IgnoreRule_IGNORE_UNSPECIFIED
+}
+
+func (x *FieldRules) GetGroups() []string {
+	if x != nil {
+		return x.Groups
+	}
+	return nil
+}
+
+func (x *FieldRules) GetErrorMessage() string {
+	if x != nil {
+		return x.ErrorMessage
+	}
+	return ""
+}
+
+func (x *FieldRules) GetErrorMessageEn() string {
+	if x != nil {
+		return x.ErrorMessageEn
+	}
+	return ""
+}
+
+func (x *FieldRules) GetRequiredMessage() string {
+	if x != nil {
+		return x.RequiredMessage
+	}
+	return ""
+}
+
+func (x *FieldRules) GetRequiredMessageEn() string {
+	if x != nil {
+		return x.RequiredMessageEn
+	}
+	return ""
+}
+
+func (x *FieldRules) GetType() isFieldRules_Type {
+	if x != nil {
+		return x.Type
+	}
+	return nil
+}
+
+func (x *FieldRules) GetFloat() *FloatRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Float); ok {
+			return x.Float
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetDouble() *DoubleRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Double); ok {
+			return x.Double
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetInt32() *Int32Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Int32); ok {
+			return x.Int32
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetInt64() *Int64Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Int64); ok {
+			return x.Int64
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetUint32() *UInt32Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Uint32); ok {
+			return x.Uint32
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetUint64() *UInt64Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Uint64); ok {
+			return x.Uint64
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetSint32() *SInt32Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Sint32); ok {
+			return x.Sint32
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetSint64() *SInt64Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Sint64); ok {
+			return x.Sint64
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetFixed32() *Fixed32Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Fixed32); ok {
+			return x.Fixed32
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetFixed64() *Fixed64Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Fixed64); ok {
+			return x.Fixed64
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetSfixed32() *SFixed32Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Sfixed32); ok {
+			return x.Sfixed32
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetSfixed64() *SFixed64Rules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Sfixed64); ok {
+			return x.Sfixed64
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetBool() *BoolRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Bool); ok {
+			return x.Bool
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetString_() *StringRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_String_); ok {
+			return x.String_
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetBytes() *BytesRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Bytes); ok {
+			return x.Bytes
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetEnum() *EnumRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Enum); ok {
+			return x.Enum
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetRepeated() *RepeatedRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Repeated); ok {
+			return x.Repeated
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetMap() *MapRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Map); ok {
+			return x.Map
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetDuration() *DurationRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Duration); ok {
+			return x.Duration
+		}
+	}
+	return nil
+}
+
+func (x *FieldRules) GetTimestamp() *TimestampRules {
+	if x != nil {
+		if x, ok := x.Type.(*FieldRules_Timestamp); ok {
+			return x.Timestamp
+		}
+	}
+	return nil
+}
+
+type isFieldRules_Type interface {
+	isFieldRules_Type()
+}
+
+type FieldRules_Float struct {
+	// 数值类型
+	Float *FloatRules `protobuf:"bytes,10,opt,name=float,proto3,oneof"`
+}
+
+type FieldRules_Double struct {
+	Double *DoubleRules `protobuf:"bytes,11,opt,name=double,proto3,oneof"`
+}
+
+type FieldRules_Int32 struct {
+	Int32 *Int32Rules `protobuf:"bytes,12,opt,name=int32,proto3,oneof"`
+}
+
+type FieldRules_Int64 struct {
+	Int64 *Int64Rules `protobuf:"bytes,13,opt,name=int64,proto3,oneof"`
+}
+
+type FieldRules_Uint32 struct {
+	Uint32 *UInt32Rules `protobuf:"bytes,14,opt,name=uint32,proto3,oneof"`
+}
+
+type FieldRules_Uint64 struct {
+	Uint64 *UInt64Rules `protobuf:"bytes,15,opt,name=uint64,proto3,oneof"`
+}
+
+type FieldRules_Sint32 struct {
+	Sint32 *SInt32Rules `protobuf:"bytes,16,opt,name=sint32,proto3,oneof"`
+}
+
+type FieldRules_Sint64 struct {
+	Sint64 *SInt64Rules `protobuf:"bytes,17,opt,name=sint64,proto3,oneof"`
+}
+
+type FieldRules_Fixed32 struct {
+	Fixed32 *Fixed32Rules `protobuf:"bytes,18,opt,name=fixed32,proto3,oneof"`
+}
+
+type FieldRules_Fixed64 struct {
+	Fixed64 *Fixed64Rules `protobuf:"bytes,19,opt,name=fixed64,proto3,oneof"`
+}
+
+type FieldRules_Sfixed32 struct {
+	Sfixed32 *SFixed32Rules `protobuf:"bytes,20,opt,name=sfixed32,proto3,oneof"`
+}
+
+type FieldRules_Sfixed64 struct {
+	Sfixed64 *SFixed64Rules `protobuf:"bytes,21,opt,name=sfixed64,proto3,oneof"`
+}
+
+type FieldRules_Bool struct {
+	// 布尔和字符串
+	Bool *BoolRules `protobuf:"bytes,30,opt,name=bool,proto3,oneof"`
+}
+
+type FieldRules_String_ struct {
+	String_ *StringRules `protobuf:"bytes,31,opt,name=string,proto3,oneof"`
+}
+
+type FieldRules_Bytes struct {
+	Bytes *BytesRules `protobuf:"bytes,32,opt,name=bytes,proto3,oneof"`
+}
+
+type FieldRules_Enum struct {
+	// 复杂类型
+	Enum *EnumRules `protobuf:"bytes,40,opt,name=enum,proto3,oneof"`
+}
+
+type FieldRules_Repeated struct {
+	Repeated *RepeatedRules `protobuf:"bytes,41,opt,name=repeated,proto3,oneof"`
+}
+
+type FieldRules_Map struct {
+	Map *MapRules `protobuf:"bytes,42,opt,name=map,proto3,oneof"`
+}
+
+type FieldRules_Duration struct {
+	// Well-Known Types
+	Duration *DurationRules `protobuf:"bytes,50,opt,name=duration,proto3,oneof"`
+}
+
+type FieldRules_Timestamp struct {
+	Timestamp *TimestampRules `protobuf:"bytes,51,opt,name=timestamp,proto3,oneof"`
+}
+
+func (*FieldRules_Float) isFieldRules_Type() {}
+
+func (*FieldRules_Double) isFieldRules_Type() {}
+
+func (*FieldRules_Int32) isFieldRules_Type() {}
+
+func (*FieldRules_Int64) isFieldRules_Type() {}
+
+func (*FieldRules_Uint32) isFieldRules_Type() {}
+
+func (*FieldRules_Uint64) isFieldRules_Type() {}
+
+func (*FieldRules_Sint32) isFieldRules_Type() {}
+
+func (*FieldRules_Sint64) isFieldRules_Type() {}
+
+func (*FieldRules_Fixed32) isFieldRules_Type() {}
+
+func (*FieldRules_Fixed64) isFieldRules_Type() {}
+
+func (*FieldRules_Sfixed32) isFieldRules_Type() {}
+
+func (*FieldRules_Sfixed64) isFieldRules_Type() {}
+
+func (*FieldRules_Bool) isFieldRules_Type() {}
+
+func (*FieldRules_String_) isFieldRules_Type() {}
+
+func (*FieldRules_Bytes) isFieldRules_Type() {}
+
+func (*FieldRules_Enum) isFieldRules_Type() {}
+
+func (*FieldRules_Repeated) isFieldRules_Type() {}
+
+func (*FieldRules_Map) isFieldRules_Type() {}
+
+func (*FieldRules_Duration) isFieldRules_Type() {}
+
+func (*FieldRules_Timestamp) isFieldRules_Type() {}
+
+// 预定义规则(用于规则扩展)
+type PredefinedRules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Cel           []*Rule                `protobuf:"bytes,1,rep,name=cel,proto3" json:"cel"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *PredefinedRules) Reset() {
+	*x = PredefinedRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *PredefinedRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PredefinedRules) ProtoMessage() {}
+
+func (x *PredefinedRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PredefinedRules.ProtoReflect.Descriptor instead.
+func (*PredefinedRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *PredefinedRules) GetCel() []*Rule {
+	if x != nil {
+		return x.Cel
+	}
+	return nil
+}
+
+// 浮点数验证规则
+type FloatRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 常量值 - 字段必须等于此值
+	Const *float32 `protobuf:"fixed32,1,opt,name=const,proto3,oneof" json:"const"`
+	// 小于
+	Lt *float32 `protobuf:"fixed32,2,opt,name=lt,proto3,oneof" json:"lt"`
+	// 小于等于
+	Lte *float32 `protobuf:"fixed32,3,opt,name=lte,proto3,oneof" json:"lte"`
+	// 大于
+	Gt *float32 `protobuf:"fixed32,4,opt,name=gt,proto3,oneof" json:"gt"`
+	// 大于等于
+	Gte *float32 `protobuf:"fixed32,5,opt,name=gte,proto3,oneof" json:"gte"`
+	// 在值列表中
+	In []float32 `protobuf:"fixed32,6,rep,packed,name=in,proto3" json:"in"`
+	// 不在值列表中
+	NotIn []float32 `protobuf:"fixed32,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	// 是否为有限数(非 NaN/Inf)
+	Finite        *bool `protobuf:"varint,8,opt,name=finite,proto3,oneof" json:"finite"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *FloatRules) Reset() {
+	*x = FloatRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *FloatRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FloatRules) ProtoMessage() {}
+
+func (x *FloatRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FloatRules.ProtoReflect.Descriptor instead.
+func (*FloatRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *FloatRules) GetConst() float32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *FloatRules) GetLt() float32 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *FloatRules) GetLte() float32 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *FloatRules) GetGt() float32 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *FloatRules) GetGte() float32 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *FloatRules) GetIn() []float32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *FloatRules) GetNotIn() []float32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+func (x *FloatRules) GetFinite() bool {
+	if x != nil && x.Finite != nil {
+		return *x.Finite
+	}
+	return false
+}
+
+// 双精度浮点数验证规则
+type DoubleRules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *float64               `protobuf:"fixed64,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *float64               `protobuf:"fixed64,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *float64               `protobuf:"fixed64,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *float64               `protobuf:"fixed64,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *float64               `protobuf:"fixed64,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []float64              `protobuf:"fixed64,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []float64              `protobuf:"fixed64,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	Finite        *bool                  `protobuf:"varint,8,opt,name=finite,proto3,oneof" json:"finite"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *DoubleRules) Reset() {
+	*x = DoubleRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *DoubleRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DoubleRules) ProtoMessage() {}
+
+func (x *DoubleRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DoubleRules.ProtoReflect.Descriptor instead.
+func (*DoubleRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *DoubleRules) GetConst() float64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *DoubleRules) GetLt() float64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *DoubleRules) GetLte() float64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *DoubleRules) GetGt() float64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *DoubleRules) GetGte() float64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *DoubleRules) GetIn() []float64 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *DoubleRules) GetNotIn() []float64 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+func (x *DoubleRules) GetFinite() bool {
+	if x != nil && x.Finite != nil {
+		return *x.Finite
+	}
+	return false
+}
+
+// Int32 验证规则
+type Int32Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int32                 `protobuf:"varint,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *int32                 `protobuf:"varint,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *int32                 `protobuf:"varint,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *int32                 `protobuf:"varint,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *int32                 `protobuf:"varint,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []int32                `protobuf:"varint,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int32                `protobuf:"varint,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Int32Rules) Reset() {
+	*x = Int32Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Int32Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Int32Rules) ProtoMessage() {}
+
+func (x *Int32Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Int32Rules.ProtoReflect.Descriptor instead.
+func (*Int32Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *Int32Rules) GetConst() int32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *Int32Rules) GetLt() int32 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *Int32Rules) GetLte() int32 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *Int32Rules) GetGt() int32 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *Int32Rules) GetGte() int32 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *Int32Rules) GetIn() []int32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *Int32Rules) GetNotIn() []int32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// Int64 验证规则
+type Int64Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int64                 `protobuf:"varint,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *int64                 `protobuf:"varint,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *int64                 `protobuf:"varint,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *int64                 `protobuf:"varint,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *int64                 `protobuf:"varint,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []int64                `protobuf:"varint,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int64                `protobuf:"varint,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Int64Rules) Reset() {
+	*x = Int64Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Int64Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Int64Rules) ProtoMessage() {}
+
+func (x *Int64Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Int64Rules.ProtoReflect.Descriptor instead.
+func (*Int64Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *Int64Rules) GetConst() int64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *Int64Rules) GetLt() int64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *Int64Rules) GetLte() int64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *Int64Rules) GetGt() int64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *Int64Rules) GetGte() int64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *Int64Rules) GetIn() []int64 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *Int64Rules) GetNotIn() []int64 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// UInt32 验证规则
+type UInt32Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *uint32                `protobuf:"varint,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *uint32                `protobuf:"varint,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *uint32                `protobuf:"varint,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *uint32                `protobuf:"varint,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *uint32                `protobuf:"varint,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []uint32               `protobuf:"varint,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []uint32               `protobuf:"varint,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *UInt32Rules) Reset() {
+	*x = UInt32Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *UInt32Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UInt32Rules) ProtoMessage() {}
+
+func (x *UInt32Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UInt32Rules.ProtoReflect.Descriptor instead.
+func (*UInt32Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *UInt32Rules) GetConst() uint32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *UInt32Rules) GetLt() uint32 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *UInt32Rules) GetLte() uint32 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *UInt32Rules) GetGt() uint32 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *UInt32Rules) GetGte() uint32 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *UInt32Rules) GetIn() []uint32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *UInt32Rules) GetNotIn() []uint32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// UInt64 验证规则
+type UInt64Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *uint64                `protobuf:"varint,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *uint64                `protobuf:"varint,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *uint64                `protobuf:"varint,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *uint64                `protobuf:"varint,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *uint64                `protobuf:"varint,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []uint64               `protobuf:"varint,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []uint64               `protobuf:"varint,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *UInt64Rules) Reset() {
+	*x = UInt64Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *UInt64Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UInt64Rules) ProtoMessage() {}
+
+func (x *UInt64Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UInt64Rules.ProtoReflect.Descriptor instead.
+func (*UInt64Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *UInt64Rules) GetConst() uint64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *UInt64Rules) GetLt() uint64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *UInt64Rules) GetLte() uint64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *UInt64Rules) GetGt() uint64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *UInt64Rules) GetGte() uint64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *UInt64Rules) GetIn() []uint64 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *UInt64Rules) GetNotIn() []uint64 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// SInt32 验证规则
+type SInt32Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int32                 `protobuf:"zigzag32,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *int32                 `protobuf:"zigzag32,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *int32                 `protobuf:"zigzag32,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *int32                 `protobuf:"zigzag32,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *int32                 `protobuf:"zigzag32,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []int32                `protobuf:"zigzag32,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int32                `protobuf:"zigzag32,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SInt32Rules) Reset() {
+	*x = SInt32Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SInt32Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SInt32Rules) ProtoMessage() {}
+
+func (x *SInt32Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SInt32Rules.ProtoReflect.Descriptor instead.
+func (*SInt32Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *SInt32Rules) GetConst() int32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *SInt32Rules) GetLt() int32 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *SInt32Rules) GetLte() int32 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *SInt32Rules) GetGt() int32 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *SInt32Rules) GetGte() int32 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *SInt32Rules) GetIn() []int32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *SInt32Rules) GetNotIn() []int32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// SInt64 验证规则
+type SInt64Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int64                 `protobuf:"zigzag64,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *int64                 `protobuf:"zigzag64,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *int64                 `protobuf:"zigzag64,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *int64                 `protobuf:"zigzag64,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *int64                 `protobuf:"zigzag64,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []int64                `protobuf:"zigzag64,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int64                `protobuf:"zigzag64,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SInt64Rules) Reset() {
+	*x = SInt64Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SInt64Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SInt64Rules) ProtoMessage() {}
+
+func (x *SInt64Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SInt64Rules.ProtoReflect.Descriptor instead.
+func (*SInt64Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *SInt64Rules) GetConst() int64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *SInt64Rules) GetLt() int64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *SInt64Rules) GetLte() int64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *SInt64Rules) GetGt() int64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *SInt64Rules) GetGte() int64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *SInt64Rules) GetIn() []int64 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *SInt64Rules) GetNotIn() []int64 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// Fixed32 验证规则
+type Fixed32Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *uint32                `protobuf:"fixed32,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *uint32                `protobuf:"fixed32,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *uint32                `protobuf:"fixed32,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *uint32                `protobuf:"fixed32,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *uint32                `protobuf:"fixed32,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []uint32               `protobuf:"fixed32,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []uint32               `protobuf:"fixed32,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Fixed32Rules) Reset() {
+	*x = Fixed32Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[13]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Fixed32Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Fixed32Rules) ProtoMessage() {}
+
+func (x *Fixed32Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[13]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Fixed32Rules.ProtoReflect.Descriptor instead.
+func (*Fixed32Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *Fixed32Rules) GetConst() uint32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *Fixed32Rules) GetLt() uint32 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *Fixed32Rules) GetLte() uint32 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *Fixed32Rules) GetGt() uint32 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *Fixed32Rules) GetGte() uint32 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *Fixed32Rules) GetIn() []uint32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *Fixed32Rules) GetNotIn() []uint32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// Fixed64 验证规则
+type Fixed64Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *uint64                `protobuf:"fixed64,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *uint64                `protobuf:"fixed64,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *uint64                `protobuf:"fixed64,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *uint64                `protobuf:"fixed64,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *uint64                `protobuf:"fixed64,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []uint64               `protobuf:"fixed64,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []uint64               `protobuf:"fixed64,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Fixed64Rules) Reset() {
+	*x = Fixed64Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[14]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Fixed64Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Fixed64Rules) ProtoMessage() {}
+
+func (x *Fixed64Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[14]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Fixed64Rules.ProtoReflect.Descriptor instead.
+func (*Fixed64Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *Fixed64Rules) GetConst() uint64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *Fixed64Rules) GetLt() uint64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *Fixed64Rules) GetLte() uint64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *Fixed64Rules) GetGt() uint64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *Fixed64Rules) GetGte() uint64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *Fixed64Rules) GetIn() []uint64 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *Fixed64Rules) GetNotIn() []uint64 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// SFixed32 验证规则
+type SFixed32Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int32                 `protobuf:"fixed32,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *int32                 `protobuf:"fixed32,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *int32                 `protobuf:"fixed32,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *int32                 `protobuf:"fixed32,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *int32                 `protobuf:"fixed32,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []int32                `protobuf:"fixed32,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int32                `protobuf:"fixed32,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SFixed32Rules) Reset() {
+	*x = SFixed32Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[15]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SFixed32Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SFixed32Rules) ProtoMessage() {}
+
+func (x *SFixed32Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[15]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SFixed32Rules.ProtoReflect.Descriptor instead.
+func (*SFixed32Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *SFixed32Rules) GetConst() int32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *SFixed32Rules) GetLt() int32 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *SFixed32Rules) GetLte() int32 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *SFixed32Rules) GetGt() int32 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *SFixed32Rules) GetGte() int32 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *SFixed32Rules) GetIn() []int32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *SFixed32Rules) GetNotIn() []int32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// SFixed64 验证规则
+type SFixed64Rules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int64                 `protobuf:"fixed64,1,opt,name=const,proto3,oneof" json:"const"`
+	Lt            *int64                 `protobuf:"fixed64,2,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte           *int64                 `protobuf:"fixed64,3,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt            *int64                 `protobuf:"fixed64,4,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte           *int64                 `protobuf:"fixed64,5,opt,name=gte,proto3,oneof" json:"gte"`
+	In            []int64                `protobuf:"fixed64,6,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int64                `protobuf:"fixed64,7,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SFixed64Rules) Reset() {
+	*x = SFixed64Rules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[16]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SFixed64Rules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SFixed64Rules) ProtoMessage() {}
+
+func (x *SFixed64Rules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[16]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SFixed64Rules.ProtoReflect.Descriptor instead.
+func (*SFixed64Rules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *SFixed64Rules) GetConst() int64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *SFixed64Rules) GetLt() int64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *SFixed64Rules) GetLte() int64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *SFixed64Rules) GetGt() int64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *SFixed64Rules) GetGte() int64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *SFixed64Rules) GetIn() []int64 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *SFixed64Rules) GetNotIn() []int64 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// 布尔值验证规则
+type BoolRules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *bool                  `protobuf:"varint,1,opt,name=const,proto3,oneof" json:"const"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BoolRules) Reset() {
+	*x = BoolRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[17]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BoolRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BoolRules) ProtoMessage() {}
+
+func (x *BoolRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[17]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BoolRules.ProtoReflect.Descriptor instead.
+func (*BoolRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *BoolRules) GetConst() bool {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return false
+}
+
+// 字符串验证规则 - 增强的中文支持
+type StringRules struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// 常量值
+	Const *string `protobuf:"bytes,1,opt,name=const,proto3,oneof" json:"const"`
+	// 长度限制(字符数,非字节数)
+	Len    *uint64 `protobuf:"varint,2,opt,name=len,proto3,oneof" json:"len"`
+	MinLen *uint64 `protobuf:"varint,3,opt,name=min_len,json=minLen,proto3,oneof" json:"min_len"`
+	MaxLen *uint64 `protobuf:"varint,4,opt,name=max_len,json=maxLen,proto3,oneof" json:"max_len"`
+	// 字节长度限制
+	LenBytes *uint64 `protobuf:"varint,5,opt,name=len_bytes,json=lenBytes,proto3,oneof" json:"len_bytes"`
+	MinBytes *uint64 `protobuf:"varint,6,opt,name=min_bytes,json=minBytes,proto3,oneof" json:"min_bytes"`
+	MaxBytes *uint64 `protobuf:"varint,7,opt,name=max_bytes,json=maxBytes,proto3,oneof" json:"max_bytes"`
+	// 模式匹配
+	Pattern *string `protobuf:"bytes,8,opt,name=pattern,proto3,oneof" json:"pattern"` // 正则表达式
+	// 前缀/后缀
+	Prefix *string `protobuf:"bytes,9,opt,name=prefix,proto3,oneof" json:"prefix"`
+	Suffix *string `protobuf:"bytes,10,opt,name=suffix,proto3,oneof" json:"suffix"`
+	// 包含/不包含
+	Contains    *string `protobuf:"bytes,11,opt,name=contains,proto3,oneof" json:"contains"`
+	NotContains *string `protobuf:"bytes,12,opt,name=not_contains,json=notContains,proto3,oneof" json:"not_contains"`
+	// 在值列表中
+	In    []string `protobuf:"bytes,13,rep,name=in,proto3" json:"in"`
+	NotIn []string `protobuf:"bytes,14,rep,name=not_in,json=notIn,proto3" json:"not_in"`
+	// 预定义格式(优化设计 - 更简洁)
+	//
+	// Types that are valid to be assigned to WellKnown:
+	//
+	//	*StringRules_Email
+	//	*StringRules_Hostname
+	//	*StringRules_Ip
+	//	*StringRules_Ipv4
+	//	*StringRules_Ipv6
+	//	*StringRules_Uri
+	//	*StringRules_UriRef
+	//	*StringRules_Uuid
+	//	*StringRules_ChineseMobile
+	//	*StringRules_ChineseIdCard
+	//	*StringRules_ChineseName
+	//	*StringRules_ChinesePostcode
+	WellKnown isStringRules_WellKnown `protobuf_oneof:"well_known"`
+	// 字符类型限制
+	Ascii        *bool `protobuf:"varint,40,opt,name=ascii,proto3,oneof" json:"ascii"`               // 仅 ASCII 字符
+	Printable    *bool `protobuf:"varint,41,opt,name=printable,proto3,oneof" json:"printable"`       // 可打印字符
+	Alpha        *bool `protobuf:"varint,42,opt,name=alpha,proto3,oneof" json:"alpha"`               // 仅字母
+	Alphanumeric *bool `protobuf:"varint,43,opt,name=alphanumeric,proto3,oneof" json:"alphanumeric"` // 字母和数字
+	Numeric      *bool `protobuf:"varint,44,opt,name=numeric,proto3,oneof" json:"numeric"`           // 仅数字
+	// 大小写要求
+	Lowercase     *bool `protobuf:"varint,50,opt,name=lowercase,proto3,oneof" json:"lowercase"` // 仅小写
+	Uppercase     *bool `protobuf:"varint,51,opt,name=uppercase,proto3,oneof" json:"uppercase"` // 仅大写
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *StringRules) Reset() {
+	*x = StringRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[18]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *StringRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StringRules) ProtoMessage() {}
+
+func (x *StringRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[18]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use StringRules.ProtoReflect.Descriptor instead.
+func (*StringRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *StringRules) GetConst() string {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return ""
+}
+
+func (x *StringRules) GetLen() uint64 {
+	if x != nil && x.Len != nil {
+		return *x.Len
+	}
+	return 0
+}
+
+func (x *StringRules) GetMinLen() uint64 {
+	if x != nil && x.MinLen != nil {
+		return *x.MinLen
+	}
+	return 0
+}
+
+func (x *StringRules) GetMaxLen() uint64 {
+	if x != nil && x.MaxLen != nil {
+		return *x.MaxLen
+	}
+	return 0
+}
+
+func (x *StringRules) GetLenBytes() uint64 {
+	if x != nil && x.LenBytes != nil {
+		return *x.LenBytes
+	}
+	return 0
+}
+
+func (x *StringRules) GetMinBytes() uint64 {
+	if x != nil && x.MinBytes != nil {
+		return *x.MinBytes
+	}
+	return 0
+}
+
+func (x *StringRules) GetMaxBytes() uint64 {
+	if x != nil && x.MaxBytes != nil {
+		return *x.MaxBytes
+	}
+	return 0
+}
+
+func (x *StringRules) GetPattern() string {
+	if x != nil && x.Pattern != nil {
+		return *x.Pattern
+	}
+	return ""
+}
+
+func (x *StringRules) GetPrefix() string {
+	if x != nil && x.Prefix != nil {
+		return *x.Prefix
+	}
+	return ""
+}
+
+func (x *StringRules) GetSuffix() string {
+	if x != nil && x.Suffix != nil {
+		return *x.Suffix
+	}
+	return ""
+}
+
+func (x *StringRules) GetContains() string {
+	if x != nil && x.Contains != nil {
+		return *x.Contains
+	}
+	return ""
+}
+
+func (x *StringRules) GetNotContains() string {
+	if x != nil && x.NotContains != nil {
+		return *x.NotContains
+	}
+	return ""
+}
+
+func (x *StringRules) GetIn() []string {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *StringRules) GetNotIn() []string {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+func (x *StringRules) GetWellKnown() isStringRules_WellKnown {
+	if x != nil {
+		return x.WellKnown
+	}
+	return nil
+}
+
+func (x *StringRules) GetEmail() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Email); ok {
+			return x.Email
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetHostname() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Hostname); ok {
+			return x.Hostname
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetIp() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Ip); ok {
+			return x.Ip
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetIpv4() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Ipv4); ok {
+			return x.Ipv4
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetIpv6() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Ipv6); ok {
+			return x.Ipv6
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetUri() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Uri); ok {
+			return x.Uri
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetUriRef() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_UriRef); ok {
+			return x.UriRef
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetUuid() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_Uuid); ok {
+			return x.Uuid
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetChineseMobile() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_ChineseMobile); ok {
+			return x.ChineseMobile
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetChineseIdCard() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_ChineseIdCard); ok {
+			return x.ChineseIdCard
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetChineseName() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_ChineseName); ok {
+			return x.ChineseName
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetChinesePostcode() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*StringRules_ChinesePostcode); ok {
+			return x.ChinesePostcode
+		}
+	}
+	return false
+}
+
+func (x *StringRules) GetAscii() bool {
+	if x != nil && x.Ascii != nil {
+		return *x.Ascii
+	}
+	return false
+}
+
+func (x *StringRules) GetPrintable() bool {
+	if x != nil && x.Printable != nil {
+		return *x.Printable
+	}
+	return false
+}
+
+func (x *StringRules) GetAlpha() bool {
+	if x != nil && x.Alpha != nil {
+		return *x.Alpha
+	}
+	return false
+}
+
+func (x *StringRules) GetAlphanumeric() bool {
+	if x != nil && x.Alphanumeric != nil {
+		return *x.Alphanumeric
+	}
+	return false
+}
+
+func (x *StringRules) GetNumeric() bool {
+	if x != nil && x.Numeric != nil {
+		return *x.Numeric
+	}
+	return false
+}
+
+func (x *StringRules) GetLowercase() bool {
+	if x != nil && x.Lowercase != nil {
+		return *x.Lowercase
+	}
+	return false
+}
+
+func (x *StringRules) GetUppercase() bool {
+	if x != nil && x.Uppercase != nil {
+		return *x.Uppercase
+	}
+	return false
+}
+
+type isStringRules_WellKnown interface {
+	isStringRules_WellKnown()
+}
+
+type StringRules_Email struct {
+	Email bool `protobuf:"varint,20,opt,name=email,proto3,oneof"` // 邮箱格式
+}
+
+type StringRules_Hostname struct {
+	Hostname bool `protobuf:"varint,21,opt,name=hostname,proto3,oneof"` // 主机名
+}
+
+type StringRules_Ip struct {
+	Ip bool `protobuf:"varint,22,opt,name=ip,proto3,oneof"` // IP 地址(v4/v6)
+}
+
+type StringRules_Ipv4 struct {
+	Ipv4 bool `protobuf:"varint,23,opt,name=ipv4,proto3,oneof"` // IPv4
+}
+
+type StringRules_Ipv6 struct {
+	Ipv6 bool `protobuf:"varint,24,opt,name=ipv6,proto3,oneof"` // IPv6
+}
+
+type StringRules_Uri struct {
+	Uri bool `protobuf:"varint,25,opt,name=uri,proto3,oneof"` // URI
+}
+
+type StringRules_UriRef struct {
+	UriRef bool `protobuf:"varint,26,opt,name=uri_ref,json=uriRef,proto3,oneof"` // URI 引用
+}
+
+type StringRules_Uuid struct {
+	Uuid bool `protobuf:"varint,27,opt,name=uuid,proto3,oneof"` // UUID
+}
+
+type StringRules_ChineseMobile struct {
+	// 中文业务格式 - 这是优化点!
+	ChineseMobile bool `protobuf:"varint,30,opt,name=chinese_mobile,json=chineseMobile,proto3,oneof"` // 中国手机号
+}
+
+type StringRules_ChineseIdCard struct {
+	ChineseIdCard bool `protobuf:"varint,31,opt,name=chinese_id_card,json=chineseIdCard,proto3,oneof"` // 中国身份证号
+}
+
+type StringRules_ChineseName struct {
+	ChineseName bool `protobuf:"varint,32,opt,name=chinese_name,json=chineseName,proto3,oneof"` // 中文姓名
+}
+
+type StringRules_ChinesePostcode struct {
+	ChinesePostcode bool `protobuf:"varint,33,opt,name=chinese_postcode,json=chinesePostcode,proto3,oneof"` // 中国邮政编码
+}
+
+func (*StringRules_Email) isStringRules_WellKnown() {}
+
+func (*StringRules_Hostname) isStringRules_WellKnown() {}
+
+func (*StringRules_Ip) isStringRules_WellKnown() {}
+
+func (*StringRules_Ipv4) isStringRules_WellKnown() {}
+
+func (*StringRules_Ipv6) isStringRules_WellKnown() {}
+
+func (*StringRules_Uri) isStringRules_WellKnown() {}
+
+func (*StringRules_UriRef) isStringRules_WellKnown() {}
+
+func (*StringRules_Uuid) isStringRules_WellKnown() {}
+
+func (*StringRules_ChineseMobile) isStringRules_WellKnown() {}
+
+func (*StringRules_ChineseIdCard) isStringRules_WellKnown() {}
+
+func (*StringRules_ChineseName) isStringRules_WellKnown() {}
+
+func (*StringRules_ChinesePostcode) isStringRules_WellKnown() {}
+
+// 字节数组验证规则
+type BytesRules struct {
+	state    protoimpl.MessageState `protogen:"open.v1"`
+	Const    []byte                 `protobuf:"bytes,1,opt,name=const,proto3,oneof" json:"const"`
+	Len      *uint64                `protobuf:"varint,2,opt,name=len,proto3,oneof" json:"len"`
+	MinLen   *uint64                `protobuf:"varint,3,opt,name=min_len,json=minLen,proto3,oneof" json:"min_len"`
+	MaxLen   *uint64                `protobuf:"varint,4,opt,name=max_len,json=maxLen,proto3,oneof" json:"max_len"`
+	Pattern  []byte                 `protobuf:"bytes,5,opt,name=pattern,proto3,oneof" json:"pattern"`
+	Prefix   []byte                 `protobuf:"bytes,6,opt,name=prefix,proto3,oneof" json:"prefix"`
+	Suffix   []byte                 `protobuf:"bytes,7,opt,name=suffix,proto3,oneof" json:"suffix"`
+	Contains []byte                 `protobuf:"bytes,8,opt,name=contains,proto3,oneof" json:"contains"`
+	In       [][]byte               `protobuf:"bytes,9,rep,name=in,proto3" json:"in"`
+	NotIn    [][]byte               `protobuf:"bytes,10,rep,name=not_in,json=notIn,proto3" json:"not_in"`
+	// Well-known 格式
+	//
+	// Types that are valid to be assigned to WellKnown:
+	//
+	//	*BytesRules_Ip
+	//	*BytesRules_Ipv4
+	//	*BytesRules_Ipv6
+	WellKnown     isBytesRules_WellKnown `protobuf_oneof:"well_known"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BytesRules) Reset() {
+	*x = BytesRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[19]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BytesRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BytesRules) ProtoMessage() {}
+
+func (x *BytesRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[19]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BytesRules.ProtoReflect.Descriptor instead.
+func (*BytesRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *BytesRules) GetConst() []byte {
+	if x != nil {
+		return x.Const
+	}
+	return nil
+}
+
+func (x *BytesRules) GetLen() uint64 {
+	if x != nil && x.Len != nil {
+		return *x.Len
+	}
+	return 0
+}
+
+func (x *BytesRules) GetMinLen() uint64 {
+	if x != nil && x.MinLen != nil {
+		return *x.MinLen
+	}
+	return 0
+}
+
+func (x *BytesRules) GetMaxLen() uint64 {
+	if x != nil && x.MaxLen != nil {
+		return *x.MaxLen
+	}
+	return 0
+}
+
+func (x *BytesRules) GetPattern() []byte {
+	if x != nil {
+		return x.Pattern
+	}
+	return nil
+}
+
+func (x *BytesRules) GetPrefix() []byte {
+	if x != nil {
+		return x.Prefix
+	}
+	return nil
+}
+
+func (x *BytesRules) GetSuffix() []byte {
+	if x != nil {
+		return x.Suffix
+	}
+	return nil
+}
+
+func (x *BytesRules) GetContains() []byte {
+	if x != nil {
+		return x.Contains
+	}
+	return nil
+}
+
+func (x *BytesRules) GetIn() [][]byte {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *BytesRules) GetNotIn() [][]byte {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+func (x *BytesRules) GetWellKnown() isBytesRules_WellKnown {
+	if x != nil {
+		return x.WellKnown
+	}
+	return nil
+}
+
+func (x *BytesRules) GetIp() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*BytesRules_Ip); ok {
+			return x.Ip
+		}
+	}
+	return false
+}
+
+func (x *BytesRules) GetIpv4() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*BytesRules_Ipv4); ok {
+			return x.Ipv4
+		}
+	}
+	return false
+}
+
+func (x *BytesRules) GetIpv6() bool {
+	if x != nil {
+		if x, ok := x.WellKnown.(*BytesRules_Ipv6); ok {
+			return x.Ipv6
+		}
+	}
+	return false
+}
+
+type isBytesRules_WellKnown interface {
+	isBytesRules_WellKnown()
+}
+
+type BytesRules_Ip struct {
+	Ip bool `protobuf:"varint,20,opt,name=ip,proto3,oneof"`
+}
+
+type BytesRules_Ipv4 struct {
+	Ipv4 bool `protobuf:"varint,21,opt,name=ipv4,proto3,oneof"`
+}
+
+type BytesRules_Ipv6 struct {
+	Ipv6 bool `protobuf:"varint,22,opt,name=ipv6,proto3,oneof"`
+}
+
+func (*BytesRules_Ip) isBytesRules_WellKnown() {}
+
+func (*BytesRules_Ipv4) isBytesRules_WellKnown() {}
+
+func (*BytesRules_Ipv6) isBytesRules_WellKnown() {}
+
+// 枚举验证规则
+type EnumRules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Const         *int32                 `protobuf:"varint,1,opt,name=const,proto3,oneof" json:"const"`
+	DefinedOnly   *bool                  `protobuf:"varint,2,opt,name=defined_only,json=definedOnly,proto3,oneof" json:"defined_only"` // 仅允许已定义的枚举值
+	In            []int32                `protobuf:"varint,3,rep,packed,name=in,proto3" json:"in"`
+	NotIn         []int32                `protobuf:"varint,4,rep,packed,name=not_in,json=notIn,proto3" json:"not_in"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *EnumRules) Reset() {
+	*x = EnumRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[20]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *EnumRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EnumRules) ProtoMessage() {}
+
+func (x *EnumRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[20]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EnumRules.ProtoReflect.Descriptor instead.
+func (*EnumRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *EnumRules) GetConst() int32 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *EnumRules) GetDefinedOnly() bool {
+	if x != nil && x.DefinedOnly != nil {
+		return *x.DefinedOnly
+	}
+	return false
+}
+
+func (x *EnumRules) GetIn() []int32 {
+	if x != nil {
+		return x.In
+	}
+	return nil
+}
+
+func (x *EnumRules) GetNotIn() []int32 {
+	if x != nil {
+		return x.NotIn
+	}
+	return nil
+}
+
+// 重复字段验证规则
+type RepeatedRules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	MinItems      *uint64                `protobuf:"varint,1,opt,name=min_items,json=minItems,proto3,oneof" json:"min_items"` // 最小元素数
+	MaxItems      *uint64                `protobuf:"varint,2,opt,name=max_items,json=maxItems,proto3,oneof" json:"max_items"` // 最大元素数
+	Unique        *bool                  `protobuf:"varint,3,opt,name=unique,proto3,oneof" json:"unique"`                     // 元素必须唯一
+	Items         *FieldRules            `protobuf:"bytes,4,opt,name=items,proto3" json:"items"`                              // 元素验证规则
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *RepeatedRules) Reset() {
+	*x = RepeatedRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[21]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *RepeatedRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RepeatedRules) ProtoMessage() {}
+
+func (x *RepeatedRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[21]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RepeatedRules.ProtoReflect.Descriptor instead.
+func (*RepeatedRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *RepeatedRules) GetMinItems() uint64 {
+	if x != nil && x.MinItems != nil {
+		return *x.MinItems
+	}
+	return 0
+}
+
+func (x *RepeatedRules) GetMaxItems() uint64 {
+	if x != nil && x.MaxItems != nil {
+		return *x.MaxItems
+	}
+	return 0
+}
+
+func (x *RepeatedRules) GetUnique() bool {
+	if x != nil && x.Unique != nil {
+		return *x.Unique
+	}
+	return false
+}
+
+func (x *RepeatedRules) GetItems() *FieldRules {
+	if x != nil {
+		return x.Items
+	}
+	return nil
+}
+
+// Map 验证规则
+type MapRules struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	MinPairs      *uint64                `protobuf:"varint,1,opt,name=min_pairs,json=minPairs,proto3,oneof" json:"min_pairs"` // 最小键值对数
+	MaxPairs      *uint64                `protobuf:"varint,2,opt,name=max_pairs,json=maxPairs,proto3,oneof" json:"max_pairs"` // 最大键值对数
+	Keys          *FieldRules            `protobuf:"bytes,3,opt,name=keys,proto3" json:"keys"`                                // 键验证规则
+	Values        *FieldRules            `protobuf:"bytes,4,opt,name=values,proto3" json:"values"`                            // 值验证规则
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *MapRules) Reset() {
+	*x = MapRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[22]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *MapRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MapRules) ProtoMessage() {}
+
+func (x *MapRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[22]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MapRules.ProtoReflect.Descriptor instead.
+func (*MapRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *MapRules) GetMinPairs() uint64 {
+	if x != nil && x.MinPairs != nil {
+		return *x.MinPairs
+	}
+	return 0
+}
+
+func (x *MapRules) GetMaxPairs() uint64 {
+	if x != nil && x.MaxPairs != nil {
+		return *x.MaxPairs
+	}
+	return 0
+}
+
+func (x *MapRules) GetKeys() *FieldRules {
+	if x != nil {
+		return x.Keys
+	}
+	return nil
+}
+
+func (x *MapRules) GetValues() *FieldRules {
+	if x != nil {
+		return x.Values
+	}
+	return nil
+}
+
+// Duration 验证规则
+type DurationRules struct {
+	state    protoimpl.MessageState `protogen:"open.v1"`
+	Required *bool                  `protobuf:"varint,1,opt,name=required,proto3,oneof" json:"required"`
+	// Duration 常量
+	ConstSeconds *int64 `protobuf:"varint,2,opt,name=const_seconds,json=constSeconds,proto3,oneof" json:"const_seconds"`
+	ConstNanos   *int32 `protobuf:"varint,3,opt,name=const_nanos,json=constNanos,proto3,oneof" json:"const_nanos"`
+	// 范围限制
+	LtSeconds  *int64 `protobuf:"varint,4,opt,name=lt_seconds,json=ltSeconds,proto3,oneof" json:"lt_seconds"`
+	LteSeconds *int64 `protobuf:"varint,5,opt,name=lte_seconds,json=lteSeconds,proto3,oneof" json:"lte_seconds"`
+	GtSeconds  *int64 `protobuf:"varint,6,opt,name=gt_seconds,json=gtSeconds,proto3,oneof" json:"gt_seconds"`
+	GteSeconds *int64 `protobuf:"varint,7,opt,name=gte_seconds,json=gteSeconds,proto3,oneof" json:"gte_seconds"`
+	// 在值列表中
+	InSeconds     []int64 `protobuf:"varint,8,rep,packed,name=in_seconds,json=inSeconds,proto3" json:"in_seconds"`
+	NotInSeconds  []int64 `protobuf:"varint,9,rep,packed,name=not_in_seconds,json=notInSeconds,proto3" json:"not_in_seconds"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *DurationRules) Reset() {
+	*x = DurationRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[23]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *DurationRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DurationRules) ProtoMessage() {}
+
+func (x *DurationRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[23]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DurationRules.ProtoReflect.Descriptor instead.
+func (*DurationRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *DurationRules) GetRequired() bool {
+	if x != nil && x.Required != nil {
+		return *x.Required
+	}
+	return false
+}
+
+func (x *DurationRules) GetConstSeconds() int64 {
+	if x != nil && x.ConstSeconds != nil {
+		return *x.ConstSeconds
+	}
+	return 0
+}
+
+func (x *DurationRules) GetConstNanos() int32 {
+	if x != nil && x.ConstNanos != nil {
+		return *x.ConstNanos
+	}
+	return 0
+}
+
+func (x *DurationRules) GetLtSeconds() int64 {
+	if x != nil && x.LtSeconds != nil {
+		return *x.LtSeconds
+	}
+	return 0
+}
+
+func (x *DurationRules) GetLteSeconds() int64 {
+	if x != nil && x.LteSeconds != nil {
+		return *x.LteSeconds
+	}
+	return 0
+}
+
+func (x *DurationRules) GetGtSeconds() int64 {
+	if x != nil && x.GtSeconds != nil {
+		return *x.GtSeconds
+	}
+	return 0
+}
+
+func (x *DurationRules) GetGteSeconds() int64 {
+	if x != nil && x.GteSeconds != nil {
+		return *x.GteSeconds
+	}
+	return 0
+}
+
+func (x *DurationRules) GetInSeconds() []int64 {
+	if x != nil {
+		return x.InSeconds
+	}
+	return nil
+}
+
+func (x *DurationRules) GetNotInSeconds() []int64 {
+	if x != nil {
+		return x.NotInSeconds
+	}
+	return nil
+}
+
+// Timestamp 验证规则
+type TimestampRules struct {
+	state    protoimpl.MessageState `protogen:"open.v1"`
+	Required *bool                  `protobuf:"varint,1,opt,name=required,proto3,oneof" json:"required"`
+	// Timestamp 常量(Unix 秒)
+	Const *int64 `protobuf:"varint,2,opt,name=const,proto3,oneof" json:"const"`
+	// 范围限制
+	Lt  *int64 `protobuf:"varint,3,opt,name=lt,proto3,oneof" json:"lt"`
+	Lte *int64 `protobuf:"varint,4,opt,name=lte,proto3,oneof" json:"lte"`
+	Gt  *int64 `protobuf:"varint,5,opt,name=gt,proto3,oneof" json:"gt"`
+	Gte *int64 `protobuf:"varint,6,opt,name=gte,proto3,oneof" json:"gte"`
+	// 相对时间限制
+	LtNow *bool `protobuf:"varint,7,opt,name=lt_now,json=ltNow,proto3,oneof" json:"lt_now"` // 必须在当前时间之前
+	GtNow *bool `protobuf:"varint,8,opt,name=gt_now,json=gtNow,proto3,oneof" json:"gt_now"` // 必须在当前时间之后
+	// 时间范围(从现在开始的偏移量,秒)
+	WithinSeconds *int64 `protobuf:"varint,9,opt,name=within_seconds,json=withinSeconds,proto3,oneof" json:"within_seconds"` // 必须在现在的 N 秒内
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *TimestampRules) Reset() {
+	*x = TimestampRules{}
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[24]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *TimestampRules) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TimestampRules) ProtoMessage() {}
+
+func (x *TimestampRules) ProtoReflect() protoreflect.Message {
+	mi := &file_kuban_api_validate_validate_proto_msgTypes[24]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TimestampRules.ProtoReflect.Descriptor instead.
+func (*TimestampRules) Descriptor() ([]byte, []int) {
+	return file_kuban_api_validate_validate_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *TimestampRules) GetRequired() bool {
+	if x != nil && x.Required != nil {
+		return *x.Required
+	}
+	return false
+}
+
+func (x *TimestampRules) GetConst() int64 {
+	if x != nil && x.Const != nil {
+		return *x.Const
+	}
+	return 0
+}
+
+func (x *TimestampRules) GetLt() int64 {
+	if x != nil && x.Lt != nil {
+		return *x.Lt
+	}
+	return 0
+}
+
+func (x *TimestampRules) GetLte() int64 {
+	if x != nil && x.Lte != nil {
+		return *x.Lte
+	}
+	return 0
+}
+
+func (x *TimestampRules) GetGt() int64 {
+	if x != nil && x.Gt != nil {
+		return *x.Gt
+	}
+	return 0
+}
+
+func (x *TimestampRules) GetGte() int64 {
+	if x != nil && x.Gte != nil {
+		return *x.Gte
+	}
+	return 0
+}
+
+func (x *TimestampRules) GetLtNow() bool {
+	if x != nil && x.LtNow != nil {
+		return *x.LtNow
+	}
+	return false
+}
+
+func (x *TimestampRules) GetGtNow() bool {
+	if x != nil && x.GtNow != nil {
+		return *x.GtNow
+	}
+	return false
+}
+
+func (x *TimestampRules) GetWithinSeconds() int64 {
+	if x != nil && x.WithinSeconds != nil {
+		return *x.WithinSeconds
+	}
+	return 0
+}
+
+var file_kuban_api_validate_validate_proto_extTypes = []protoimpl.ExtensionInfo{
+	{
+		ExtendedType:  (*descriptorpb.MessageOptions)(nil),
+		ExtensionType: (*MessageRules)(nil),
+		Field:         10100,
+		Name:          "kuban.api.validate.message",
+		Tag:           "bytes,10100,opt,name=message",
+		Filename:      "kuban/api/validate/validate.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.FieldOptions)(nil),
+		ExtensionType: (*FieldRules)(nil),
+		Field:         10100,
+		Name:          "kuban.api.validate.field",
+		Tag:           "bytes,10100,opt,name=field",
+		Filename:      "kuban/api/validate/validate.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.FieldOptions)(nil),
+		ExtensionType: (*PredefinedRules)(nil),
+		Field:         10101,
+		Name:          "kuban.api.validate.predefined",
+		Tag:           "bytes,10101,opt,name=predefined",
+		Filename:      "kuban/api/validate/validate.proto",
+	},
+	{
+		ExtendedType:  (*descriptorpb.OneofOptions)(nil),
+		ExtensionType: (*OneofRules)(nil),
+		Field:         10100,
+		Name:          "kuban.api.validate.oneof",
+		Tag:           "bytes,10100,opt,name=oneof",
+		Filename:      "kuban/api/validate/validate.proto",
+	},
+}
+
+// Extension fields to descriptorpb.MessageOptions.
+var (
+	// 消息级别的验证规则
+	//
+	// optional kuban.api.validate.MessageRules message = 10100;
+	E_Message = &file_kuban_api_validate_validate_proto_extTypes[0]
+)
+
+// Extension fields to descriptorpb.FieldOptions.
+var (
+	// 字段级别的验证规则
+	//
+	// optional kuban.api.validate.FieldRules field = 10100;
+	E_Field = &file_kuban_api_validate_validate_proto_extTypes[1]
+	// 预定义规则引用(用于扩展)
+	//
+	// optional kuban.api.validate.PredefinedRules predefined = 10101;
+	E_Predefined = &file_kuban_api_validate_validate_proto_extTypes[2]
+)
+
+// Extension fields to descriptorpb.OneofOptions.
+var (
+	// oneof 级别的验证规则
+	//
+	// optional kuban.api.validate.OneofRules oneof = 10100;
+	E_Oneof = &file_kuban_api_validate_validate_proto_extTypes[3]
+)
+
+var File_kuban_api_validate_validate_proto protoreflect.FileDescriptor
+
+const file_kuban_api_validate_validate_proto_rawDesc = "" +
+	"\n" +
+	"!kuban/api/validate/validate.proto\x12\x12kuban.api.validate\x1a google/protobuf/descriptor.proto\"o\n" +
+	"\x04Rule\x12\x0e\n" +
+	"\x02id\x18\x01 \x01(\tR\x02id\x12\x18\n" +
+	"\amessage\x18\x02 \x01(\tR\amessage\x12\x1d\n" +
+	"\n" +
+	"message_en\x18\x03 \x01(\tR\tmessageEn\x12\x1e\n" +
+	"\n" +
+	"expression\x18\x04 \x01(\tR\n" +
+	"expression\"n\n" +
+	"\fMessageRules\x12*\n" +
+	"\x03cel\x18\x01 \x03(\v2\x18.kuban.api.validate.RuleR\x03cel\x12\x1a\n" +
+	"\bdisabled\x18\x02 \x01(\bR\bdisabled\x12\x16\n" +
+	"\x06groups\x18\x03 \x03(\tR\x06groups\"(\n" +
+	"\n" +
+	"OneofRules\x12\x1a\n" +
+	"\brequired\x18\x01 \x01(\bR\brequired\"\xf8\v\n" +
+	"\n" +
+	"FieldRules\x12*\n" +
+	"\x03cel\x18\x01 \x03(\v2\x18.kuban.api.validate.RuleR\x03cel\x12\x1a\n" +
+	"\brequired\x18\x02 \x01(\bR\brequired\x126\n" +
+	"\x06ignore\x18\x03 \x01(\x0e2\x1e.kuban.api.validate.IgnoreRuleR\x06ignore\x12\x16\n" +
+	"\x06groups\x18\x04 \x03(\tR\x06groups\x12#\n" +
+	"\rerror_message\x18\x05 \x01(\tR\ferrorMessage\x12(\n" +
+	"\x10error_message_en\x18\x06 \x01(\tR\x0eerrorMessageEn\x12)\n" +
+	"\x10required_message\x18\a \x01(\tR\x0frequiredMessage\x12.\n" +
+	"\x13required_message_en\x18\b \x01(\tR\x11requiredMessageEn\x126\n" +
+	"\x05float\x18\n" +
+	" \x01(\v2\x1e.kuban.api.validate.FloatRulesH\x00R\x05float\x129\n" +
+	"\x06double\x18\v \x01(\v2\x1f.kuban.api.validate.DoubleRulesH\x00R\x06double\x126\n" +
+	"\x05int32\x18\f \x01(\v2\x1e.kuban.api.validate.Int32RulesH\x00R\x05int32\x126\n" +
+	"\x05int64\x18\r \x01(\v2\x1e.kuban.api.validate.Int64RulesH\x00R\x05int64\x129\n" +
+	"\x06uint32\x18\x0e \x01(\v2\x1f.kuban.api.validate.UInt32RulesH\x00R\x06uint32\x129\n" +
+	"\x06uint64\x18\x0f \x01(\v2\x1f.kuban.api.validate.UInt64RulesH\x00R\x06uint64\x129\n" +
+	"\x06sint32\x18\x10 \x01(\v2\x1f.kuban.api.validate.SInt32RulesH\x00R\x06sint32\x129\n" +
+	"\x06sint64\x18\x11 \x01(\v2\x1f.kuban.api.validate.SInt64RulesH\x00R\x06sint64\x12<\n" +
+	"\afixed32\x18\x12 \x01(\v2 .kuban.api.validate.Fixed32RulesH\x00R\afixed32\x12<\n" +
+	"\afixed64\x18\x13 \x01(\v2 .kuban.api.validate.Fixed64RulesH\x00R\afixed64\x12?\n" +
+	"\bsfixed32\x18\x14 \x01(\v2!.kuban.api.validate.SFixed32RulesH\x00R\bsfixed32\x12?\n" +
+	"\bsfixed64\x18\x15 \x01(\v2!.kuban.api.validate.SFixed64RulesH\x00R\bsfixed64\x123\n" +
+	"\x04bool\x18\x1e \x01(\v2\x1d.kuban.api.validate.BoolRulesH\x00R\x04bool\x129\n" +
+	"\x06string\x18\x1f \x01(\v2\x1f.kuban.api.validate.StringRulesH\x00R\x06string\x126\n" +
+	"\x05bytes\x18  \x01(\v2\x1e.kuban.api.validate.BytesRulesH\x00R\x05bytes\x123\n" +
+	"\x04enum\x18( \x01(\v2\x1d.kuban.api.validate.EnumRulesH\x00R\x04enum\x12?\n" +
+	"\brepeated\x18) \x01(\v2!.kuban.api.validate.RepeatedRulesH\x00R\brepeated\x120\n" +
+	"\x03map\x18* \x01(\v2\x1c.kuban.api.validate.MapRulesH\x00R\x03map\x12?\n" +
+	"\bduration\x182 \x01(\v2!.kuban.api.validate.DurationRulesH\x00R\bduration\x12B\n" +
+	"\ttimestamp\x183 \x01(\v2\".kuban.api.validate.TimestampRulesH\x00R\ttimestampB\x06\n" +
+	"\x04type\"=\n" +
+	"\x0fPredefinedRules\x12*\n" +
+	"\x03cel\x18\x01 \x03(\v2\x18.kuban.api.validate.RuleR\x03cel\"\xf6\x01\n" +
+	"\n" +
+	"FloatRules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x02H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x02H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x02H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x02H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x02H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x02R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x02R\x05notIn\x12\x1b\n" +
+	"\x06finite\x18\b \x01(\bH\x05R\x06finite\x88\x01\x01B\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gteB\t\n" +
+	"\a_finite\"\xf7\x01\n" +
+	"\vDoubleRules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x01H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x01H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x01H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x01H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x01H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x01R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x01R\x05notIn\x12\x1b\n" +
+	"\x06finite\x18\b \x01(\bH\x05R\x06finite\x88\x01\x01B\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gteB\t\n" +
+	"\a_finite\"\xce\x01\n" +
+	"\n" +
+	"Int32Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x05H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x05H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x05H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x05H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x05H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x05R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x05R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xce\x01\n" +
+	"\n" +
+	"Int64Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x03H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x03H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x03H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x03H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x03H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x03R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x03R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xcf\x01\n" +
+	"\vUInt32Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\rH\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\rH\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\rH\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\rH\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\rH\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\rR\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\rR\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xcf\x01\n" +
+	"\vUInt64Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x04H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x04H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x04H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x04H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x04H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x04R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x04R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xcf\x01\n" +
+	"\vSInt32Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x11H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x11H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x11H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x11H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x11H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x11R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x11R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xcf\x01\n" +
+	"\vSInt64Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x12H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x12H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x12H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x12H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x12H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x12R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x12R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xd0\x01\n" +
+	"\fFixed32Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\aH\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\aH\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\aH\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\aH\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\aH\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\aR\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\aR\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xd0\x01\n" +
+	"\fFixed64Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x06H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x06H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x06H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x06H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x06H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x06R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x06R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xd1\x01\n" +
+	"\rSFixed32Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x0fH\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x0fH\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x0fH\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x0fH\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x0fH\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x0fR\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x0fR\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"\xd1\x01\n" +
+	"\rSFixed64Rules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x10H\x00R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x02 \x01(\x10H\x01R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x03 \x01(\x10H\x02R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x04 \x01(\x10H\x03R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x05 \x01(\x10H\x04R\x03gte\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x06 \x03(\x10R\x02in\x12\x15\n" +
+	"\x06not_in\x18\a \x03(\x10R\x05notInB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gte\"0\n" +
+	"\tBoolRules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\bH\x00R\x05const\x88\x01\x01B\b\n" +
+	"\x06_const\"\xec\t\n" +
+	"\vStringRules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\tH\x01R\x05const\x88\x01\x01\x12\x15\n" +
+	"\x03len\x18\x02 \x01(\x04H\x02R\x03len\x88\x01\x01\x12\x1c\n" +
+	"\amin_len\x18\x03 \x01(\x04H\x03R\x06minLen\x88\x01\x01\x12\x1c\n" +
+	"\amax_len\x18\x04 \x01(\x04H\x04R\x06maxLen\x88\x01\x01\x12 \n" +
+	"\tlen_bytes\x18\x05 \x01(\x04H\x05R\blenBytes\x88\x01\x01\x12 \n" +
+	"\tmin_bytes\x18\x06 \x01(\x04H\x06R\bminBytes\x88\x01\x01\x12 \n" +
+	"\tmax_bytes\x18\a \x01(\x04H\aR\bmaxBytes\x88\x01\x01\x12\x1d\n" +
+	"\apattern\x18\b \x01(\tH\bR\apattern\x88\x01\x01\x12\x1b\n" +
+	"\x06prefix\x18\t \x01(\tH\tR\x06prefix\x88\x01\x01\x12\x1b\n" +
+	"\x06suffix\x18\n" +
+	" \x01(\tH\n" +
+	"R\x06suffix\x88\x01\x01\x12\x1f\n" +
+	"\bcontains\x18\v \x01(\tH\vR\bcontains\x88\x01\x01\x12&\n" +
+	"\fnot_contains\x18\f \x01(\tH\fR\vnotContains\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\r \x03(\tR\x02in\x12\x15\n" +
+	"\x06not_in\x18\x0e \x03(\tR\x05notIn\x12\x16\n" +
+	"\x05email\x18\x14 \x01(\bH\x00R\x05email\x12\x1c\n" +
+	"\bhostname\x18\x15 \x01(\bH\x00R\bhostname\x12\x10\n" +
+	"\x02ip\x18\x16 \x01(\bH\x00R\x02ip\x12\x14\n" +
+	"\x04ipv4\x18\x17 \x01(\bH\x00R\x04ipv4\x12\x14\n" +
+	"\x04ipv6\x18\x18 \x01(\bH\x00R\x04ipv6\x12\x12\n" +
+	"\x03uri\x18\x19 \x01(\bH\x00R\x03uri\x12\x19\n" +
+	"\auri_ref\x18\x1a \x01(\bH\x00R\x06uriRef\x12\x14\n" +
+	"\x04uuid\x18\x1b \x01(\bH\x00R\x04uuid\x12'\n" +
+	"\x0echinese_mobile\x18\x1e \x01(\bH\x00R\rchineseMobile\x12(\n" +
+	"\x0fchinese_id_card\x18\x1f \x01(\bH\x00R\rchineseIdCard\x12#\n" +
+	"\fchinese_name\x18  \x01(\bH\x00R\vchineseName\x12+\n" +
+	"\x10chinese_postcode\x18! \x01(\bH\x00R\x0fchinesePostcode\x12\x19\n" +
+	"\x05ascii\x18( \x01(\bH\rR\x05ascii\x88\x01\x01\x12!\n" +
+	"\tprintable\x18) \x01(\bH\x0eR\tprintable\x88\x01\x01\x12\x19\n" +
+	"\x05alpha\x18* \x01(\bH\x0fR\x05alpha\x88\x01\x01\x12'\n" +
+	"\falphanumeric\x18+ \x01(\bH\x10R\falphanumeric\x88\x01\x01\x12\x1d\n" +
+	"\anumeric\x18, \x01(\bH\x11R\anumeric\x88\x01\x01\x12!\n" +
+	"\tlowercase\x182 \x01(\bH\x12R\tlowercase\x88\x01\x01\x12!\n" +
+	"\tuppercase\x183 \x01(\bH\x13R\tuppercase\x88\x01\x01B\f\n" +
+	"\n" +
+	"well_knownB\b\n" +
+	"\x06_constB\x06\n" +
+	"\x04_lenB\n" +
+	"\n" +
+	"\b_min_lenB\n" +
+	"\n" +
+	"\b_max_lenB\f\n" +
+	"\n" +
+	"_len_bytesB\f\n" +
+	"\n" +
+	"_min_bytesB\f\n" +
+	"\n" +
+	"_max_bytesB\n" +
+	"\n" +
+	"\b_patternB\t\n" +
+	"\a_prefixB\t\n" +
+	"\a_suffixB\v\n" +
+	"\t_containsB\x0f\n" +
+	"\r_not_containsB\b\n" +
+	"\x06_asciiB\f\n" +
+	"\n" +
+	"_printableB\b\n" +
+	"\x06_alphaB\x0f\n" +
+	"\r_alphanumericB\n" +
+	"\n" +
+	"\b_numericB\f\n" +
+	"\n" +
+	"_lowercaseB\f\n" +
+	"\n" +
+	"_uppercase\"\xc0\x03\n" +
+	"\n" +
+	"BytesRules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\fH\x01R\x05const\x88\x01\x01\x12\x15\n" +
+	"\x03len\x18\x02 \x01(\x04H\x02R\x03len\x88\x01\x01\x12\x1c\n" +
+	"\amin_len\x18\x03 \x01(\x04H\x03R\x06minLen\x88\x01\x01\x12\x1c\n" +
+	"\amax_len\x18\x04 \x01(\x04H\x04R\x06maxLen\x88\x01\x01\x12\x1d\n" +
+	"\apattern\x18\x05 \x01(\fH\x05R\apattern\x88\x01\x01\x12\x1b\n" +
+	"\x06prefix\x18\x06 \x01(\fH\x06R\x06prefix\x88\x01\x01\x12\x1b\n" +
+	"\x06suffix\x18\a \x01(\fH\aR\x06suffix\x88\x01\x01\x12\x1f\n" +
+	"\bcontains\x18\b \x01(\fH\bR\bcontains\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\t \x03(\fR\x02in\x12\x15\n" +
+	"\x06not_in\x18\n" +
+	" \x03(\fR\x05notIn\x12\x10\n" +
+	"\x02ip\x18\x14 \x01(\bH\x00R\x02ip\x12\x14\n" +
+	"\x04ipv4\x18\x15 \x01(\bH\x00R\x04ipv4\x12\x14\n" +
+	"\x04ipv6\x18\x16 \x01(\bH\x00R\x04ipv6B\f\n" +
+	"\n" +
+	"well_knownB\b\n" +
+	"\x06_constB\x06\n" +
+	"\x04_lenB\n" +
+	"\n" +
+	"\b_min_lenB\n" +
+	"\n" +
+	"\b_max_lenB\n" +
+	"\n" +
+	"\b_patternB\t\n" +
+	"\a_prefixB\t\n" +
+	"\a_suffixB\v\n" +
+	"\t_contains\"\x90\x01\n" +
+	"\tEnumRules\x12\x19\n" +
+	"\x05const\x18\x01 \x01(\x05H\x00R\x05const\x88\x01\x01\x12&\n" +
+	"\fdefined_only\x18\x02 \x01(\bH\x01R\vdefinedOnly\x88\x01\x01\x12\x0e\n" +
+	"\x02in\x18\x03 \x03(\x05R\x02in\x12\x15\n" +
+	"\x06not_in\x18\x04 \x03(\x05R\x05notInB\b\n" +
+	"\x06_constB\x0f\n" +
+	"\r_defined_only\"\xcd\x01\n" +
+	"\rRepeatedRules\x12 \n" +
+	"\tmin_items\x18\x01 \x01(\x04H\x00R\bminItems\x88\x01\x01\x12 \n" +
+	"\tmax_items\x18\x02 \x01(\x04H\x01R\bmaxItems\x88\x01\x01\x12\x1b\n" +
+	"\x06unique\x18\x03 \x01(\bH\x02R\x06unique\x88\x01\x01\x124\n" +
+	"\x05items\x18\x04 \x01(\v2\x1e.kuban.api.validate.FieldRulesR\x05itemsB\f\n" +
+	"\n" +
+	"_min_itemsB\f\n" +
+	"\n" +
+	"_max_itemsB\t\n" +
+	"\a_unique\"\xd6\x01\n" +
+	"\bMapRules\x12 \n" +
+	"\tmin_pairs\x18\x01 \x01(\x04H\x00R\bminPairs\x88\x01\x01\x12 \n" +
+	"\tmax_pairs\x18\x02 \x01(\x04H\x01R\bmaxPairs\x88\x01\x01\x122\n" +
+	"\x04keys\x18\x03 \x01(\v2\x1e.kuban.api.validate.FieldRulesR\x04keys\x126\n" +
+	"\x06values\x18\x04 \x01(\v2\x1e.kuban.api.validate.FieldRulesR\x06valuesB\f\n" +
+	"\n" +
+	"_min_pairsB\f\n" +
+	"\n" +
+	"_max_pairs\"\xc6\x03\n" +
+	"\rDurationRules\x12\x1f\n" +
+	"\brequired\x18\x01 \x01(\bH\x00R\brequired\x88\x01\x01\x12(\n" +
+	"\rconst_seconds\x18\x02 \x01(\x03H\x01R\fconstSeconds\x88\x01\x01\x12$\n" +
+	"\vconst_nanos\x18\x03 \x01(\x05H\x02R\n" +
+	"constNanos\x88\x01\x01\x12\"\n" +
+	"\n" +
+	"lt_seconds\x18\x04 \x01(\x03H\x03R\tltSeconds\x88\x01\x01\x12$\n" +
+	"\vlte_seconds\x18\x05 \x01(\x03H\x04R\n" +
+	"lteSeconds\x88\x01\x01\x12\"\n" +
+	"\n" +
+	"gt_seconds\x18\x06 \x01(\x03H\x05R\tgtSeconds\x88\x01\x01\x12$\n" +
+	"\vgte_seconds\x18\a \x01(\x03H\x06R\n" +
+	"gteSeconds\x88\x01\x01\x12\x1d\n" +
+	"\n" +
+	"in_seconds\x18\b \x03(\x03R\tinSeconds\x12$\n" +
+	"\x0enot_in_seconds\x18\t \x03(\x03R\fnotInSecondsB\v\n" +
+	"\t_requiredB\x10\n" +
+	"\x0e_const_secondsB\x0e\n" +
+	"\f_const_nanosB\r\n" +
+	"\v_lt_secondsB\x0e\n" +
+	"\f_lte_secondsB\r\n" +
+	"\v_gt_secondsB\x0e\n" +
+	"\f_gte_seconds\"\xe6\x02\n" +
+	"\x0eTimestampRules\x12\x1f\n" +
+	"\brequired\x18\x01 \x01(\bH\x00R\brequired\x88\x01\x01\x12\x19\n" +
+	"\x05const\x18\x02 \x01(\x03H\x01R\x05const\x88\x01\x01\x12\x13\n" +
+	"\x02lt\x18\x03 \x01(\x03H\x02R\x02lt\x88\x01\x01\x12\x15\n" +
+	"\x03lte\x18\x04 \x01(\x03H\x03R\x03lte\x88\x01\x01\x12\x13\n" +
+	"\x02gt\x18\x05 \x01(\x03H\x04R\x02gt\x88\x01\x01\x12\x15\n" +
+	"\x03gte\x18\x06 \x01(\x03H\x05R\x03gte\x88\x01\x01\x12\x1a\n" +
+	"\x06lt_now\x18\a \x01(\bH\x06R\x05ltNow\x88\x01\x01\x12\x1a\n" +
+	"\x06gt_now\x18\b \x01(\bH\aR\x05gtNow\x88\x01\x01\x12*\n" +
+	"\x0ewithin_seconds\x18\t \x01(\x03H\bR\rwithinSeconds\x88\x01\x01B\v\n" +
+	"\t_requiredB\b\n" +
+	"\x06_constB\x05\n" +
+	"\x03_ltB\x06\n" +
+	"\x04_lteB\x05\n" +
+	"\x03_gtB\x06\n" +
+	"\x04_gteB\t\n" +
+	"\a_lt_nowB\t\n" +
+	"\a_gt_nowB\x11\n" +
+	"\x0f_within_seconds*]\n" +
+	"\n" +
+	"IgnoreRule\x12\x16\n" +
+	"\x12IGNORE_UNSPECIFIED\x10\x00\x12\x12\n" +
+	"\x0eIGNORE_IF_ZERO\x10\x01\x12\x11\n" +
+	"\rIGNORE_ALWAYS\x10\x02\x12\x10\n" +
+	"\fIGNORE_NEVER\x10\x03:\\\n" +
+	"\amessage\x12\x1f.google.protobuf.MessageOptions\x18\xf4N \x01(\v2 .kuban.api.validate.MessageRulesR\amessage:T\n" +
+	"\x05field\x12\x1d.google.protobuf.FieldOptions\x18\xf4N \x01(\v2\x1e.kuban.api.validate.FieldRulesR\x05field:c\n" +
+	"\n" +
+	"predefined\x12\x1d.google.protobuf.FieldOptions\x18\xf5N \x01(\v2#.kuban.api.validate.PredefinedRulesR\n" +
+	"predefined:T\n" +
+	"\x05oneof\x12\x1d.google.protobuf.OneofOptions\x18\xf4N \x01(\v2\x1e.kuban.api.validate.OneofRulesR\x05oneofB=Z;git.ikuban.com/server/kubanapis/kuban/api/validate;validateb\x06proto3"
+
+var (
+	file_kuban_api_validate_validate_proto_rawDescOnce sync.Once
+	file_kuban_api_validate_validate_proto_rawDescData []byte
+)
+
+func file_kuban_api_validate_validate_proto_rawDescGZIP() []byte {
+	file_kuban_api_validate_validate_proto_rawDescOnce.Do(func() {
+		file_kuban_api_validate_validate_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_kuban_api_validate_validate_proto_rawDesc), len(file_kuban_api_validate_validate_proto_rawDesc)))
+	})
+	return file_kuban_api_validate_validate_proto_rawDescData
+}
+
+var file_kuban_api_validate_validate_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_kuban_api_validate_validate_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
+var file_kuban_api_validate_validate_proto_goTypes = []any{
+	(IgnoreRule)(0),                     // 0: kuban.api.validate.IgnoreRule
+	(*Rule)(nil),                        // 1: kuban.api.validate.Rule
+	(*MessageRules)(nil),                // 2: kuban.api.validate.MessageRules
+	(*OneofRules)(nil),                  // 3: kuban.api.validate.OneofRules
+	(*FieldRules)(nil),                  // 4: kuban.api.validate.FieldRules
+	(*PredefinedRules)(nil),             // 5: kuban.api.validate.PredefinedRules
+	(*FloatRules)(nil),                  // 6: kuban.api.validate.FloatRules
+	(*DoubleRules)(nil),                 // 7: kuban.api.validate.DoubleRules
+	(*Int32Rules)(nil),                  // 8: kuban.api.validate.Int32Rules
+	(*Int64Rules)(nil),                  // 9: kuban.api.validate.Int64Rules
+	(*UInt32Rules)(nil),                 // 10: kuban.api.validate.UInt32Rules
+	(*UInt64Rules)(nil),                 // 11: kuban.api.validate.UInt64Rules
+	(*SInt32Rules)(nil),                 // 12: kuban.api.validate.SInt32Rules
+	(*SInt64Rules)(nil),                 // 13: kuban.api.validate.SInt64Rules
+	(*Fixed32Rules)(nil),                // 14: kuban.api.validate.Fixed32Rules
+	(*Fixed64Rules)(nil),                // 15: kuban.api.validate.Fixed64Rules
+	(*SFixed32Rules)(nil),               // 16: kuban.api.validate.SFixed32Rules
+	(*SFixed64Rules)(nil),               // 17: kuban.api.validate.SFixed64Rules
+	(*BoolRules)(nil),                   // 18: kuban.api.validate.BoolRules
+	(*StringRules)(nil),                 // 19: kuban.api.validate.StringRules
+	(*BytesRules)(nil),                  // 20: kuban.api.validate.BytesRules
+	(*EnumRules)(nil),                   // 21: kuban.api.validate.EnumRules
+	(*RepeatedRules)(nil),               // 22: kuban.api.validate.RepeatedRules
+	(*MapRules)(nil),                    // 23: kuban.api.validate.MapRules
+	(*DurationRules)(nil),               // 24: kuban.api.validate.DurationRules
+	(*TimestampRules)(nil),              // 25: kuban.api.validate.TimestampRules
+	(*descriptorpb.MessageOptions)(nil), // 26: google.protobuf.MessageOptions
+	(*descriptorpb.FieldOptions)(nil),   // 27: google.protobuf.FieldOptions
+	(*descriptorpb.OneofOptions)(nil),   // 28: google.protobuf.OneofOptions
+}
+var file_kuban_api_validate_validate_proto_depIdxs = []int32{
+	1,  // 0: kuban.api.validate.MessageRules.cel:type_name -> kuban.api.validate.Rule
+	1,  // 1: kuban.api.validate.FieldRules.cel:type_name -> kuban.api.validate.Rule
+	0,  // 2: kuban.api.validate.FieldRules.ignore:type_name -> kuban.api.validate.IgnoreRule
+	6,  // 3: kuban.api.validate.FieldRules.float:type_name -> kuban.api.validate.FloatRules
+	7,  // 4: kuban.api.validate.FieldRules.double:type_name -> kuban.api.validate.DoubleRules
+	8,  // 5: kuban.api.validate.FieldRules.int32:type_name -> kuban.api.validate.Int32Rules
+	9,  // 6: kuban.api.validate.FieldRules.int64:type_name -> kuban.api.validate.Int64Rules
+	10, // 7: kuban.api.validate.FieldRules.uint32:type_name -> kuban.api.validate.UInt32Rules
+	11, // 8: kuban.api.validate.FieldRules.uint64:type_name -> kuban.api.validate.UInt64Rules
+	12, // 9: kuban.api.validate.FieldRules.sint32:type_name -> kuban.api.validate.SInt32Rules
+	13, // 10: kuban.api.validate.FieldRules.sint64:type_name -> kuban.api.validate.SInt64Rules
+	14, // 11: kuban.api.validate.FieldRules.fixed32:type_name -> kuban.api.validate.Fixed32Rules
+	15, // 12: kuban.api.validate.FieldRules.fixed64:type_name -> kuban.api.validate.Fixed64Rules
+	16, // 13: kuban.api.validate.FieldRules.sfixed32:type_name -> kuban.api.validate.SFixed32Rules
+	17, // 14: kuban.api.validate.FieldRules.sfixed64:type_name -> kuban.api.validate.SFixed64Rules
+	18, // 15: kuban.api.validate.FieldRules.bool:type_name -> kuban.api.validate.BoolRules
+	19, // 16: kuban.api.validate.FieldRules.string:type_name -> kuban.api.validate.StringRules
+	20, // 17: kuban.api.validate.FieldRules.bytes:type_name -> kuban.api.validate.BytesRules
+	21, // 18: kuban.api.validate.FieldRules.enum:type_name -> kuban.api.validate.EnumRules
+	22, // 19: kuban.api.validate.FieldRules.repeated:type_name -> kuban.api.validate.RepeatedRules
+	23, // 20: kuban.api.validate.FieldRules.map:type_name -> kuban.api.validate.MapRules
+	24, // 21: kuban.api.validate.FieldRules.duration:type_name -> kuban.api.validate.DurationRules
+	25, // 22: kuban.api.validate.FieldRules.timestamp:type_name -> kuban.api.validate.TimestampRules
+	1,  // 23: kuban.api.validate.PredefinedRules.cel:type_name -> kuban.api.validate.Rule
+	4,  // 24: kuban.api.validate.RepeatedRules.items:type_name -> kuban.api.validate.FieldRules
+	4,  // 25: kuban.api.validate.MapRules.keys:type_name -> kuban.api.validate.FieldRules
+	4,  // 26: kuban.api.validate.MapRules.values:type_name -> kuban.api.validate.FieldRules
+	26, // 27: kuban.api.validate.message:extendee -> google.protobuf.MessageOptions
+	27, // 28: kuban.api.validate.field:extendee -> google.protobuf.FieldOptions
+	27, // 29: kuban.api.validate.predefined:extendee -> google.protobuf.FieldOptions
+	28, // 30: kuban.api.validate.oneof:extendee -> google.protobuf.OneofOptions
+	2,  // 31: kuban.api.validate.message:type_name -> kuban.api.validate.MessageRules
+	4,  // 32: kuban.api.validate.field:type_name -> kuban.api.validate.FieldRules
+	5,  // 33: kuban.api.validate.predefined:type_name -> kuban.api.validate.PredefinedRules
+	3,  // 34: kuban.api.validate.oneof:type_name -> kuban.api.validate.OneofRules
+	35, // [35:35] is the sub-list for method output_type
+	35, // [35:35] is the sub-list for method input_type
+	31, // [31:35] is the sub-list for extension type_name
+	27, // [27:31] is the sub-list for extension extendee
+	0,  // [0:27] is the sub-list for field type_name
+}
+
+func init() { file_kuban_api_validate_validate_proto_init() }
+func file_kuban_api_validate_validate_proto_init() {
+	if File_kuban_api_validate_validate_proto != nil {
+		return
+	}
+	file_kuban_api_validate_validate_proto_msgTypes[3].OneofWrappers = []any{
+		(*FieldRules_Float)(nil),
+		(*FieldRules_Double)(nil),
+		(*FieldRules_Int32)(nil),
+		(*FieldRules_Int64)(nil),
+		(*FieldRules_Uint32)(nil),
+		(*FieldRules_Uint64)(nil),
+		(*FieldRules_Sint32)(nil),
+		(*FieldRules_Sint64)(nil),
+		(*FieldRules_Fixed32)(nil),
+		(*FieldRules_Fixed64)(nil),
+		(*FieldRules_Sfixed32)(nil),
+		(*FieldRules_Sfixed64)(nil),
+		(*FieldRules_Bool)(nil),
+		(*FieldRules_String_)(nil),
+		(*FieldRules_Bytes)(nil),
+		(*FieldRules_Enum)(nil),
+		(*FieldRules_Repeated)(nil),
+		(*FieldRules_Map)(nil),
+		(*FieldRules_Duration)(nil),
+		(*FieldRules_Timestamp)(nil),
+	}
+	file_kuban_api_validate_validate_proto_msgTypes[5].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[6].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[7].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[8].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[9].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[10].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[11].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[12].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[13].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[14].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[15].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[16].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[17].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[18].OneofWrappers = []any{
+		(*StringRules_Email)(nil),
+		(*StringRules_Hostname)(nil),
+		(*StringRules_Ip)(nil),
+		(*StringRules_Ipv4)(nil),
+		(*StringRules_Ipv6)(nil),
+		(*StringRules_Uri)(nil),
+		(*StringRules_UriRef)(nil),
+		(*StringRules_Uuid)(nil),
+		(*StringRules_ChineseMobile)(nil),
+		(*StringRules_ChineseIdCard)(nil),
+		(*StringRules_ChineseName)(nil),
+		(*StringRules_ChinesePostcode)(nil),
+	}
+	file_kuban_api_validate_validate_proto_msgTypes[19].OneofWrappers = []any{
+		(*BytesRules_Ip)(nil),
+		(*BytesRules_Ipv4)(nil),
+		(*BytesRules_Ipv6)(nil),
+	}
+	file_kuban_api_validate_validate_proto_msgTypes[20].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[21].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[22].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[23].OneofWrappers = []any{}
+	file_kuban_api_validate_validate_proto_msgTypes[24].OneofWrappers = []any{}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_kuban_api_validate_validate_proto_rawDesc), len(file_kuban_api_validate_validate_proto_rawDesc)),
+			NumEnums:      1,
+			NumMessages:   25,
+			NumExtensions: 4,
+			NumServices:   0,
+		},
+		GoTypes:           file_kuban_api_validate_validate_proto_goTypes,
+		DependencyIndexes: file_kuban_api_validate_validate_proto_depIdxs,
+		EnumInfos:         file_kuban_api_validate_validate_proto_enumTypes,
+		MessageInfos:      file_kuban_api_validate_validate_proto_msgTypes,
+		ExtensionInfos:    file_kuban_api_validate_validate_proto_extTypes,
+	}.Build()
+	File_kuban_api_validate_validate_proto = out.File
+	file_kuban_api_validate_validate_proto_goTypes = nil
+	file_kuban_api_validate_validate_proto_depIdxs = nil
+}

+ 771 - 0
proto/kuban/api/validate/README_VALIDATE.md

@@ -0,0 +1,771 @@
+# Kuban API 验证框架
+
+基于 buf/validate 优化设计的自定义字段验证框架,提供简化的 API、中文支持和业务规则集成。
+
+## 目录
+
+- [特性](#特性)
+- [快速开始](#快速开始)
+- [核心概念](#核心概念)
+- [使用指南](#使用指南)
+- [业务规则](#业务规则)
+- [分组验证](#分组验证)
+- [最佳实践](#最佳实践)
+
+## 特性
+
+### 🚀 相比 buf/validate 的优化
+
+1. **简化的 API 设计**
+   - 更直观的规则定义语法
+   - 减少冗余配置
+   - 更好的类型安全
+
+2. **增强的中文支持**
+   - 内置中文错误消息
+   - 中文特定验证规则(手机号、身份证等)
+   - 双语错误消息支持
+
+3. **业务规则集成**
+   - 开箱即用的中国业务验证规则
+   - 手机号、身份证、统一社会信用代码等
+   - 易于扩展的业务规则库
+
+4. **分组验证**
+   - 场景化验证支持
+   - 创建、更新、审核等不同场景使用不同规则
+   - 灵活的规则组合
+
+5. **保留 CEL 支持**
+   - 完整的 CEL 表达式支持
+   - 灵活的自定义验证逻辑
+   - 跨字段验证能力
+
+## 快速开始
+
+### 1. 引入依赖
+
+```proto
+import "kuban/api/validate.proto";
+import "kuban/api/business_rules.proto";  // 可选:业务规则
+import "kuban/api/rule_groups.proto";     // 可选:分组验证
+```
+
+### 2. 基本字段验证
+
+```proto
+message User {
+  // 必填字符串,长度 2-50
+  string name = 1 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      min_len: 2,
+      max_len: 50
+    }
+  }];
+
+  // 必填邮箱
+  string email = 2 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      email: true
+    }
+  }];
+
+  // 年龄范围 0-150
+  int32 age = 3 [(kuban.api.validate.field) = {
+    int32: {
+      gte: 0,
+      lte: 150
+    }
+  }];
+}
+```
+
+### 3. 中文业务验证
+
+```proto
+message ChineseUser {
+  // 中国手机号
+  string mobile = 1 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      chinese_mobile: true
+    }
+  }];
+
+  // 中国身份证
+  string id_card = 2 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      chinese_id_card: true
+    }
+  }];
+
+  // 中文姓名
+  string name = 3 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      chinese_name: true
+    }
+  }];
+}
+```
+
+## 核心概念
+
+### 验证级别
+
+框架支持三个级别的验证:
+
+1. **字段级别验证** - 验证单个字段的值
+2. **消息级别验证** - 验证整个消息的一致性(跨字段验证)
+3. **Oneof 级别验证** - 验证 oneof 字段的选择
+
+### 验证规则类型
+
+- **类型特定规则**: 针对不同数据类型的验证规则(如 StringRules, Int32Rules)
+- **通用规则**: 适用于所有类型的规则(如 required, ignore)
+- **CEL 自定义规则**: 使用 CEL 表达式的自定义验证逻辑
+- **业务规则**: 预定义的业务场景验证规则
+
+## 使用指南
+
+### 字符串验证
+
+```proto
+message StringExample {
+  // 长度限制
+  string username = 1 [(kuban.api.validate.field).string = {
+    min_len: 3,
+    max_len: 20
+  }];
+
+  // 正则表达式
+  string code = 2 [(kuban.api.validate.field).string = {
+    pattern: "^[A-Z]{2}\\d{4}$"
+  }];
+
+  // 前缀/后缀
+  string ref_id = 3 [(kuban.api.validate.field).string = {
+    prefix: "REF_"
+  }];
+
+  // 枚举值
+  string status = 4 [(kuban.api.validate.field).string = {
+    in: ["pending", "approved", "rejected"]
+  }];
+
+  // 预定义格式
+  string email = 5 [(kuban.api.validate.field).string.email = true];
+  string url = 6 [(kuban.api.validate.field).string.uri = true];
+  string uuid = 7 [(kuban.api.validate.field).string.uuid = true];
+  string ip = 8 [(kuban.api.validate.field).string.ip = true];
+}
+```
+
+### 数值验证
+
+```proto
+message NumberExample {
+  // 范围验证
+  int32 score = 1 [(kuban.api.validate.field).int32 = {
+    gte: 0,
+    lte: 100
+  }];
+
+  // 常量值
+  int32 version = 2 [(kuban.api.validate.field).int32.const = 1];
+
+  // 枚举值
+  int32 priority = 3 [(kuban.api.validate.field).int32 = {
+    in: [1, 2, 3, 4, 5]
+  }];
+
+  // 浮点数
+  double price = 4 [(kuban.api.validate.field).double = {
+    gt: 0.0,
+    finite: true  // 不允许 NaN 和 Infinity
+  }];
+}
+```
+
+### 复杂类型验证
+
+```proto
+message ComplexExample {
+  // 重复字段
+  repeated string tags = 1 [(kuban.api.validate.field).repeated = {
+    min_items: 1,
+    max_items: 10,
+    unique: true,
+    items: {
+      string: {
+        min_len: 2,
+        max_len: 20
+      }
+    }
+  }];
+
+  // Map 字段
+  map<string, int32> scores = 2 [(kuban.api.validate.field).map = {
+    min_pairs: 1,
+    max_pairs: 100,
+    keys: {
+      string: { min_len: 1 }
+    },
+    values: {
+      int32: { gte: 0, lte: 100 }
+    }
+  }];
+}
+```
+
+### CEL 自定义验证
+
+```proto
+message CELExample {
+  string password = 1 [(kuban.api.validate.field) = {
+    required: true,
+    cel: [
+      {
+        id: "password.length",
+        message: "密码长度必须在 8-32 之间",
+        expression: "this.size() >= 8 && this.size() <= 32"
+      },
+      {
+        id: "password.complexity",
+        message: "密码必须包含大小写字母和数字",
+        expression: "this.matches('(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)')"
+      }
+    ]
+  }];
+
+  // 跨字段验证
+  int64 start_time = 2;
+  int64 end_time = 3 [(kuban.api.validate.field).cel = [{
+    id: "time.range",
+    message: "结束时间必须大于开始时间",
+    expression: "this > this.start_time"
+  }]];
+}
+```
+
+### 消息级别验证
+
+```proto
+message MessageExample {
+  option (kuban.api.validate.message).cel = [
+    {
+      id: "at_least_one_contact",
+      message: "邮箱和手机号至少需要填写一个",
+      expression: "has(this.email) || has(this.mobile)"
+    }
+  ];
+
+  optional string email = 1;
+  optional string mobile = 2;
+}
+```
+
+## 业务规则
+
+### 中国手机号验证
+
+```proto
+message MobileExample {
+  // 简单用法
+  string mobile = 1 [(kuban.api.validate.field).string.chinese_mobile = true];
+
+  // 详细配置
+  string mobile_advanced = 2 [(kuban.api.validate.field).string = {
+    (kuban.api.validate.chinese_mobile_rules): {
+      enabled: true,
+      allowed_operators: [
+        MOBILE_OPERATOR_CHINA_MOBILE,
+        MOBILE_OPERATOR_CHINA_UNICOM,
+        MOBILE_OPERATOR_CHINA_TELECOM
+      ],
+      allow_virtual: false,
+      error_message: "请输入有效的中国大陆手机号"
+    }
+  }];
+}
+```
+
+**支持的运营商:**
+- 中国移动 (MOBILE_OPERATOR_CHINA_MOBILE)
+- 中国联通 (MOBILE_OPERATOR_CHINA_UNICOM)
+- 中国电信 (MOBILE_OPERATOR_CHINA_TELECOM)
+- 中国广电 (MOBILE_OPERATOR_CHINA_BROADNET)
+
+### 中国身份证验证
+
+```proto
+message IdCardExample {
+  string id_card = 1 [(kuban.api.validate.field).string = {
+    (kuban.api.validate.chinese_id_card_rules): {
+      enabled: true,
+      verify_checksum: true,      // 验证校验位
+      verify_birth_date: true,    // 验证出生日期
+      verify_area_code: true,     // 验证地区码
+      allowed_types: [ID_CARD_TYPE_18_DIGIT],
+      min_age: 18,
+      max_age: 65,
+      required_gender: GENDER_UNSPECIFIED,  // 不限制性别
+      error_message: "请输入有效的18位身份证号"
+    }
+  }];
+}
+```
+
+**验证内容:**
+- 长度验证(15位/18位)
+- 校验位算法验证
+- 出生日期有效性
+- 地区码有效性
+- 年龄范围限制
+- 性别限制(可选)
+
+### 统一社会信用代码验证
+
+```proto
+message USCCExample {
+  string uscc = 1 [(kuban.api.validate.field).string = {
+    (kuban.api.validate.uscc_rules): {
+      enabled: true,
+      verify_checksum: true,
+      allowed_types: [
+        ORGANIZATION_TYPE_ENTERPRISE,
+        ORGANIZATION_TYPE_INSTITUTION
+      ],
+      error_message: "请输入有效的统一社会信用代码"
+    }
+  }];
+}
+```
+
+### 银行卡号验证
+
+```proto
+message BankCardExample {
+  string bank_card = 1 [(kuban.api.validate.field).string = {
+    (kuban.api.validate.bank_card_rules): {
+      enabled: true,
+      verify_luhn: true,  // Luhn 算法校验
+      allowed_types: [
+        BANK_CARD_TYPE_DEBIT,
+        BANK_CARD_TYPE_CREDIT
+      ],
+      allowed_banks: ["ICBC", "CCB", "ABC"],  // 允许的银行
+      error_message: "请输入有效的银行卡号"
+    }
+  }];
+}
+```
+
+### 中文姓名验证
+
+```proto
+message NameExample {
+  string name = 1 [(kuban.api.validate.field).string = {
+    (kuban.api.validate.chinese_name_rules): {
+      enabled: true,
+      min_length: 2,
+      max_length: 20,
+      allow_ethnic_minority: true,  // 允许少数民族姓名(如阿依·古丽)
+      allow_english: false,
+      error_message: "请输入2-20个字符的中文姓名"
+    }
+  }];
+}
+```
+
+### 邮政编码验证
+
+```proto
+message PostcodeExample {
+  string postcode = 1 [(kuban.api.validate.field).string = {
+    (kuban.api.validate.postcode_rules): {
+      enabled: true,
+      country_code: "CN",
+      allowed_provinces: ["11", "31", "44"],  // 北京、上海、广东
+      error_message: "请输入有效的邮政编码"
+    }
+  }];
+}
+```
+
+## 分组验证
+
+### 基本用法
+
+```proto
+message User {
+  // 在创建和更新时都验证
+  string username = 1 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["create", "update"],
+    string: { min_len: 3, max_len: 20 }
+  }];
+
+  // 仅在创建时验证
+  string password = 2 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["create"],
+    string: { min_len: 8 }
+  }];
+
+  // 仅在修改密码时验证
+  string new_password = 3 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["change_password"],
+    string: { min_len: 8 }
+  }];
+}
+```
+
+### 常用验证组
+
+框架预定义了以下常用验证组:
+
+**CRUD 操作:**
+- `create` - 创建场景
+- `update` - 更新场景
+- `patch` - 部分更新场景
+- `delete` - 删除场景
+- `query` - 查询场景
+
+**严格程度:**
+- `strict` - 严格模式
+- `normal` - 标准模式
+- `loose` - 宽松模式
+
+**用户场景:**
+- `register` - 用户注册
+- `login` - 用户登录
+- `profile` - 个人资料
+- `change_password` - 修改密码
+- `reset_password` - 重置密码
+
+**审核场景:**
+- `draft` - 草稿
+- `submit` - 提交审核
+- `approve` - 审核通过
+- `reject` - 审核拒绝
+
+**认证场景:**
+- `real_name_auth` - 实名认证
+- `enterprise_auth` - 企业认证
+- `bank_card_binding` - 银行卡绑定
+
+**安全场景:**
+- `sensitive_op` - 敏感操作
+- `financial` - 金融交易
+- `admin` - 管理员操作
+
+### 验证上下文
+
+在运行时,你可以通过 `ValidationContext` 指定激活的验证组:
+
+```proto
+message ValidationContext {
+  repeated string active_groups = 1;  // ["create", "strict"]
+  repeated string user_roles = 2;
+  bool is_admin = 6;
+  string language = 9;  // "zh-CN" 或 "en-US"
+}
+```
+
+## 忽略策略
+
+控制何时跳过验证:
+
+```proto
+message IgnoreExample {
+  // 未设置时不验证(默认行为)
+  optional string url = 1 [(kuban.api.validate.field) = {
+    ignore: IGNORE_UNSPECIFIED,
+    string: { uri: true }
+  }];
+
+  // 为零值时不验证
+  optional string optional_url = 2 [(kuban.api.validate.field) = {
+    ignore: IGNORE_IF_ZERO,
+    string: { uri: true }
+  }];
+
+  // 始终验证
+  optional string required_field = 3 [(kuban.api.validate.field) = {
+    ignore: IGNORE_NEVER,
+    required: true
+  }];
+
+  // 始终忽略(用于临时禁用)
+  string temp_field = 4 [(kuban.api.validate.field) = {
+    ignore: IGNORE_ALWAYS,
+    string: { min_len: 10 }
+  }];
+}
+```
+
+## 完整示例
+
+### 用户注册
+
+```proto
+message UserRegistrationRequest {
+  option (kuban.api.validate.message) = {
+    groups: ["register"]
+  };
+
+  string username = 1 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: {
+      min_len: 3,
+      max_len: 20,
+      pattern: "^[a-zA-Z0-9_]+$"
+    },
+    cel: [{
+      id: "username.reserved",
+      message: "该用户名为系统保留,不可使用",
+      expression: "!['admin', 'root'].contains(this.toLowerCase())"
+    }]
+  }];
+
+  string password = 2 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: { min_len: 8, max_len: 32 },
+    cel: [{
+      id: "password.complexity",
+      message: "密码必须包含大小写字母、数字和特殊字符",
+      expression: "this.matches('(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)(?=.*[@$!%*?&])')"
+    }]
+  }];
+
+  string mobile = 3 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: { chinese_mobile: true }
+  }];
+
+  string verification_code = 4 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: { len: 6, numeric: true }
+  }];
+
+  optional string email = 5 [(kuban.api.validate.field) = {
+    groups: ["register"],
+    ignore: IGNORE_IF_ZERO,
+    string: { email: true }
+  }];
+
+  bool agree_terms = 6 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    bool: { const: true }
+  }];
+}
+```
+
+### 企业认证
+
+```proto
+message EnterpriseAuthRequest {
+  option (kuban.api.validate.message) = {
+    groups: ["enterprise_auth"]
+  };
+
+  string company_name = 1 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    string: { min_len: 2, max_len: 100 }
+  }];
+
+  string uscc = 2 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    string: {
+      len: 18,
+      (kuban.api.validate.uscc_rules): {
+        enabled: true,
+        verify_checksum: true,
+        allowed_types: [ORGANIZATION_TYPE_ENTERPRISE]
+      }
+    }
+  }];
+
+  string legal_person = 3 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    string: {
+      chinese_name: true,
+      (kuban.api.validate.chinese_name_rules): {
+        enabled: true,
+        min_length: 2,
+        max_length: 20
+      }
+    }
+  }];
+
+  string legal_person_id_card = 4 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    string: {
+      chinese_id_card: true,
+      (kuban.api.validate.chinese_id_card_rules): {
+        enabled: true,
+        verify_checksum: true,
+        min_age: 18
+      }
+    }
+  }];
+}
+```
+
+## 最佳实践
+
+### 1. 优先使用内置规则
+
+```proto
+// ✅ 好 - 使用内置规则
+string email = 1 [(kuban.api.validate.field).string.email = true];
+
+// ❌ 不推荐 - 自己写正则
+string email = 2 [(kuban.api.validate.field).string = {
+  pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
+}];
+```
+
+### 2. 合理使用验证组
+
+```proto
+// ✅ 好 - 根据场景使用不同规则
+message User {
+  string password = 1 [(kuban.api.validate.field) = {
+    groups: ["create", "change_password"],
+    required: true,
+    string: { min_len: 8 }
+  }];
+}
+
+// ❌ 不推荐 - 所有场景都验证密码
+message User {
+  string password = 1 [(kuban.api.validate.field) = {
+    required: true,  // 更新用户资料时也要求密码
+    string: { min_len: 8 }
+  }];
+}
+```
+
+### 3. 提供友好的错误消息
+
+```proto
+// ✅ 好 - 提供清晰的错误消息
+string mobile = 1 [(kuban.api.validate.field).string = {
+  (kuban.api.validate.chinese_mobile_rules): {
+    enabled: true,
+    error_message: "请输入有效的11位手机号"
+  }
+}];
+
+// ❌ 不推荐 - 使用默认消息
+string mobile = 2 [(kuban.api.validate.field).string.chinese_mobile = true];
+```
+
+### 4. 适当使用 CEL
+
+```proto
+// ✅ 好 - 复杂逻辑使用 CEL
+message DateRange {
+  option (kuban.api.validate.message).cel = [{
+    id: "date_range.valid",
+    message: "结束日期必须大于开始日期",
+    expression: "this.end_date > this.start_date"
+  }];
+
+  int64 start_date = 1;
+  int64 end_date = 2;
+}
+
+// ❌ 不推荐 - 简单验证使用 CEL
+string email = 1 [(kuban.api.validate.field).cel = [{
+  expression: "this.contains('@')"  // 应该用 string.email = true
+}]];
+```
+
+### 5. 使用忽略策略优化可选字段
+
+```proto
+// ✅ 好 - 可选字段使用 IGNORE_IF_ZERO
+optional string website = 1 [(kuban.api.validate.field) = {
+  ignore: IGNORE_IF_ZERO,
+  string: { uri: true }
+}];
+
+// ❌ 不推荐 - 不必要的 required
+optional string website = 2 [(kuban.api.validate.field) = {
+  required: true,  // optional 和 required 矛盾
+  string: { uri: true }
+}];
+```
+
+## 文件结构
+
+```
+proto/kuban/api/
+├── validate.proto           # 核心验证框架
+├── business_rules.proto     # 业务规则库
+├── rule_groups.proto        # 规则分组管理
+├── validate_example.proto   # 使用示例
+└── README_VALIDATE.md       # 本文档
+```
+
+## 与 buf/validate 的对比
+
+| 特性 | buf/validate | kuban.api.validate |
+|------|--------------|-------------------|
+| 基本验证 | ✅ | ✅ |
+| CEL 支持 | ✅ | ✅ |
+| 中文错误消息 | ❌ | ✅ |
+| 中国业务规则 | ❌ | ✅ (手机号、身份证等) |
+| 分组验证 | ❌ | ✅ |
+| 简化 API | ❌ | ✅ |
+| 双语支持 | ❌ | ✅ |
+| 条件验证 | 基础 | ✅ 增强 |
+
+## 常见问题
+
+### Q: 如何在代码中使用这些验证规则?
+
+A: 你需要实现一个验证器来解析和执行这些规则。框架只定义了规则的结构,具体的验证逻辑需要在运行时实现。
+
+### Q: 可以自定义业务规则吗?
+
+A: 可以!你可以通过 extend StringRules 添加自己的业务规则扩展。
+
+### Q: 验证组在运行时如何激活?
+
+A: 通过 ValidationContext 消息传递激活的组名列表。
+
+### Q: CEL 表达式可以访问哪些变量?
+
+A:
+- `this` - 当前字段的值
+- `this.field_name` - 同一消息的其他字段(跨字段验证)
+- 内置函数如 `size()`, `matches()`, `contains()` 等
+
+### Q: 如何处理验证错误?
+
+A: 验证器应该返回 ValidationResult 消息,包含所有的 ValidationError 详情。
+
+## 贡献
+
+欢迎提交 Issue 和 Pull Request 来改进这个验证框架!
+
+## 许可证
+
+Copyright 2025 Kuban Technologies

+ 326 - 0
proto/kuban/api/validate/business_rules.proto

@@ -0,0 +1,326 @@
+// Copyright 2025 Kuban Technologies
+//
+// 业务规则库 - 针对中国业务场景的预定义验证规则
+// 提供开箱即用的常用业务验证
+
+syntax = "proto3";
+
+package kuban.api.validate;
+
+import "google/protobuf/descriptor.proto";
+import "kuban/api/validate/validate.proto";
+
+option go_package = "git.ikuban.com/server/kubanapis/kuban/api/validate;validate";
+
+// ============================================================================
+// 业务规则定义
+// ============================================================================
+//
+// 注意: Proto3 不支持 extend 语法,这些业务规则应该通过以下方式使用:
+// 1. 在 FieldRules 中使用 CEL 表达式引用这些规则
+// 2. 在应用层直接使用这些独立的规则消息
+// 3. 使用 StringRules 中已有的 well_known 字段(如 chinese_mobile, chinese_id_card 等)
+//
+// ============================================================================
+
+// 中国手机号验证规则
+message ChineseMobileRules {
+  // 是否启用验证
+  bool enabled = 1;
+
+  // 允许的运营商
+  repeated MobileOperator allowed_operators = 2;
+
+  // 是否允许虚拟运营商号码
+  bool allow_virtual = 3;
+
+  // 自定义错误消息
+  string error_message = 4;
+}
+
+// 手机运营商枚举
+enum MobileOperator {
+  MOBILE_OPERATOR_UNSPECIFIED = 0;
+  MOBILE_OPERATOR_CHINA_MOBILE = 1;    // 中国移动
+  MOBILE_OPERATOR_CHINA_UNICOM = 2;    // 中国联通
+  MOBILE_OPERATOR_CHINA_TELECOM = 3;   // 中国电信
+  MOBILE_OPERATOR_CHINA_BROADNET = 4;  // 中国广电
+}
+
+// 中国身份证验证规则
+message ChineseIdCardRules {
+  // 是否启用验证
+  bool enabled = 1;
+
+  // 是否验证校验位
+  bool verify_checksum = 2;
+
+  // 是否验证出生日期有效性
+  bool verify_birth_date = 3;
+
+  // 是否验证地区码有效性
+  bool verify_area_code = 4;
+
+  // 允许的身份证类型
+  repeated IdCardType allowed_types = 5;
+
+  // 年龄范围限制
+  optional int32 min_age = 6;
+  optional int32 max_age = 7;
+
+  // 性别限制
+  optional Gender required_gender = 8;
+
+  // 自定义错误消息
+  string error_message = 9;
+}
+
+// 身份证类型
+enum IdCardType {
+  ID_CARD_TYPE_UNSPECIFIED = 0;
+  ID_CARD_TYPE_18_DIGIT = 1;  // 18位身份证
+  ID_CARD_TYPE_15_DIGIT = 2;  // 15位身份证(旧版)
+}
+
+// 性别枚举
+enum Gender {
+  GENDER_UNSPECIFIED = 0;
+  GENDER_MALE = 1;      // 男性
+  GENDER_FEMALE = 2;    // 女性
+}
+
+// 统一社会信用代码验证规则
+message UnifiedSocialCreditCodeRules {
+  // 是否启用验证
+  bool enabled = 1;
+
+  // 是否验证校验位
+  bool verify_checksum = 2;
+
+  // 允许的机构类型
+  repeated OrganizationType allowed_types = 3;
+
+  // 自定义错误消息
+  string error_message = 4;
+}
+
+// 机构类型
+enum OrganizationType {
+  ORGANIZATION_TYPE_UNSPECIFIED = 0;
+  ORGANIZATION_TYPE_ENTERPRISE = 1;        // 企业
+  ORGANIZATION_TYPE_INSTITUTION = 2;       // 事业单位
+  ORGANIZATION_TYPE_SOCIAL_GROUP = 3;      // 社会团体
+  ORGANIZATION_TYPE_GOVERNMENT = 9;        // 机关
+}
+
+// 银行卡号验证规则
+message BankCardRules {
+  // 是否启用验证
+  bool enabled = 1;
+
+  // 是否使用 Luhn 算法验证
+  bool verify_luhn = 2;
+
+  // 允许的卡类型
+  repeated BankCardType allowed_types = 3;
+
+  // 允许的银行
+  repeated string allowed_banks = 4;  // 银行代码列表
+
+  // 自定义错误消息
+  string error_message = 5;
+}
+
+// 银行卡类型
+enum BankCardType {
+  BANK_CARD_TYPE_UNSPECIFIED = 0;
+  BANK_CARD_TYPE_DEBIT = 1;   // 借记卡
+  BANK_CARD_TYPE_CREDIT = 2;  // 信用卡
+}
+
+// 中文姓名验证规则
+message ChineseNameRules {
+  // 是否启用验证
+  bool enabled = 1;
+
+  // 最小长度(字符数)
+  optional uint32 min_length = 2;
+
+  // 最大长度(字符数)
+  optional uint32 max_length = 3;
+
+  // 是否允许少数民族姓名(可能包含·等特殊字符)
+  bool allow_ethnic_minority = 4;
+
+  // 是否允许英文名
+  bool allow_english = 5;
+
+  // 自定义错误消息
+  string error_message = 6;
+}
+
+// 邮政编码验证规则
+message PostcodeRules {
+  // 是否启用验证
+  bool enabled = 1;
+
+  // 国家/地区代码(默认为中国 CN)
+  string country_code = 2;
+
+  // 允许的省份代码(中国邮编前两位)
+  repeated string allowed_provinces = 3;
+
+  // 自定义错误消息
+  string error_message = 4;
+}
+
+// ============================================================================
+// 常用业务场景验证规则组合
+// ============================================================================
+
+// 用户注册验证规则
+message UserRegistrationRules {
+  // 用户名规则
+  StringRules username = 1;
+
+  // 手机号规则
+  ChineseMobileRules mobile = 2;
+
+  // 邮箱规则
+  StringRules email = 3;
+
+  // 密码规则
+  PasswordRules password = 4;
+
+  // 真实姓名规则(可选)
+  ChineseNameRules real_name = 5;
+
+  // 身份证规则(可选)
+  ChineseIdCardRules id_card = 6;
+}
+
+// 密码强度验证规则
+message PasswordRules {
+  // 最小长度
+  uint32 min_length = 1;
+
+  // 最大长度
+  uint32 max_length = 2;
+
+  // 是否要求包含大写字母
+  bool require_uppercase = 3;
+
+  // 是否要求包含小写字母
+  bool require_lowercase = 4;
+
+  // 是否要求包含数字
+  bool require_digit = 5;
+
+  // 是否要求包含特殊字符
+  bool require_special = 6;
+
+  // 特殊字符集合(默认: !@#$%^&*()_+-=[]{}|;:,.<>?)
+  string special_chars = 7;
+
+  // 是否禁止常见弱密码
+  bool reject_common_weak = 8;
+
+  // 自定义错误消息
+  string error_message = 9;
+}
+
+// 企业信息验证规则
+message EnterpriseInfoRules {
+  // 企业名称规则
+  StringRules company_name = 1;
+
+  // 统一社会信用代码规则
+  UnifiedSocialCreditCodeRules uscc = 2;
+
+  // 法人姓名规则
+  ChineseNameRules legal_person_name = 3;
+
+  // 注册资本范围
+  optional int64 min_registered_capital = 4;
+  optional int64 max_registered_capital = 5;
+
+  // 营业执照号码(旧格式)
+  StringRules business_license = 6;
+}
+
+// 地址验证规则
+message AddressRules {
+  // 省份
+  StringRules province = 1;
+
+  // 城市
+  StringRules city = 2;
+
+  // 区县
+  StringRules district = 3;
+
+  // 详细地址
+  StringRules detail = 4;
+
+  // 邮政编码
+  PostcodeRules postcode = 5;
+
+  // 是否要求完整地址
+  bool require_complete = 6;
+}
+
+// 金融交易验证规则
+message FinancialTransactionRules {
+  // 交易金额范围
+  optional double min_amount = 1;
+  optional double max_amount = 2;
+
+  // 银行卡号验证
+  BankCardRules bank_card = 3;
+
+  // 交易密码规则
+  PasswordRules transaction_password = 4;
+
+  // 是否要求二次确认
+  bool require_confirmation = 5;
+}
+
+// ============================================================================
+// 验证规则辅助消息
+// ============================================================================
+
+// 验证错误详情
+message ValidationError {
+  // 字段路径
+  string field_path = 1;
+
+  // 规则 ID
+  string rule_id = 2;
+
+  // 错误消息(中文)
+  string message = 3;
+
+  // 错误消息(英文)
+  string message_en = 4;
+
+  // 失败的值
+  string value = 5;
+
+  // 附加信息
+  map<string, string> metadata = 6;
+}
+
+// 批量验证结果
+message ValidationResult {
+  // 是否验证通过
+  bool valid = 1;
+
+  // 错误列表
+  repeated ValidationError errors = 2;
+
+  // 警告列表(非阻塞性)
+  repeated ValidationError warnings = 3;
+
+  // 验证组
+  string group = 4;
+}

+ 333 - 0
proto/kuban/api/validate/rule_groups.proto

@@ -0,0 +1,333 @@
+// Copyright 2025 Kuban Technologies
+//
+// 规则分组管理 - 支持场景化验证
+// 允许在不同业务场景下应用不同的验证规则集
+
+syntax = "proto3";
+
+package kuban.api.validate;
+
+import "google/protobuf/descriptor.proto";
+
+option go_package = "git.ikuban.com/server/kubanapis/kuban/api/validate;validate";
+
+// ============================================================================
+// 验证组定义
+// ============================================================================
+
+// 验证组 - 用于场景化验证
+//
+// 使用示例:
+// ```proto
+// message User {
+//   string name = 1 [
+//     (kuban.api.validate.field).string = { min_len: 2, max_len: 50 },
+//     (kuban.api.validate.field).groups = ["create", "update"]
+//   ];
+//
+//   string password = 2 [
+//     (kuban.api.validate.field).string = { min_len: 8 },
+//     (kuban.api.validate.field).groups = ["create", "change_password"]
+//   ];
+// }
+// ```
+message ValidationGroup {
+  // 组名称(唯一标识)
+  string name = 1;
+
+  // 组显示名称(中文)
+  string display_name = 2;
+
+  // 组显示名称(英文)
+  string display_name_en = 3;
+
+  // 组描述
+  string description = 4;
+
+  // 是否为默认组(默认启用)
+  bool is_default = 5;
+
+  // 优先级(数字越大优先级越高)
+  int32 priority = 6;
+
+  // 父组(用于继承规则)
+  string parent_group = 7;
+
+  // 互斥组(不能同时激活的组)
+  repeated string exclusive_groups = 8;
+}
+
+// 常用验证组定义
+enum CommonValidationGroup {
+  COMMON_VALIDATION_GROUP_UNSPECIFIED = 0;
+
+  // CRUD 操作组
+  COMMON_VALIDATION_GROUP_CREATE = 1;    // 创建场景
+  COMMON_VALIDATION_GROUP_UPDATE = 2;    // 更新场景
+  COMMON_VALIDATION_GROUP_PATCH = 3;     // 部分更新场景
+  COMMON_VALIDATION_GROUP_DELETE = 4;    // 删除场景
+  COMMON_VALIDATION_GROUP_QUERY = 5;     // 查询场景
+
+  // 严格程度组
+  COMMON_VALIDATION_GROUP_STRICT = 10;   // 严格模式
+  COMMON_VALIDATION_GROUP_NORMAL = 11;   // 标准模式
+  COMMON_VALIDATION_GROUP_LOOSE = 12;    // 宽松模式
+
+  // 用户场景组
+  COMMON_VALIDATION_GROUP_REGISTER = 20;        // 用户注册
+  COMMON_VALIDATION_GROUP_LOGIN = 21;           // 用户登录
+  COMMON_VALIDATION_GROUP_PROFILE = 22;         // 个人资料
+  COMMON_VALIDATION_GROUP_CHANGE_PASSWORD = 23; // 修改密码
+  COMMON_VALIDATION_GROUP_RESET_PASSWORD = 24;  // 重置密码
+
+  // 审核场景组
+  COMMON_VALIDATION_GROUP_DRAFT = 30;    // 草稿
+  COMMON_VALIDATION_GROUP_SUBMIT = 31;   // 提交审核
+  COMMON_VALIDATION_GROUP_APPROVE = 32;  // 审核通过
+  COMMON_VALIDATION_GROUP_REJECT = 33;   // 审核拒绝
+
+  // 实名认证场景
+  COMMON_VALIDATION_GROUP_REAL_NAME_AUTH = 40;     // 实名认证
+  COMMON_VALIDATION_GROUP_ENTERPRISE_AUTH = 41;    // 企业认证
+  COMMON_VALIDATION_GROUP_BANK_CARD_BINDING = 42;  // 银行卡绑定
+
+  // 安全场景组
+  COMMON_VALIDATION_GROUP_SENSITIVE_OP = 50;  // 敏感操作
+  COMMON_VALIDATION_GROUP_FINANCIAL = 51;     // 金融交易
+  COMMON_VALIDATION_GROUP_ADMIN = 52;         // 管理员操作
+}
+
+// ============================================================================
+// 验证上下文
+// ============================================================================
+
+// 验证上下文 - 运行时传递给验证器的上下文信息
+message ValidationContext {
+  // 激活的验证组
+  repeated string active_groups = 1;
+
+  // 用户角色
+  repeated string user_roles = 2;
+
+  // 用户权限
+  repeated string user_permissions = 3;
+
+  // 租户 ID(多租户场景)
+  string tenant_id = 4;
+
+  // 请求来源
+  RequestSource source = 5;
+
+  // 是否为管理员操作
+  bool is_admin = 6;
+
+  // 自定义元数据
+  map<string, string> metadata = 7;
+
+  // 验证时间戳
+  int64 timestamp = 8;
+
+  // 语言偏好(用于错误消息)
+  string language = 9;
+}
+
+// 请求来源
+enum RequestSource {
+  REQUEST_SOURCE_UNSPECIFIED = 0;
+  REQUEST_SOURCE_WEB = 1;          // Web 端
+  REQUEST_SOURCE_MOBILE = 2;       // 移动端
+  REQUEST_SOURCE_API = 3;          // API 调用
+  REQUEST_SOURCE_INTERNAL = 4;     // 内部调用
+  REQUEST_SOURCE_BATCH = 5;        // 批量处理
+}
+
+// ============================================================================
+// 验证策略
+// ============================================================================
+
+// 验证策略 - 控制验证行为
+message ValidationStrategy {
+  // 验证模式
+  ValidationMode mode = 1;
+
+  // 是否快速失败(遇到第一个错误就停止)
+  bool fail_fast = 2;
+
+  // 是否收集警告(非阻塞性错误)
+  bool collect_warnings = 3;
+
+  // 最大错误数(超过后停止验证)
+  int32 max_errors = 4;
+
+  // 验证超时(毫秒)
+  int64 timeout_ms = 5;
+
+  // 是否启用缓存
+  bool enable_cache = 6;
+
+  // 缓存 TTL(秒)
+  int32 cache_ttl_seconds = 7;
+}
+
+// 验证模式
+enum ValidationMode {
+  VALIDATION_MODE_UNSPECIFIED = 0;
+  VALIDATION_MODE_ALL = 1;         // 验证所有规则
+  VALIDATION_MODE_REQUIRED_ONLY = 2; // 仅验证必填项
+  VALIDATION_MODE_CHANGED_ONLY = 3;  // 仅验证修改的字段
+  VALIDATION_MODE_CUSTOM = 4;        // 自定义(根据组选择)
+}
+
+// ============================================================================
+// 组合验证规则
+// ============================================================================
+
+// 组合验证规则 - 支持复杂的验证逻辑组合
+message CompositeRule {
+  // 规则组合类型
+  CompositeType type = 1;
+
+  // 子规则列表
+  repeated RuleRef rules = 2;
+
+  // 错误消息
+  string message = 3;
+
+  // 错误消息(英文)
+  string message_en = 4;
+}
+
+// 组合类型
+enum CompositeType {
+  COMPOSITE_TYPE_UNSPECIFIED = 0;
+  COMPOSITE_TYPE_AND = 1;  // 所有规则都必须通过
+  COMPOSITE_TYPE_OR = 2;   // 至少一个规则通过
+  COMPOSITE_TYPE_XOR = 3;  // 恰好一个规则通过
+  COMPOSITE_TYPE_NOT = 4;  // 规则不能通过
+}
+
+// 规则引用
+message RuleRef {
+  // 规则 ID
+  string rule_id = 1;
+
+  // 规则权重(用于优先级排序)
+  int32 weight = 2;
+
+  // 是否为可选规则
+  bool optional = 3;
+}
+
+// ============================================================================
+// 条件验证
+// ============================================================================
+
+// 条件验证规则 - 根据条件决定是否应用规则
+message ConditionalRule {
+  // 条件表达式(CEL)
+  string condition = 1;
+
+  // 条件为真时应用的规则
+  repeated RuleRef when_true = 2;
+
+  // 条件为假时应用的规则
+  repeated RuleRef when_false = 3;
+
+  // 条件评估失败时的默认行为
+  DefaultBehavior on_error = 4;
+}
+
+// 默认行为
+enum DefaultBehavior {
+  DEFAULT_BEHAVIOR_UNSPECIFIED = 0;
+  DEFAULT_BEHAVIOR_SKIP = 1;      // 跳过验证
+  DEFAULT_BEHAVIOR_APPLY = 2;     // 应用验证
+  DEFAULT_BEHAVIOR_FAIL = 3;      // 验证失败
+}
+
+// ============================================================================
+// 验证规则集
+// ============================================================================
+
+// 验证规则集 - 预定义的规则组合,可复用
+message ValidationRuleSet {
+  // 规则集 ID
+  string id = 1;
+
+  // 规则集名称
+  string name = 2;
+
+  // 规则集描述
+  string description = 3;
+
+  // 规则集版本
+  string version = 4;
+
+  // 包含的验证组
+  repeated string groups = 5;
+
+  // 包含的规则
+  repeated RuleRef rules = 6;
+
+  // 验证策略
+  ValidationStrategy strategy = 7;
+
+  // 是否为内置规则集
+  bool builtin = 8;
+
+  // 创建时间
+  int64 created_at = 9;
+
+  // 更新时间
+  int64 updated_at = 10;
+
+  // 创建者
+  string created_by = 11;
+}
+
+// ============================================================================
+// 验证规则集市场(可选 - 用于规则共享)
+// ============================================================================
+
+// 规则集模板 - 用于快速创建常见场景的验证规则
+message RuleSetTemplate {
+  // 模板 ID
+  string id = 1;
+
+  // 模板名称
+  string name = 2;
+
+  // 模板描述
+  string description = 3;
+
+  // 适用场景
+  repeated string scenarios = 4;
+
+  // 模板类别
+  repeated string categories = 5;
+
+  // 规则集定义
+  ValidationRuleSet rule_set = 6;
+
+  // 使用示例
+  string usage_example = 7;
+
+  // 下载次数
+  int64 download_count = 8;
+
+  // 评分
+  float rating = 9;
+}
+
+// 规则集类别
+enum RuleSetCategory {
+  RULE_SET_CATEGORY_UNSPECIFIED = 0;
+  RULE_SET_CATEGORY_USER_MANAGEMENT = 1;    // 用户管理
+  RULE_SET_CATEGORY_FINANCIAL = 2;          // 金融
+  RULE_SET_CATEGORY_ECOMMERCE = 3;          // 电商
+  RULE_SET_CATEGORY_CONTENT = 4;            // 内容管理
+  RULE_SET_CATEGORY_GOVERNMENT = 5;         // 政务
+  RULE_SET_CATEGORY_HEALTHCARE = 6;         // 医疗
+  RULE_SET_CATEGORY_EDUCATION = 7;          // 教育
+  RULE_SET_CATEGORY_GENERAL = 99;           // 通用
+}

+ 485 - 0
proto/kuban/api/validate/validate.proto

@@ -0,0 +1,485 @@
+// Copyright 2025 Kuban Technologies
+//
+// 自定义字段验证框架 - 基于 buf/validate 优化设计
+// 提供简化的 API、中文支持和业务规则集成
+
+syntax = "proto3";
+
+package kuban.api.validate;
+
+import "google/protobuf/descriptor.proto";
+// import "google/protobuf/duration.proto";  // 未使用
+// import "google/protobuf/timestamp.proto";  // 未使用
+
+option go_package = "git.ikuban.com/server/kubanapis/kuban/api/validate;validate";
+
+// ============================================================================
+// 扩展定义 - 为 Protobuf 描述符添加验证能力
+// ============================================================================
+
+// MessageOptions 扩展 - 消息级别验证
+extend google.protobuf.MessageOptions {
+  // 消息级别的验证规则
+  MessageRules message = 10100;
+}
+
+// FieldOptions 扩展 - 字段级别验证
+extend google.protobuf.FieldOptions {
+  // 字段级别的验证规则
+  FieldRules field = 10100;
+
+  // 预定义规则引用(用于扩展)
+  PredefinedRules predefined = 10101;
+}
+
+// OneofOptions 扩展 - oneof 级别验证
+extend google.protobuf.OneofOptions {
+  // oneof 级别的验证规则
+  OneofRules oneof = 10100;
+}
+
+// ============================================================================
+// 核心规则定义
+// ============================================================================
+
+// CEL 验证规则
+// 使用 Common Expression Language 编写自定义验证逻辑
+message Rule {
+  // 规则唯一标识符
+  string id = 1;
+
+  // 错误消息(中文)
+  string message = 2;
+
+  // 错误消息(英文) - 可选,用于国际化
+  string message_en = 3;
+
+  // CEL 表达式 - 返回 true 表示验证通过
+  string expression = 4;
+}
+
+// 消息级别验证规则
+message MessageRules {
+  // CEL 自定义规则列表
+  repeated Rule cel = 1;
+
+  // 是否禁用所有字段验证
+  bool disabled = 2;
+
+  // 验证组 - 用于分组验证
+  repeated string groups = 3;
+}
+
+// Oneof 验证规则
+message OneofRules {
+  // 是否必须选择一个字段
+  bool required = 1;
+}
+
+// 字段级别验证规则
+message FieldRules {
+  // CEL 自定义规则列表
+  repeated Rule cel = 1;
+
+  // 字段是否必填 (Proto3 不需要 optional 关键字)
+  bool required = 2;
+
+  // 忽略策略
+  IgnoreRule ignore = 3;
+
+  // 验证组 - 只在指定组中验证
+  repeated string groups = 4;
+
+  // ========== 自定义错误消息 ==========
+  // 使用场景:
+  // 1. error_message: 覆盖所有类型验证规则的默认错误消息
+  // 2. required_message: 专门为 required 验证自定义错误消息
+  //
+  // 优先级: required_message > error_message > 默认消息
+  //
+  // 示例:
+  //   string password = 1 [(kuban.api.validate.field) = {
+  //     required: true,
+  //     required_message: "密码不能为空",      // required 验证失败时使用
+  //     error_message: "密码格式不符合要求",  // 其他验证失败时使用
+  //     string: { min_len: 8, max_len: 32 }
+  //   }];
+
+  // 通用错误消息(中文) - 覆盖所有验证规则的默认消息
+  string error_message = 5;
+
+  // 通用错误消息(英文)
+  string error_message_en = 6;
+
+  // required 验证专用错误消息(中文)
+  string required_message = 7;
+
+  // required 验证专用错误消息(英文)
+  string required_message_en = 8;
+
+  // 类型特定的验证规则
+  oneof type {
+    // 数值类型
+    FloatRules float = 10;
+    DoubleRules double = 11;
+    Int32Rules int32 = 12;
+    Int64Rules int64 = 13;
+    UInt32Rules uint32 = 14;
+    UInt64Rules uint64 = 15;
+    SInt32Rules sint32 = 16;
+    SInt64Rules sint64 = 17;
+    Fixed32Rules fixed32 = 18;
+    Fixed64Rules fixed64 = 19;
+    SFixed32Rules sfixed32 = 20;
+    SFixed64Rules sfixed64 = 21;
+
+    // 布尔和字符串
+    BoolRules bool = 30;
+    StringRules string = 31;
+    BytesRules bytes = 32;
+
+    // 复杂类型
+    EnumRules enum = 40;
+    RepeatedRules repeated = 41;
+    MapRules map = 42;
+
+    // Well-Known Types
+    DurationRules duration = 50;
+    TimestampRules timestamp = 51;
+  }
+}
+
+// 预定义规则(用于规则扩展)
+message PredefinedRules {
+  repeated Rule cel = 1;
+}
+
+// 忽略策略
+enum IgnoreRule {
+  // 未指定 - 默认行为(字段未设置时不验证)
+  IGNORE_UNSPECIFIED = 0;
+
+  // 字段为零值时忽略验证
+  IGNORE_IF_ZERO = 1;
+
+  // 始终忽略验证
+  IGNORE_ALWAYS = 2;
+
+  // 从不忽略验证(即使未设置也验证)
+  IGNORE_NEVER = 3;
+}
+
+// ============================================================================
+// 数值类型验证规则
+// ============================================================================
+
+// 浮点数验证规则
+message FloatRules {
+  // 常量值 - 字段必须等于此值
+  optional float const = 1;
+
+  // 小于
+  optional float lt = 2;
+
+  // 小于等于
+  optional float lte = 3;
+
+  // 大于
+  optional float gt = 4;
+
+  // 大于等于
+  optional float gte = 5;
+
+  // 在值列表中
+  repeated float in = 6;
+
+  // 不在值列表中
+  repeated float not_in = 7;
+
+  // 是否为有限数(非 NaN/Inf)
+  optional bool finite = 8;
+}
+
+// 双精度浮点数验证规则
+message DoubleRules {
+  optional double const = 1;
+  optional double lt = 2;
+  optional double lte = 3;
+  optional double gt = 4;
+  optional double gte = 5;
+  repeated double in = 6;
+  repeated double not_in = 7;
+  optional bool finite = 8;
+}
+
+// Int32 验证规则
+message Int32Rules {
+  optional int32 const = 1;
+  optional int32 lt = 2;
+  optional int32 lte = 3;
+  optional int32 gt = 4;
+  optional int32 gte = 5;
+  repeated int32 in = 6;
+  repeated int32 not_in = 7;
+}
+
+// Int64 验证规则
+message Int64Rules {
+  optional int64 const = 1;
+  optional int64 lt = 2;
+  optional int64 lte = 3;
+  optional int64 gt = 4;
+  optional int64 gte = 5;
+  repeated int64 in = 6;
+  repeated int64 not_in = 7;
+}
+
+// UInt32 验证规则
+message UInt32Rules {
+  optional uint32 const = 1;
+  optional uint32 lt = 2;
+  optional uint32 lte = 3;
+  optional uint32 gt = 4;
+  optional uint32 gte = 5;
+  repeated uint32 in = 6;
+  repeated uint32 not_in = 7;
+}
+
+// UInt64 验证规则
+message UInt64Rules {
+  optional uint64 const = 1;
+  optional uint64 lt = 2;
+  optional uint64 lte = 3;
+  optional uint64 gt = 4;
+  optional uint64 gte = 5;
+  repeated uint64 in = 6;
+  repeated uint64 not_in = 7;
+}
+
+// SInt32 验证规则
+message SInt32Rules {
+  optional sint32 const = 1;
+  optional sint32 lt = 2;
+  optional sint32 lte = 3;
+  optional sint32 gt = 4;
+  optional sint32 gte = 5;
+  repeated sint32 in = 6;
+  repeated sint32 not_in = 7;
+}
+
+// SInt64 验证规则
+message SInt64Rules {
+  optional sint64 const = 1;
+  optional sint64 lt = 2;
+  optional sint64 lte = 3;
+  optional sint64 gt = 4;
+  optional sint64 gte = 5;
+  repeated sint64 in = 6;
+  repeated sint64 not_in = 7;
+}
+
+// Fixed32 验证规则
+message Fixed32Rules {
+  optional fixed32 const = 1;
+  optional fixed32 lt = 2;
+  optional fixed32 lte = 3;
+  optional fixed32 gt = 4;
+  optional fixed32 gte = 5;
+  repeated fixed32 in = 6;
+  repeated fixed32 not_in = 7;
+}
+
+// Fixed64 验证规则
+message Fixed64Rules {
+  optional fixed64 const = 1;
+  optional fixed64 lt = 2;
+  optional fixed64 lte = 3;
+  optional fixed64 gt = 4;
+  optional fixed64 gte = 5;
+  repeated fixed64 in = 6;
+  repeated fixed64 not_in = 7;
+}
+
+// SFixed32 验证规则
+message SFixed32Rules {
+  optional sfixed32 const = 1;
+  optional sfixed32 lt = 2;
+  optional sfixed32 lte = 3;
+  optional sfixed32 gt = 4;
+  optional sfixed32 gte = 5;
+  repeated sfixed32 in = 6;
+  repeated sfixed32 not_in = 7;
+}
+
+// SFixed64 验证规则
+message SFixed64Rules {
+  optional sfixed64 const = 1;
+  optional sfixed64 lt = 2;
+  optional sfixed64 lte = 3;
+  optional sfixed64 gt = 4;
+  optional sfixed64 gte = 5;
+  repeated sfixed64 in = 6;
+  repeated sfixed64 not_in = 7;
+}
+
+// ============================================================================
+// 字符串验证规则
+// ============================================================================
+
+// 布尔值验证规则
+message BoolRules {
+  optional bool const = 1;
+}
+
+// 字符串验证规则 - 增强的中文支持
+message StringRules {
+  // 常量值
+  optional string const = 1;
+
+  // 长度限制(字符数,非字节数)
+  optional uint64 len = 2;
+  optional uint64 min_len = 3;
+  optional uint64 max_len = 4;
+
+  // 字节长度限制
+  optional uint64 len_bytes = 5;
+  optional uint64 min_bytes = 6;
+  optional uint64 max_bytes = 7;
+
+  // 模式匹配
+  optional string pattern = 8;        // 正则表达式
+
+  // 前缀/后缀
+  optional string prefix = 9;
+  optional string suffix = 10;
+
+  // 包含/不包含
+  optional string contains = 11;
+  optional string not_contains = 12;
+
+  // 在值列表中
+  repeated string in = 13;
+  repeated string not_in = 14;
+
+  // 预定义格式(优化设计 - 更简洁)
+  oneof well_known {
+    bool email = 20;           // 邮箱格式
+    bool hostname = 21;        // 主机名
+    bool ip = 22;              // IP 地址(v4/v6)
+    bool ipv4 = 23;            // IPv4
+    bool ipv6 = 24;            // IPv6
+    bool uri = 25;             // URI
+    bool uri_ref = 26;         // URI 引用
+    bool uuid = 27;            // UUID
+
+    // 中文业务格式 - 这是优化点!
+    bool chinese_mobile = 30;  // 中国手机号
+    bool chinese_id_card = 31; // 中国身份证号
+    bool chinese_name = 32;    // 中文姓名
+    bool chinese_postcode = 33; // 中国邮政编码
+  }
+
+  // 字符类型限制
+  optional bool ascii = 40;          // 仅 ASCII 字符
+  optional bool printable = 41;      // 可打印字符
+  optional bool alpha = 42;          // 仅字母
+  optional bool alphanumeric = 43;   // 字母和数字
+  optional bool numeric = 44;        // 仅数字
+
+  // 大小写要求
+  optional bool lowercase = 50;      // 仅小写
+  optional bool uppercase = 51;      // 仅大写
+}
+
+// 字节数组验证规则
+message BytesRules {
+  optional bytes const = 1;
+  optional uint64 len = 2;
+  optional uint64 min_len = 3;
+  optional uint64 max_len = 4;
+  optional bytes pattern = 5;
+  optional bytes prefix = 6;
+  optional bytes suffix = 7;
+  optional bytes contains = 8;
+  repeated bytes in = 9;
+  repeated bytes not_in = 10;
+
+  // Well-known 格式
+  oneof well_known {
+    bool ip = 20;
+    bool ipv4 = 21;
+    bool ipv6 = 22;
+  }
+}
+
+// ============================================================================
+// 复杂类型验证规则
+// ============================================================================
+
+// 枚举验证规则
+message EnumRules {
+  optional int32 const = 1;
+  optional bool defined_only = 2;   // 仅允许已定义的枚举值
+  repeated int32 in = 3;
+  repeated int32 not_in = 4;
+}
+
+// 重复字段验证规则
+message RepeatedRules {
+  optional uint64 min_items = 1;    // 最小元素数
+  optional uint64 max_items = 2;    // 最大元素数
+  optional bool unique = 3;         // 元素必须唯一
+  FieldRules items = 4;             // 元素验证规则
+}
+
+// Map 验证规则
+message MapRules {
+  optional uint64 min_pairs = 1;    // 最小键值对数
+  optional uint64 max_pairs = 2;    // 最大键值对数
+  FieldRules keys = 3;              // 键验证规则
+  FieldRules values = 4;            // 值验证规则
+}
+
+// ============================================================================
+// Well-Known Types 验证规则
+// ============================================================================
+
+// Duration 验证规则
+message DurationRules {
+  optional bool required = 1;
+
+  // Duration 常量
+  optional int64 const_seconds = 2;
+  optional int32 const_nanos = 3;
+
+  // 范围限制
+  optional int64 lt_seconds = 4;
+  optional int64 lte_seconds = 5;
+  optional int64 gt_seconds = 6;
+  optional int64 gte_seconds = 7;
+
+  // 在值列表中
+  repeated int64 in_seconds = 8;
+  repeated int64 not_in_seconds = 9;
+}
+
+// Timestamp 验证规则
+message TimestampRules {
+  optional bool required = 1;
+
+  // Timestamp 常量(Unix 秒)
+  optional int64 const = 2;
+
+  // 范围限制
+  optional int64 lt = 3;
+  optional int64 lte = 4;
+  optional int64 gt = 5;
+  optional int64 gte = 6;
+
+  // 相对时间限制
+  optional bool lt_now = 7;         // 必须在当前时间之前
+  optional bool gt_now = 8;         // 必须在当前时间之后
+
+  // 时间范围(从现在开始的偏移量,秒)
+  optional int64 within_seconds = 9;  // 必须在现在的 N 秒内
+}

+ 539 - 0
proto/kuban/api/validate/validate_example.proto

@@ -0,0 +1,539 @@
+// Copyright 2025 Kuban Technologies
+//
+// 验证系统使用示例
+// 展示如何使用 kuban.api.validate 验证框架
+
+syntax = "proto3";
+
+package kuban.api.example;
+
+import "kuban/api/validate/validate.proto";
+// import "kuban/api/validate/business_rules.proto";  // 未使用
+// import "kuban/api/validate/rule_groups.proto";  // 未使用
+
+option go_package = "git.ikuban.com/server/kubanapis/kuban/api/example;example";
+
+// ============================================================================
+// 示例 1: 基本字段验证
+// ============================================================================
+
+message BasicValidationExample {
+  // 必填字符串,长度 2-50
+  string name = 1 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      min_len: 2,
+      max_len: 50
+    }
+  }];
+
+  // 必填邮箱
+  string email = 2 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      email: true
+    }
+  }];
+
+  // 年龄范围 0-150
+  int32 age = 3 [(kuban.api.validate.field) = {
+    int32: {
+      gte: 0,
+      lte: 150
+    }
+  }];
+
+  // 可选字段,设置时必须符合 URL 格式
+  optional string website = 4 [(kuban.api.validate.field) = {
+    string: {
+      uri: true
+    }
+  }];
+}
+
+// ============================================================================
+// 示例 2: 中文业务验证
+// ============================================================================
+
+message ChineseBusinessExample {
+  // 中国手机号验证(简化方式)
+  string mobile = 1 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      chinese_mobile: true  // 使用内置的中国手机号验证
+    }
+  }];
+
+  // 中国手机号验证(带自定义错误消息)
+  string mobile_advanced = 2 [(kuban.api.validate.field) = {
+    required: true,
+    error_message: "请输入有效的中国大陆手机号",
+    string: {
+      chinese_mobile: true
+    }
+  }];
+
+  // 中国身份证验证
+  string id_card = 3 [(kuban.api.validate.field) = {
+    required: true,
+    error_message: "请输入有效的18位身份证号",
+    string: {
+      chinese_id_card: true
+    }
+  }];
+
+  // 中文姓名验证
+  string chinese_name = 4 [(kuban.api.validate.field) = {
+    required: true,
+    error_message: "请输入2-20个字符的中文姓名",
+    string: {
+      chinese_name: true,
+      min_len: 2,
+      max_len: 20
+    }
+  }];
+
+  // 统一社会信用代码(使用 CEL 或正则表达式验证)
+  string uscc = 5 [(kuban.api.validate.field) = {
+    error_message: "请输入有效的企业统一社会信用代码(18位)",
+    string: {
+      pattern: "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$",
+      len: 18
+    }
+  }];
+
+  // 银行卡号(使用正则表达式和长度验证)
+  string bank_card = 6 [(kuban.api.validate.field) = {
+    error_message: "请输入有效的银行卡号(16-19位)",
+    string: {
+      pattern: "^\\d{16,19}$",
+      min_len: 16,
+      max_len: 19
+    }
+  }];
+
+  // 中国邮政编码
+  string postcode = 7 [(kuban.api.validate.field) = {
+    error_message: "请输入有效的6位邮政编码",
+    string: {
+      chinese_postcode: true
+    }
+  }];
+}
+
+// ============================================================================
+// 示例 3: 使用 CEL 自定义验证
+// ============================================================================
+
+message CustomCELExample {
+  string username = 1 [(kuban.api.validate.field) = {
+    required: true,
+    cel: [
+      {
+        id: "username.format",
+        message: "用户名只能包含字母、数字和下划线",
+        expression: "this.matches('^[a-zA-Z0-9_]+$')"
+      },
+      {
+        id: "username.no_admin",
+        message: "用户名不能包含 'admin'",
+        expression: "!this.contains('admin')"
+      }
+    ],
+    string: {
+      min_len: 3,
+      max_len: 20
+    }
+  }];
+
+  int32 score = 2 [(kuban.api.validate.field) = {
+    cel: [
+      {
+        id: "score.range",
+        message: "分数必须在 0-100 之间",
+        message_en: "Score must be between 0 and 100",
+        expression: "this >= 0 && this <= 100"
+      }
+    ]
+  }];
+
+  // 跨字段验证
+  string password = 3;
+  string password_confirm = 4 [(kuban.api.validate.field) = {
+    cel: [
+      {
+        id: "password.match",
+        message: "两次输入的密码不一致",
+        expression: "this == this.password"  // 引用同一消息的其他字段
+      }
+    ]
+  }];
+}
+
+// ============================================================================
+// 示例 4: 分组验证
+// ============================================================================
+
+message GroupValidationExample {
+  // 用户名在创建和更新时都需要验证
+  string username = 1 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["create", "update"],
+    string: {
+      min_len: 3,
+      max_len: 20
+    }
+  }];
+
+  // 密码仅在创建和修改密码时需要验证
+  string password = 2 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["create", "change_password"],
+    string: {
+      min_len: 8,
+      max_len: 32
+    }
+  }];
+
+  // 手机号在实名认证时必填
+  string mobile = 3 [(kuban.api.validate.field) = {
+    groups: ["real_name_auth"],
+    required: true,
+    string: {
+      chinese_mobile: true
+    }
+  }];
+
+  // 可选字段,但在严格模式下必填
+  optional string nickname = 4 [(kuban.api.validate.field) = {
+    groups: ["strict"],
+    required: true,
+    string: {
+      min_len: 2,
+      max_len: 30
+    }
+  }];
+}
+
+// ============================================================================
+// 示例 5: 复杂类型验证
+// ============================================================================
+
+message ComplexTypeExample {
+  // 重复字段验证
+  repeated string tags = 1 [(kuban.api.validate.field) = {
+    repeated: {
+      min_items: 1,
+      max_items: 10,
+      unique: true,
+      items: {
+        string: {
+          min_len: 2,
+          max_len: 20
+        }
+      }
+    }
+  }];
+
+  // Map 验证
+  map<string, int32> scores = 2 [(kuban.api.validate.field) = {
+    map: {
+      min_pairs: 1,
+      max_pairs: 100,
+      keys: {
+        string: {
+          min_len: 1,
+          max_len: 50
+        }
+      },
+      values: {
+        int32: {
+          gte: 0,
+          lte: 100
+        }
+      }
+    }
+  }];
+
+  // 嵌套消息验证
+  Address address = 3 [(kuban.api.validate.field) = {
+    required: true
+  }];
+}
+
+message Address {
+  string province = 1 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      min_len: 2,
+      max_len: 20
+    }
+  }];
+
+  string city = 2 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      min_len: 2,
+      max_len: 20
+    }
+  }];
+
+  string detail = 3 [(kuban.api.validate.field) = {
+    required: true,
+    string: {
+      min_len: 5,
+      max_len: 200
+    }
+  }];
+
+  string postcode = 4 [(kuban.api.validate.field) = {
+    string: {
+      chinese_postcode: true
+    }
+  }];
+}
+
+// ============================================================================
+// 示例 6: 消息级别验证
+// ============================================================================
+
+message MessageLevelExample {
+  option (kuban.api.validate.message) = {
+    cel: [
+      {
+        id: "date_range.valid",
+        message: "结束日期必须大于开始日期",
+        expression: "this.end_date > this.start_date"
+      },
+      {
+        id: "required_fields",
+        message: "姓名和手机号至少需要填写一个",
+        expression: "has(this.name) || has(this.mobile)"
+      }
+    ],
+    groups: ["create", "update"]
+  };
+
+  optional string name = 1;
+  optional string mobile = 2;
+  int64 start_date = 3;
+  int64 end_date = 4;
+}
+
+// ============================================================================
+// 示例 7: Oneof 验证
+// ============================================================================
+
+message OneofExample {
+  // 联系方式:邮箱和手机号必须选择一个
+  oneof contact {
+    option (kuban.api.validate.oneof).required = true;
+
+    string email = 1 [(kuban.api.validate.field) = {
+      string: { email: true }
+    }];
+
+    string mobile = 2 [(kuban.api.validate.field) = {
+      string: { chinese_mobile: true }
+    }];
+  }
+}
+
+// ============================================================================
+// 示例 8: 忽略策略
+// ============================================================================
+
+message IgnoreRuleExample {
+  // 仅在值不为空时验证
+  optional string optional_url = 1 [(kuban.api.validate.field) = {
+    ignore: IGNORE_IF_ZERO,
+    string: {
+      uri: true
+    }
+  }];
+
+  // 始终验证(即使未设置)
+  optional string required_email = 2 [(kuban.api.validate.field) = {
+    ignore: IGNORE_NEVER,
+    required: true,
+    string: {
+      email: true
+    }
+  }];
+
+  // 暂时忽略验证(用于开发阶段)
+  string temp_field = 3 [(kuban.api.validate.field) = {
+    ignore: IGNORE_ALWAYS,
+    string: {
+      min_len: 10  // 这个规则不会生效
+    }
+  }];
+}
+
+// ============================================================================
+// 示例 9: 实际业务场景 - 用户注册
+// ============================================================================
+
+message UserRegistrationRequest {
+  option (kuban.api.validate.message) = {
+    groups: ["register"]
+  };
+
+  // 用户名
+  string username = 1 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: {
+      min_len: 3,
+      max_len: 20,
+      pattern: "^[a-zA-Z0-9_]+$"
+    },
+    cel: [
+      {
+        id: "username.reserved",
+        message: "该用户名为系统保留,不可使用",
+        expression: "!['admin', 'root', 'system'].contains(this.toLowerCase())"
+      }
+    ]
+  }];
+
+  // 密码
+  string password = 2 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: {
+      min_len: 8,
+      max_len: 32
+    },
+    cel: [
+      {
+        id: "password.complexity",
+        message: "密码必须包含大小写字母、数字和特殊字符",
+        expression: "this.matches('(?=.*[a-z])(?=.*[A-Z])(?=.*\\\\d)(?=.*[@$!%*?&])[A-Za-z\\\\d@$!%*?&]+')"
+      }
+    ]
+  }];
+
+  // 手机号
+  string mobile = 3 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: {
+      chinese_mobile: true
+    }
+  }];
+
+  // 验证码
+  string verification_code = 4 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    string: {
+      len: 6,
+      numeric: true
+    }
+  }];
+
+  // 邮箱(可选)
+  optional string email = 5 [(kuban.api.validate.field) = {
+    groups: ["register"],
+    ignore: IGNORE_IF_ZERO,
+    string: {
+      email: true
+    }
+  }];
+
+  // 同意服务条款
+  bool agree_terms = 6 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["register"],
+    bool: {
+      const: true
+    },
+    cel: [
+      {
+        id: "agree_terms.must_true",
+        message: "必须同意服务条款才能注册",
+        expression: "this == true"
+      }
+    ]
+  }];
+}
+
+// ============================================================================
+// 示例 10: 实际业务场景 - 企业认证
+// ============================================================================
+
+message EnterpriseAuthRequest {
+  option (kuban.api.validate.message) = {
+    groups: ["enterprise_auth"],
+    cel: [
+      {
+        id: "complete_info",
+        message: "企业认证信息不完整",
+        expression: "has(this.company_name) && has(this.uscc) && has(this.legal_person)"
+      }
+    ]
+  };
+
+  // 企业名称
+  string company_name = 1 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    string: {
+      min_len: 2,
+      max_len: 100
+    }
+  }];
+
+  // 统一社会信用代码
+  string uscc = 2 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    error_message: "请输入有效的企业统一社会信用代码(18位)",
+    string: {
+      pattern: "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$",
+      len: 18
+    }
+  }];
+
+  // 法人代表姓名
+  string legal_person = 3 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    error_message: "请输入2-20个字符的中文姓名",
+    string: {
+      chinese_name: true,
+      min_len: 2,
+      max_len: 20
+    }
+  }];
+
+  // 法人身份证号
+  string legal_person_id_card = 4 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    error_message: "请输入有效的18位身份证号",
+    string: {
+      chinese_id_card: true
+    }
+  }];
+
+  // 企业联系电话
+  string contact_phone = 5 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    string: {
+      chinese_mobile: true
+    }
+  }];
+
+  // 营业执照附件
+  bytes business_license_image = 6 [(kuban.api.validate.field) = {
+    required: true,
+    groups: ["enterprise_auth"],
+    bytes: {
+      min_len: 1024,           // 至少 1KB
+      max_len: 5242880         // 最大 5MB
+    }
+  }];
+}

+ 5004 - 0
proto/protovalidate/buf/validate/validate.proto

@@ -0,0 +1,5004 @@
+// Copyright 2023-2025 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+
+package buf.validate;
+
+import "google/protobuf/descriptor.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+
+option go_package = "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate";
+option java_multiple_files = true;
+option java_outer_classname = "ValidateProto";
+option java_package = "build.buf.validate";
+
+// MessageOptions is an extension to google.protobuf.MessageOptions. It allows
+// the addition of validation rules at the message level. These rules can be
+// applied to incoming messages to ensure they meet certain criteria before
+// being processed.
+extend google.protobuf.MessageOptions {
+  // Rules specify the validations to be performed on this message. By default,
+  // no validation is performed against a message.
+  optional MessageRules message = 1159;
+}
+
+// OneofOptions is an extension to google.protobuf.OneofOptions. It allows
+// the addition of validation rules on a oneof. These rules can be
+// applied to incoming messages to ensure they meet certain criteria before
+// being processed.
+extend google.protobuf.OneofOptions {
+  // Rules specify the validations to be performed on this oneof. By default,
+  // no validation is performed against a oneof.
+  optional OneofRules oneof = 1159;
+}
+
+// FieldOptions is an extension to google.protobuf.FieldOptions. It allows
+// the addition of validation rules at the field level. These rules can be
+// applied to incoming messages to ensure they meet certain criteria before
+// being processed.
+extend google.protobuf.FieldOptions {
+  // Rules specify the validations to be performed on this field. By default,
+  // no validation is performed against a field.
+  optional FieldRules field = 1159;
+
+  // Specifies predefined rules. When extending a standard rule message,
+  // this adds additional CEL expressions that apply when the extension is used.
+  //
+  // ```proto
+  // extend buf.validate.Int32Rules {
+  //   bool is_zero [(buf.validate.predefined).cel = {
+  //     id: "int32.is_zero",
+  //     message: "value must be zero",
+  //     expression: "!rule || this == 0",
+  //   }];
+  // }
+  //
+  // message Foo {
+  //   int32 reserved = 1 [(buf.validate.field).int32.(is_zero) = true];
+  // }
+  // ```
+  optional PredefinedRules predefined = 1160;
+}
+
+// `Rule` represents a validation rule written in the Common Expression
+// Language (CEL) syntax. Each Rule includes a unique identifier, an
+// optional error message, and the CEL expression to evaluate. For more
+// information, [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
+//
+// ```proto
+// message Foo {
+//   option (buf.validate.message).cel = {
+//     id: "foo.bar"
+//     message: "bar must be greater than 0"
+//     expression: "this.bar > 0"
+//   };
+//   int32 bar = 1;
+// }
+// ```
+message Rule {
+  // `id` is a string that serves as a machine-readable name for this Rule.
+  // It should be unique within its scope, which could be either a message or a field.
+  optional string id = 1;
+
+  // `message` is an optional field that provides a human-readable error message
+  // for this Rule when the CEL expression evaluates to false. If a
+  // non-empty message is provided, any strings resulting from the CEL
+  // expression evaluation are ignored.
+  optional string message = 2;
+
+  // `expression` is the actual CEL expression that will be evaluated for
+  // validation. This string must resolve to either a boolean or a string
+  // value. If the expression evaluates to false or a non-empty string, the
+  // validation is considered failed, and the message is rejected.
+  optional string expression = 3;
+}
+
+// MessageRules represents validation rules that are applied to the entire message.
+// It includes disabling options and a list of Rule messages representing Common Expression Language (CEL) validation rules.
+message MessageRules {
+  // `cel` is a repeated field of type Rule. Each Rule specifies a validation rule to be applied to this message.
+  // These rules are written in Common Expression Language (CEL) syntax. For more information,
+  // [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
+  //
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `foo` must be greater than 42.
+  //   option (buf.validate.message).cel = {
+  //     id: "my_message.value",
+  //     message: "value must be greater than 42",
+  //     expression: "this.foo > 42",
+  //   };
+  //   optional int32 foo = 1;
+  // }
+  // ```
+  repeated Rule cel = 3;
+
+  // `oneof` is a repeated field of type MessageOneofRule that specifies a list of fields
+  // of which at most one can be present. If `required` is also specified, then exactly one
+  // of the specified fields _must_ be present.
+  //
+  // This will enforce oneof-like constraints with a few features not provided by
+  // actual Protobuf oneof declarations:
+  //   1. Repeated and map fields are allowed in this validation. In a Protobuf oneof,
+  //      only scalar fields are allowed.
+  //   2. Fields with implicit presence are allowed. In a Protobuf oneof, all member
+  //      fields have explicit presence. This means that, for the purpose of determining
+  //      how many fields are set, explicitly setting such a field to its zero value is
+  //      effectively the same as not setting it at all.
+  //   3. This will always generate validation errors for a message unmarshalled from
+  //      serialized data that sets more than one field. With a Protobuf oneof, when
+  //      multiple fields are present in the serialized form, earlier values are usually
+  //      silently ignored when unmarshalling, with only the last field being set when
+  //      unmarshalling completes.
+  //
+  // Note that adding a field to a `oneof` will also set the IGNORE_IF_ZERO_VALUE on the fields. This means
+  // only the field that is set will be validated and the unset fields are not validated according to the field rules.
+  // This behavior can be overridden by setting `ignore` against a field.
+  //
+  // ```proto
+  // message MyMessage {
+  //   // Only one of `field1` or `field2` _can_ be present in this message.
+  //   option (buf.validate.message).oneof = { fields: ["field1", "field2"] };
+  //   // Exactly one of `field3` or `field4` _must_ be present in this message.
+  //   option (buf.validate.message).oneof = { fields: ["field3", "field4"], required: true };
+  //   string field1 = 1;
+  //   bytes field2 = 2;
+  //   bool field3 = 3;
+  //   int32 field4 = 4;
+  // }
+  // ```
+  repeated MessageOneofRule oneof = 4;
+
+  reserved 1;
+  reserved "disabled";
+}
+
+message MessageOneofRule {
+  // A list of field names to include in the oneof. All field names must be
+  // defined in the message. At least one field must be specified, and
+  // duplicates are not permitted.
+  repeated string fields = 1;
+  // If true, one of the fields specified _must_ be set.
+  optional bool required = 2;
+}
+
+// The `OneofRules` message type enables you to manage rules for
+// oneof fields in your protobuf messages.
+message OneofRules {
+  // If `required` is true, exactly one field of the oneof must be set. A
+  // validation error is returned if no fields in the oneof are set. Further rules
+  // should be placed on the fields themselves to ensure they are valid values,
+  // such as `min_len` or `gt`.
+  //
+  // ```proto
+  // message MyMessage {
+  //   oneof value {
+  //     // Either `a` or `b` must be set. If `a` is set, it must also be
+  //     // non-empty; whereas if `b` is set, it can still be an empty string.
+  //     option (buf.validate.oneof).required = true;
+  //     string a = 1 [(buf.validate.field).string.min_len = 1];
+  //     string b = 2;
+  //   }
+  // }
+  // ```
+  optional bool required = 1;
+}
+
+// FieldRules encapsulates the rules for each type of field. Depending on
+// the field, the correct set should be used to ensure proper validations.
+message FieldRules {
+  // `cel` is a repeated field used to represent a textual expression
+  // in the Common Expression Language (CEL) syntax. For more information,
+  // [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `value` must be greater than 42.
+  //   optional int32 value = 1 [(buf.validate.field).cel = {
+  //     id: "my_message.value",
+  //     message: "value must be greater than 42",
+  //     expression: "this > 42",
+  //   }];
+  // }
+  // ```
+  repeated Rule cel = 23;
+  // If `required` is true, the field must be set. A validation error is returned
+  // if the field is not set.
+  //
+  // ```proto
+  // syntax="proto3";
+  //
+  // message FieldsWithPresence {
+  //   // Requires any string to be set, including the empty string.
+  //   optional string link = 1 [
+  //     (buf.validate.field).required = true
+  //   ];
+  //   // Requires true or false to be set.
+  //   optional bool disabled = 2 [
+  //     (buf.validate.field).required = true
+  //   ];
+  //   // Requires a message to be set, including the empty message.
+  //   SomeMessage msg = 4 [
+  //     (buf.validate.field).required = true
+  //   ];
+  // }
+  // ```
+  //
+  // All fields in the example above track presence. By default, Protovalidate
+  // ignores rules on those fields if no value is set. `required` ensures that
+  // the fields are set and valid.
+  //
+  // Fields that don't track presence are always validated by Protovalidate,
+  // whether they are set or not. It is not necessary to add `required`. It
+  // can be added to indicate that the field cannot be the zero value.
+  //
+  // ```proto
+  // syntax="proto3";
+  //
+  // message FieldsWithoutPresence {
+  //   // `string.email` always applies, even to an empty string.
+  //   string link = 1 [
+  //     (buf.validate.field).string.email = true
+  //   ];
+  //   // `repeated.min_items` always applies, even to an empty list.
+  //   repeated string labels = 2 [
+  //     (buf.validate.field).repeated.min_items = 1
+  //   ];
+  //   // `required`, for fields that don't track presence, indicates
+  //   // the value of the field can't be the zero value.
+  //   int32 zero_value_not_allowed = 3 [
+  //     (buf.validate.field).required = true
+  //   ];
+  // }
+  // ```
+  //
+  // To learn which fields track presence, see the
+  // [Field Presence cheat sheet](https://protobuf.dev/programming-guides/field_presence/#cheat).
+  //
+  // Note: While field rules can be applied to repeated items, map keys, and map
+  // values, the elements are always considered to be set. Consequently,
+  // specifying `repeated.items.required` is redundant.
+  optional bool required = 25;
+  // Ignore validation rules on the field if its value matches the specified
+  // criteria. See the `Ignore` enum for details.
+  //
+  // ```proto
+  // message UpdateRequest {
+  //   // The uri rule only applies if the field is not an empty string.
+  //   string url = 1 [
+  //     (buf.validate.field).ignore = IGNORE_IF_ZERO_VALUE,
+  //     (buf.validate.field).string.uri = true
+  //   ];
+  // }
+  // ```
+  optional Ignore ignore = 27;
+
+  oneof type {
+    // Scalar Field Types
+    FloatRules float = 1;
+    DoubleRules double = 2;
+    Int32Rules int32 = 3;
+    Int64Rules int64 = 4;
+    UInt32Rules uint32 = 5;
+    UInt64Rules uint64 = 6;
+    SInt32Rules sint32 = 7;
+    SInt64Rules sint64 = 8;
+    Fixed32Rules fixed32 = 9;
+    Fixed64Rules fixed64 = 10;
+    SFixed32Rules sfixed32 = 11;
+    SFixed64Rules sfixed64 = 12;
+    BoolRules bool = 13;
+    StringRules string = 14;
+    BytesRules bytes = 15;
+
+    // Complex Field Types
+    EnumRules enum = 16;
+    RepeatedRules repeated = 18;
+    MapRules map = 19;
+
+    // Well-Known Field Types
+    AnyRules any = 20;
+    DurationRules duration = 21;
+    TimestampRules timestamp = 22;
+  }
+
+  reserved 24, 26;
+  reserved "skipped", "ignore_empty";
+}
+
+// PredefinedRules are custom rules that can be re-used with
+// multiple fields.
+message PredefinedRules {
+  // `cel` is a repeated field used to represent a textual expression
+  // in the Common Expression Language (CEL) syntax. For more information,
+  // [see our documentation](https://buf.build/docs/protovalidate/schemas/predefined-rules/).
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `value` must be greater than 42.
+  //   optional int32 value = 1 [(buf.validate.predefined).cel = {
+  //     id: "my_message.value",
+  //     message: "value must be greater than 42",
+  //     expression: "this > 42",
+  //   }];
+  // }
+  // ```
+  repeated Rule cel = 1;
+
+  reserved 24, 26;
+  reserved "skipped", "ignore_empty";
+}
+
+// Specifies how `FieldRules.ignore` behaves, depending on the field's value, and
+// whether the field tracks presence.
+enum Ignore {
+  // Ignore rules if the field tracks presence and is unset. This is the default
+  // behavior.
+  //
+  // In proto3, only message fields, members of a Protobuf `oneof`, and fields
+  // with the `optional` label track presence. Consequently, the following fields
+  // are always validated, whether a value is set or not:
+  //
+  // ```proto
+  // syntax="proto3";
+  //
+  // message RulesApply {
+  //   string email = 1 [
+  //     (buf.validate.field).string.email = true
+  //   ];
+  //   int32 age = 2 [
+  //     (buf.validate.field).int32.gt = 0
+  //   ];
+  //   repeated string labels = 3 [
+  //     (buf.validate.field).repeated.min_items = 1
+  //   ];
+  // }
+  // ```
+  //
+  // In contrast, the following fields track presence, and are only validated if
+  // a value is set:
+  //
+  // ```proto
+  // syntax="proto3";
+  //
+  // message RulesApplyIfSet {
+  //   optional string email = 1 [
+  //     (buf.validate.field).string.email = true
+  //   ];
+  //   oneof ref {
+  //     string reference = 2 [
+  //       (buf.validate.field).string.uuid = true
+  //     ];
+  //     string name = 3 [
+  //       (buf.validate.field).string.min_len = 4
+  //     ];
+  //   }
+  //   SomeMessage msg = 4 [
+  //     (buf.validate.field).cel = {/* ... */}
+  //   ];
+  // }
+  // ```
+  //
+  // To ensure that such a field is set, add the `required` rule.
+  //
+  // To learn which fields track presence, see the
+  // [Field Presence cheat sheet](https://protobuf.dev/programming-guides/field_presence/#cheat).
+  IGNORE_UNSPECIFIED = 0;
+
+  // Ignore rules if the field is unset, or set to the zero value.
+  //
+  // The zero value depends on the field type:
+  // - For strings, the zero value is the empty string.
+  // - For bytes, the zero value is empty bytes.
+  // - For bool, the zero value is false.
+  // - For numeric types, the zero value is zero.
+  // - For enums, the zero value is the first defined enum value.
+  // - For repeated fields, the zero is an empty list.
+  // - For map fields, the zero is an empty map.
+  // - For message fields, absence of the message (typically a null-value) is considered zero value.
+  //
+  // For fields that track presence (e.g. adding the `optional` label in proto3),
+  // this a no-op and behavior is the same as the default `IGNORE_UNSPECIFIED`.
+  IGNORE_IF_ZERO_VALUE = 1;
+
+  // Always ignore rules, including the `required` rule.
+  //
+  // This is useful for ignoring the rules of a referenced message, or to
+  // temporarily ignore rules during development.
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field's rules will always be ignored, including any validations
+  //   // on value's fields.
+  //   MyOtherMessage value = 1 [
+  //     (buf.validate.field).ignore = IGNORE_ALWAYS
+  //   ];
+  // }
+  // ```
+  IGNORE_ALWAYS = 3;
+
+  reserved 2;
+  reserved "IGNORE_EMPTY", "IGNORE_DEFAULT", "IGNORE_IF_DEFAULT_VALUE", "IGNORE_IF_UNPOPULATED";
+}
+
+// FloatRules describes the rules applied to `float` values. These
+// rules may also be applied to the `google.protobuf.FloatValue` Well-Known-Type.
+message FloatRules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyFloat {
+  //   // value must equal 42.0
+  //   float value = 1 [(buf.validate.field).float.const = 42.0];
+  // }
+  // ```
+  optional float const = 1 [(predefined).cel = {
+    id: "float.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be less than 10.0
+    //   float value = 1 [(buf.validate.field).float.lt = 10.0];
+    // }
+    // ```
+    float lt = 2 [(predefined).cel = {
+      id: "float.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be less than or equal to 10.0
+    //   float value = 1 [(buf.validate.field).float.lte = 10.0];
+    // }
+    // ```
+    float lte = 3 [(predefined).cel = {
+      id: "float.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be greater than 5.0 [float.gt]
+    //   float value = 1 [(buf.validate.field).float.gt = 5.0];
+    //
+    //   // value must be greater than 5 and less than 10.0 [float.gt_lt]
+    //   float other_value = 2 [(buf.validate.field).float = { gt: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than 10 or less than 5.0 [float.gt_lt_exclusive]
+    //   float another_value = 3 [(buf.validate.field).float = { gt: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    float gt = 4 [
+      (predefined).cel = {
+        id: "float.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be greater than or equal to 5.0 [float.gte]
+    //   float value = 1 [(buf.validate.field).float.gte = 5.0];
+    //
+    //   // value must be greater than or equal to 5.0 and less than 10.0 [float.gte_lt]
+    //   float other_value = 2 [(buf.validate.field).float = { gte: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than or equal to 10.0 or less than 5.0 [float.gte_lt_exclusive]
+    //   float another_value = 3 [(buf.validate.field).float = { gte: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    float gte = 5 [
+      (predefined).cel = {
+        id: "float.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MyFloat {
+  //   // value must be in list [1.0, 2.0, 3.0]
+  //   float value = 1 [(buf.validate.field).float = { in: [1.0, 2.0, 3.0] }];
+  // }
+  // ```
+  repeated float in = 6 [(predefined).cel = {
+    id: "float.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyFloat {
+  //   // value must not be in list [1.0, 2.0, 3.0]
+  //   float value = 1 [(buf.validate.field).float = { not_in: [1.0, 2.0, 3.0] }];
+  // }
+  // ```
+  repeated float not_in = 7 [(predefined).cel = {
+    id: "float.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `finite` requires the field value to be finite. If the field value is
+  // infinite or NaN, an error message is generated.
+  optional bool finite = 8 [(predefined).cel = {
+    id: "float.finite"
+    expression: "rules.finite ? (this.isNan() || this.isInf() ? 'value must be finite' : '') : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFloat {
+  //   float value = 1 [
+  //     (buf.validate.field).float.example = 1.0,
+  //     (buf.validate.field).float.example = inf
+  //   ];
+  // }
+  // ```
+  repeated float example = 9 [(predefined).cel = {
+    id: "float.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// DoubleRules describes the rules applied to `double` values. These
+// rules may also be applied to the `google.protobuf.DoubleValue` Well-Known-Type.
+message DoubleRules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyDouble {
+  //   // value must equal 42.0
+  //   double value = 1 [(buf.validate.field).double.const = 42.0];
+  // }
+  // ```
+  optional double const = 1 [(predefined).cel = {
+    id: "double.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be less than 10.0
+    //   double value = 1 [(buf.validate.field).double.lt = 10.0];
+    // }
+    // ```
+    double lt = 2 [(predefined).cel = {
+      id: "double.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified value
+    // (field <= value). If the field value is greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be less than or equal to 10.0
+    //   double value = 1 [(buf.validate.field).double.lte = 10.0];
+    // }
+    // ```
+    double lte = 3 [(predefined).cel = {
+      id: "double.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or `lte`,
+    // the range is reversed, and the field value must be outside the specified
+    // range. If the field value doesn't meet the required conditions, an error
+    // message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be greater than 5.0 [double.gt]
+    //   double value = 1 [(buf.validate.field).double.gt = 5.0];
+    //
+    //   // value must be greater than 5 and less than 10.0 [double.gt_lt]
+    //   double other_value = 2 [(buf.validate.field).double = { gt: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than 10 or less than 5.0 [double.gt_lt_exclusive]
+    //   double another_value = 3 [(buf.validate.field).double = { gt: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    double gt = 4 [
+      (predefined).cel = {
+        id: "double.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be greater than or equal to 5.0 [double.gte]
+    //   double value = 1 [(buf.validate.field).double.gte = 5.0];
+    //
+    //   // value must be greater than or equal to 5.0 and less than 10.0 [double.gte_lt]
+    //   double other_value = 2 [(buf.validate.field).double = { gte: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than or equal to 10.0 or less than 5.0 [double.gte_lt_exclusive]
+    //   double another_value = 3 [(buf.validate.field).double = { gte: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    double gte = 5 [
+      (predefined).cel = {
+        id: "double.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyDouble {
+  //   // value must be in list [1.0, 2.0, 3.0]
+  //   double value = 1 [(buf.validate.field).double = { in: [1.0, 2.0, 3.0] }];
+  // }
+  // ```
+  repeated double in = 6 [(predefined).cel = {
+    id: "double.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyDouble {
+  //   // value must not be in list [1.0, 2.0, 3.0]
+  //   double value = 1 [(buf.validate.field).double = { not_in: [1.0, 2.0, 3.0] }];
+  // }
+  // ```
+  repeated double not_in = 7 [(predefined).cel = {
+    id: "double.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `finite` requires the field value to be finite. If the field value is
+  // infinite or NaN, an error message is generated.
+  optional bool finite = 8 [(predefined).cel = {
+    id: "double.finite"
+    expression: "rules.finite ? (this.isNan() || this.isInf() ? 'value must be finite' : '') : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyDouble {
+  //   double value = 1 [
+  //     (buf.validate.field).double.example = 1.0,
+  //     (buf.validate.field).double.example = inf
+  //   ];
+  // }
+  // ```
+  repeated double example = 9 [(predefined).cel = {
+    id: "double.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Int32Rules describes the rules applied to `int32` values. These
+// rules may also be applied to the `google.protobuf.Int32Value` Well-Known-Type.
+message Int32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   // value must equal 42
+  //   int32 value = 1 [(buf.validate.field).int32.const = 42];
+  // }
+  // ```
+  optional int32 const = 1 [(predefined).cel = {
+    id: "int32.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field
+    // < value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be less than 10
+    //   int32 value = 1 [(buf.validate.field).int32.lt = 10];
+    // }
+    // ```
+    int32 lt = 2 [(predefined).cel = {
+      id: "int32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be less than or equal to 10
+    //   int32 value = 1 [(buf.validate.field).int32.lte = 10];
+    // }
+    // ```
+    int32 lte = 3 [(predefined).cel = {
+      id: "int32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be greater than 5 [int32.gt]
+    //   int32 value = 1 [(buf.validate.field).int32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [int32.gt_lt]
+    //   int32 other_value = 2 [(buf.validate.field).int32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [int32.gt_lt_exclusive]
+    //   int32 another_value = 3 [(buf.validate.field).int32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    int32 gt = 4 [
+      (predefined).cel = {
+        id: "int32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified value
+    // (exclusive). If the value of `gte` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be greater than or equal to 5 [int32.gte]
+    //   int32 value = 1 [(buf.validate.field).int32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [int32.gte_lt]
+    //   int32 other_value = 2 [(buf.validate.field).int32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [int32.gte_lt_exclusive]
+    //   int32 another_value = 3 [(buf.validate.field).int32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    int32 gte = 5 [
+      (predefined).cel = {
+        id: "int32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   // value must be in list [1, 2, 3]
+  //   int32 value = 1 [(buf.validate.field).int32 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated int32 in = 6 [(predefined).cel = {
+    id: "int32.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   // value must not be in list [1, 2, 3]
+  //   int32 value = 1 [(buf.validate.field).int32 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated int32 not_in = 7 [(predefined).cel = {
+    id: "int32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   int32 value = 1 [
+  //     (buf.validate.field).int32.example = 1,
+  //     (buf.validate.field).int32.example = -10
+  //   ];
+  // }
+  // ```
+  repeated int32 example = 8 [(predefined).cel = {
+    id: "int32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Int64Rules describes the rules applied to `int64` values. These
+// rules may also be applied to the `google.protobuf.Int64Value` Well-Known-Type.
+message Int64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   // value must equal 42
+  //   int64 value = 1 [(buf.validate.field).int64.const = 42];
+  // }
+  // ```
+  optional int64 const = 1 [(predefined).cel = {
+    id: "int64.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be less than 10
+    //   int64 value = 1 [(buf.validate.field).int64.lt = 10];
+    // }
+    // ```
+    int64 lt = 2 [(predefined).cel = {
+      id: "int64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be less than or equal to 10
+    //   int64 value = 1 [(buf.validate.field).int64.lte = 10];
+    // }
+    // ```
+    int64 lte = 3 [(predefined).cel = {
+      id: "int64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be greater than 5 [int64.gt]
+    //   int64 value = 1 [(buf.validate.field).int64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [int64.gt_lt]
+    //   int64 other_value = 2 [(buf.validate.field).int64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [int64.gt_lt_exclusive]
+    //   int64 another_value = 3 [(buf.validate.field).int64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    int64 gt = 4 [
+      (predefined).cel = {
+        id: "int64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be greater than or equal to 5 [int64.gte]
+    //   int64 value = 1 [(buf.validate.field).int64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [int64.gte_lt]
+    //   int64 other_value = 2 [(buf.validate.field).int64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [int64.gte_lt_exclusive]
+    //   int64 another_value = 3 [(buf.validate.field).int64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    int64 gte = 5 [
+      (predefined).cel = {
+        id: "int64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   // value must be in list [1, 2, 3]
+  //   int64 value = 1 [(buf.validate.field).int64 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated int64 in = 6 [(predefined).cel = {
+    id: "int64.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   // value must not be in list [1, 2, 3]
+  //   int64 value = 1 [(buf.validate.field).int64 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated int64 not_in = 7 [(predefined).cel = {
+    id: "int64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   int64 value = 1 [
+  //     (buf.validate.field).int64.example = 1,
+  //     (buf.validate.field).int64.example = -10
+  //   ];
+  // }
+  // ```
+  repeated int64 example = 9 [(predefined).cel = {
+    id: "int64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// UInt32Rules describes the rules applied to `uint32` values. These
+// rules may also be applied to the `google.protobuf.UInt32Value` Well-Known-Type.
+message UInt32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   // value must equal 42
+  //   uint32 value = 1 [(buf.validate.field).uint32.const = 42];
+  // }
+  // ```
+  optional uint32 const = 1 [(predefined).cel = {
+    id: "uint32.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be less than 10
+    //   uint32 value = 1 [(buf.validate.field).uint32.lt = 10];
+    // }
+    // ```
+    uint32 lt = 2 [(predefined).cel = {
+      id: "uint32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be less than or equal to 10
+    //   uint32 value = 1 [(buf.validate.field).uint32.lte = 10];
+    // }
+    // ```
+    uint32 lte = 3 [(predefined).cel = {
+      id: "uint32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be greater than 5 [uint32.gt]
+    //   uint32 value = 1 [(buf.validate.field).uint32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [uint32.gt_lt]
+    //   uint32 other_value = 2 [(buf.validate.field).uint32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [uint32.gt_lt_exclusive]
+    //   uint32 another_value = 3 [(buf.validate.field).uint32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    uint32 gt = 4 [
+      (predefined).cel = {
+        id: "uint32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be greater than or equal to 5 [uint32.gte]
+    //   uint32 value = 1 [(buf.validate.field).uint32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [uint32.gte_lt]
+    //   uint32 other_value = 2 [(buf.validate.field).uint32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [uint32.gte_lt_exclusive]
+    //   uint32 another_value = 3 [(buf.validate.field).uint32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    uint32 gte = 5 [
+      (predefined).cel = {
+        id: "uint32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   // value must be in list [1, 2, 3]
+  //   uint32 value = 1 [(buf.validate.field).uint32 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated uint32 in = 6 [(predefined).cel = {
+    id: "uint32.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   // value must not be in list [1, 2, 3]
+  //   uint32 value = 1 [(buf.validate.field).uint32 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated uint32 not_in = 7 [(predefined).cel = {
+    id: "uint32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   uint32 value = 1 [
+  //     (buf.validate.field).uint32.example = 1,
+  //     (buf.validate.field).uint32.example = 10
+  //   ];
+  // }
+  // ```
+  repeated uint32 example = 8 [(predefined).cel = {
+    id: "uint32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// UInt64Rules describes the rules applied to `uint64` values. These
+// rules may also be applied to the `google.protobuf.UInt64Value` Well-Known-Type.
+message UInt64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   // value must equal 42
+  //   uint64 value = 1 [(buf.validate.field).uint64.const = 42];
+  // }
+  // ```
+  optional uint64 const = 1 [(predefined).cel = {
+    id: "uint64.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be less than 10
+    //   uint64 value = 1 [(buf.validate.field).uint64.lt = 10];
+    // }
+    // ```
+    uint64 lt = 2 [(predefined).cel = {
+      id: "uint64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be less than or equal to 10
+    //   uint64 value = 1 [(buf.validate.field).uint64.lte = 10];
+    // }
+    // ```
+    uint64 lte = 3 [(predefined).cel = {
+      id: "uint64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be greater than 5 [uint64.gt]
+    //   uint64 value = 1 [(buf.validate.field).uint64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [uint64.gt_lt]
+    //   uint64 other_value = 2 [(buf.validate.field).uint64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [uint64.gt_lt_exclusive]
+    //   uint64 another_value = 3 [(buf.validate.field).uint64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    uint64 gt = 4 [
+      (predefined).cel = {
+        id: "uint64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be greater than or equal to 5 [uint64.gte]
+    //   uint64 value = 1 [(buf.validate.field).uint64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [uint64.gte_lt]
+    //   uint64 other_value = 2 [(buf.validate.field).uint64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [uint64.gte_lt_exclusive]
+    //   uint64 another_value = 3 [(buf.validate.field).uint64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    uint64 gte = 5 [
+      (predefined).cel = {
+        id: "uint64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   // value must be in list [1, 2, 3]
+  //   uint64 value = 1 [(buf.validate.field).uint64 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated uint64 in = 6 [(predefined).cel = {
+    id: "uint64.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   // value must not be in list [1, 2, 3]
+  //   uint64 value = 1 [(buf.validate.field).uint64 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated uint64 not_in = 7 [(predefined).cel = {
+    id: "uint64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   uint64 value = 1 [
+  //     (buf.validate.field).uint64.example = 1,
+  //     (buf.validate.field).uint64.example = -10
+  //   ];
+  // }
+  // ```
+  repeated uint64 example = 8 [(predefined).cel = {
+    id: "uint64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SInt32Rules describes the rules applied to `sint32` values.
+message SInt32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   // value must equal 42
+  //   sint32 value = 1 [(buf.validate.field).sint32.const = 42];
+  // }
+  // ```
+  optional sint32 const = 1 [(predefined).cel = {
+    id: "sint32.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field
+    // < value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //   // value must be less than 10
+    //   sint32 value = 1 [(buf.validate.field).sint32.lt = 10];
+    // }
+    // ```
+    sint32 lt = 2 [(predefined).cel = {
+      id: "sint32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //   // value must be less than or equal to 10
+    //   sint32 value = 1 [(buf.validate.field).sint32.lte = 10];
+    // }
+    // ```
+    sint32 lte = 3 [(predefined).cel = {
+      id: "sint32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //   // value must be greater than 5 [sint32.gt]
+    //   sint32 value = 1 [(buf.validate.field).sint32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sint32.gt_lt]
+    //   sint32 other_value = 2 [(buf.validate.field).sint32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sint32.gt_lt_exclusive]
+    //   sint32 another_value = 3 [(buf.validate.field).sint32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sint32 gt = 4 [
+      (predefined).cel = {
+        id: "sint32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //  // value must be greater than or equal to 5 [sint32.gte]
+    //  sint32 value = 1 [(buf.validate.field).sint32.gte = 5];
+    //
+    //  // value must be greater than or equal to 5 and less than 10 [sint32.gte_lt]
+    //  sint32 other_value = 2 [(buf.validate.field).sint32 = { gte: 5, lt: 10 }];
+    //
+    //  // value must be greater than or equal to 10 or less than 5 [sint32.gte_lt_exclusive]
+    //  sint32 another_value = 3 [(buf.validate.field).sint32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sint32 gte = 5 [
+      (predefined).cel = {
+        id: "sint32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   // value must be in list [1, 2, 3]
+  //   sint32 value = 1 [(buf.validate.field).sint32 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sint32 in = 6 [(predefined).cel = {
+    id: "sint32.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   // value must not be in list [1, 2, 3]
+  //   sint32 value = 1 [(buf.validate.field).sint32 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sint32 not_in = 7 [(predefined).cel = {
+    id: "sint32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   sint32 value = 1 [
+  //     (buf.validate.field).sint32.example = 1,
+  //     (buf.validate.field).sint32.example = -10
+  //   ];
+  // }
+  // ```
+  repeated sint32 example = 8 [(predefined).cel = {
+    id: "sint32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SInt64Rules describes the rules applied to `sint64` values.
+message SInt64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   // value must equal 42
+  //   sint64 value = 1 [(buf.validate.field).sint64.const = 42];
+  // }
+  // ```
+  optional sint64 const = 1 [(predefined).cel = {
+    id: "sint64.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field
+    // < value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be less than 10
+    //   sint64 value = 1 [(buf.validate.field).sint64.lt = 10];
+    // }
+    // ```
+    sint64 lt = 2 [(predefined).cel = {
+      id: "sint64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be less than or equal to 10
+    //   sint64 value = 1 [(buf.validate.field).sint64.lte = 10];
+    // }
+    // ```
+    sint64 lte = 3 [(predefined).cel = {
+      id: "sint64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be greater than 5 [sint64.gt]
+    //   sint64 value = 1 [(buf.validate.field).sint64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sint64.gt_lt]
+    //   sint64 other_value = 2 [(buf.validate.field).sint64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sint64.gt_lt_exclusive]
+    //   sint64 another_value = 3 [(buf.validate.field).sint64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sint64 gt = 4 [
+      (predefined).cel = {
+        id: "sint64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be greater than or equal to 5 [sint64.gte]
+    //   sint64 value = 1 [(buf.validate.field).sint64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [sint64.gte_lt]
+    //   sint64 other_value = 2 [(buf.validate.field).sint64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [sint64.gte_lt_exclusive]
+    //   sint64 another_value = 3 [(buf.validate.field).sint64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sint64 gte = 5 [
+      (predefined).cel = {
+        id: "sint64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   // value must be in list [1, 2, 3]
+  //   sint64 value = 1 [(buf.validate.field).sint64 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sint64 in = 6 [(predefined).cel = {
+    id: "sint64.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   // value must not be in list [1, 2, 3]
+  //   sint64 value = 1 [(buf.validate.field).sint64 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sint64 not_in = 7 [(predefined).cel = {
+    id: "sint64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   sint64 value = 1 [
+  //     (buf.validate.field).sint64.example = 1,
+  //     (buf.validate.field).sint64.example = -10
+  //   ];
+  // }
+  // ```
+  repeated sint64 example = 8 [(predefined).cel = {
+    id: "sint64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Fixed32Rules describes the rules applied to `fixed32` values.
+message Fixed32Rules {
+  // `const` requires the field value to exactly match the specified value.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   // value must equal 42
+  //   fixed32 value = 1 [(buf.validate.field).fixed32.const = 42];
+  // }
+  // ```
+  optional fixed32 const = 1 [(predefined).cel = {
+    id: "fixed32.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be less than 10
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.lt = 10];
+    // }
+    // ```
+    fixed32 lt = 2 [(predefined).cel = {
+      id: "fixed32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be less than or equal to 10
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.lte = 10];
+    // }
+    // ```
+    fixed32 lte = 3 [(predefined).cel = {
+      id: "fixed32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be greater than 5 [fixed32.gt]
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [fixed32.gt_lt]
+    //   fixed32 other_value = 2 [(buf.validate.field).fixed32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [fixed32.gt_lt_exclusive]
+    //   fixed32 another_value = 3 [(buf.validate.field).fixed32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    fixed32 gt = 4 [
+      (predefined).cel = {
+        id: "fixed32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be greater than or equal to 5 [fixed32.gte]
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [fixed32.gte_lt]
+    //   fixed32 other_value = 2 [(buf.validate.field).fixed32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [fixed32.gte_lt_exclusive]
+    //   fixed32 another_value = 3 [(buf.validate.field).fixed32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    fixed32 gte = 5 [
+      (predefined).cel = {
+        id: "fixed32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   // value must be in list [1, 2, 3]
+  //   fixed32 value = 1 [(buf.validate.field).fixed32 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated fixed32 in = 6 [(predefined).cel = {
+    id: "fixed32.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   // value must not be in list [1, 2, 3]
+  //   fixed32 value = 1 [(buf.validate.field).fixed32 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated fixed32 not_in = 7 [(predefined).cel = {
+    id: "fixed32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   fixed32 value = 1 [
+  //     (buf.validate.field).fixed32.example = 1,
+  //     (buf.validate.field).fixed32.example = 2
+  //   ];
+  // }
+  // ```
+  repeated fixed32 example = 8 [(predefined).cel = {
+    id: "fixed32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Fixed64Rules describes the rules applied to `fixed64` values.
+message Fixed64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   // value must equal 42
+  //   fixed64 value = 1 [(buf.validate.field).fixed64.const = 42];
+  // }
+  // ```
+  optional fixed64 const = 1 [(predefined).cel = {
+    id: "fixed64.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be less than 10
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.lt = 10];
+    // }
+    // ```
+    fixed64 lt = 2 [(predefined).cel = {
+      id: "fixed64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be less than or equal to 10
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.lte = 10];
+    // }
+    // ```
+    fixed64 lte = 3 [(predefined).cel = {
+      id: "fixed64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be greater than 5 [fixed64.gt]
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [fixed64.gt_lt]
+    //   fixed64 other_value = 2 [(buf.validate.field).fixed64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [fixed64.gt_lt_exclusive]
+    //   fixed64 another_value = 3 [(buf.validate.field).fixed64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    fixed64 gt = 4 [
+      (predefined).cel = {
+        id: "fixed64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be greater than or equal to 5 [fixed64.gte]
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [fixed64.gte_lt]
+    //   fixed64 other_value = 2 [(buf.validate.field).fixed64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [fixed64.gte_lt_exclusive]
+    //   fixed64 another_value = 3 [(buf.validate.field).fixed64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    fixed64 gte = 5 [
+      (predefined).cel = {
+        id: "fixed64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   // value must be in list [1, 2, 3]
+  //   fixed64 value = 1 [(buf.validate.field).fixed64 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated fixed64 in = 6 [(predefined).cel = {
+    id: "fixed64.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   // value must not be in list [1, 2, 3]
+  //   fixed64 value = 1 [(buf.validate.field).fixed64 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated fixed64 not_in = 7 [(predefined).cel = {
+    id: "fixed64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   fixed64 value = 1 [
+  //     (buf.validate.field).fixed64.example = 1,
+  //     (buf.validate.field).fixed64.example = 2
+  //   ];
+  // }
+  // ```
+  repeated fixed64 example = 8 [(predefined).cel = {
+    id: "fixed64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SFixed32Rules describes the rules applied to `fixed32` values.
+message SFixed32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   // value must equal 42
+  //   sfixed32 value = 1 [(buf.validate.field).sfixed32.const = 42];
+  // }
+  // ```
+  optional sfixed32 const = 1 [(predefined).cel = {
+    id: "sfixed32.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be less than 10
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.lt = 10];
+    // }
+    // ```
+    sfixed32 lt = 2 [(predefined).cel = {
+      id: "sfixed32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be less than or equal to 10
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.lte = 10];
+    // }
+    // ```
+    sfixed32 lte = 3 [(predefined).cel = {
+      id: "sfixed32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be greater than 5 [sfixed32.gt]
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sfixed32.gt_lt]
+    //   sfixed32 other_value = 2 [(buf.validate.field).sfixed32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sfixed32.gt_lt_exclusive]
+    //   sfixed32 another_value = 3 [(buf.validate.field).sfixed32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed32 gt = 4 [
+      (predefined).cel = {
+        id: "sfixed32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be greater than or equal to 5 [sfixed32.gte]
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [sfixed32.gte_lt]
+    //   sfixed32 other_value = 2 [(buf.validate.field).sfixed32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [sfixed32.gte_lt_exclusive]
+    //   sfixed32 another_value = 3 [(buf.validate.field).sfixed32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed32 gte = 5 [
+      (predefined).cel = {
+        id: "sfixed32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   // value must be in list [1, 2, 3]
+  //   sfixed32 value = 1 [(buf.validate.field).sfixed32 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sfixed32 in = 6 [(predefined).cel = {
+    id: "sfixed32.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   // value must not be in list [1, 2, 3]
+  //   sfixed32 value = 1 [(buf.validate.field).sfixed32 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sfixed32 not_in = 7 [(predefined).cel = {
+    id: "sfixed32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   sfixed32 value = 1 [
+  //     (buf.validate.field).sfixed32.example = 1,
+  //     (buf.validate.field).sfixed32.example = 2
+  //   ];
+  // }
+  // ```
+  repeated sfixed32 example = 8 [(predefined).cel = {
+    id: "sfixed32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SFixed64Rules describes the rules applied to `fixed64` values.
+message SFixed64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   // value must equal 42
+  //   sfixed64 value = 1 [(buf.validate.field).sfixed64.const = 42];
+  // }
+  // ```
+  optional sfixed64 const = 1 [(predefined).cel = {
+    id: "sfixed64.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be less than 10
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.lt = 10];
+    // }
+    // ```
+    sfixed64 lt = 2 [(predefined).cel = {
+      id: "sfixed64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be less than or equal to 10
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.lte = 10];
+    // }
+    // ```
+    sfixed64 lte = 3 [(predefined).cel = {
+      id: "sfixed64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be greater than 5 [sfixed64.gt]
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sfixed64.gt_lt]
+    //   sfixed64 other_value = 2 [(buf.validate.field).sfixed64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sfixed64.gt_lt_exclusive]
+    //   sfixed64 another_value = 3 [(buf.validate.field).sfixed64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed64 gt = 4 [
+      (predefined).cel = {
+        id: "sfixed64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be greater than or equal to 5 [sfixed64.gte]
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [sfixed64.gte_lt]
+    //   sfixed64 other_value = 2 [(buf.validate.field).sfixed64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [sfixed64.gte_lt_exclusive]
+    //   sfixed64 another_value = 3 [(buf.validate.field).sfixed64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed64 gte = 5 [
+      (predefined).cel = {
+        id: "sfixed64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   // value must be in list [1, 2, 3]
+  //   sfixed64 value = 1 [(buf.validate.field).sfixed64 = { in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sfixed64 in = 6 [(predefined).cel = {
+    id: "sfixed64.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   // value must not be in list [1, 2, 3]
+  //   sfixed64 value = 1 [(buf.validate.field).sfixed64 = { not_in: [1, 2, 3] }];
+  // }
+  // ```
+  repeated sfixed64 not_in = 7 [(predefined).cel = {
+    id: "sfixed64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   sfixed64 value = 1 [
+  //     (buf.validate.field).sfixed64.example = 1,
+  //     (buf.validate.field).sfixed64.example = 2
+  //   ];
+  // }
+  // ```
+  repeated sfixed64 example = 8 [(predefined).cel = {
+    id: "sfixed64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// BoolRules describes the rules applied to `bool` values. These rules
+// may also be applied to the `google.protobuf.BoolValue` Well-Known-Type.
+message BoolRules {
+  // `const` requires the field value to exactly match the specified boolean value.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyBool {
+  //   // value must equal true
+  //   bool value = 1 [(buf.validate.field).bool.const = true];
+  // }
+  // ```
+  optional bool const = 1 [(predefined).cel = {
+    id: "bool.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyBool {
+  //   bool value = 1 [
+  //     (buf.validate.field).bool.example = 1,
+  //     (buf.validate.field).bool.example = 2
+  //   ];
+  // }
+  // ```
+  repeated bool example = 2 [(predefined).cel = {
+    id: "bool.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// StringRules describes the rules applied to `string` values These
+// rules may also be applied to the `google.protobuf.StringValue` Well-Known-Type.
+message StringRules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value must equal `hello`
+  //   string value = 1 [(buf.validate.field).string.const = "hello"];
+  // }
+  // ```
+  optional string const = 1 [(predefined).cel = {
+    id: "string.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal `%s`'.format([getField(rules, 'const')]) : ''"
+  }];
+
+  // `len` dictates that the field value must have the specified
+  // number of characters (Unicode code points), which may differ from the number
+  // of bytes in the string. If the field value does not meet the specified
+  // length, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be 5 characters
+  //   string value = 1 [(buf.validate.field).string.len = 5];
+  // }
+  // ```
+  optional uint64 len = 19 [(predefined).cel = {
+    id: "string.len"
+    expression: "uint(this.size()) != rules.len ? 'value length must be %s characters'.format([rules.len]) : ''"
+  }];
+
+  // `min_len` specifies that the field value must have at least the specified
+  // number of characters (Unicode code points), which may differ from the number
+  // of bytes in the string. If the field value contains fewer characters, an error
+  // message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at least 3 characters
+  //   string value = 1 [(buf.validate.field).string.min_len = 3];
+  // }
+  // ```
+  optional uint64 min_len = 2 [(predefined).cel = {
+    id: "string.min_len"
+    expression: "uint(this.size()) < rules.min_len ? 'value length must be at least %s characters'.format([rules.min_len]) : ''"
+  }];
+
+  // `max_len` specifies that the field value must have no more than the specified
+  // number of characters (Unicode code points), which may differ from the
+  // number of bytes in the string. If the field value contains more characters,
+  // an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at most 10 characters
+  //   string value = 1 [(buf.validate.field).string.max_len = 10];
+  // }
+  // ```
+  optional uint64 max_len = 3 [(predefined).cel = {
+    id: "string.max_len"
+    expression: "uint(this.size()) > rules.max_len ? 'value length must be at most %s characters'.format([rules.max_len]) : ''"
+  }];
+
+  // `len_bytes` dictates that the field value must have the specified number of
+  // bytes. If the field value does not match the specified length in bytes,
+  // an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be 6 bytes
+  //   string value = 1 [(buf.validate.field).string.len_bytes = 6];
+  // }
+  // ```
+  optional uint64 len_bytes = 20 [(predefined).cel = {
+    id: "string.len_bytes"
+    expression: "uint(bytes(this).size()) != rules.len_bytes ? 'value length must be %s bytes'.format([rules.len_bytes]) : ''"
+  }];
+
+  // `min_bytes` specifies that the field value must have at least the specified
+  // number of bytes. If the field value contains fewer bytes, an error message
+  // will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at least 4 bytes
+  //   string value = 1 [(buf.validate.field).string.min_bytes = 4];
+  // }
+  //
+  // ```
+  optional uint64 min_bytes = 4 [(predefined).cel = {
+    id: "string.min_bytes"
+    expression: "uint(bytes(this).size()) < rules.min_bytes ? 'value length must be at least %s bytes'.format([rules.min_bytes]) : ''"
+  }];
+
+  // `max_bytes` specifies that the field value must have no more than the
+  //specified number of bytes. If the field value contains more bytes, an
+  // error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at most 8 bytes
+  //   string value = 1 [(buf.validate.field).string.max_bytes = 8];
+  // }
+  // ```
+  optional uint64 max_bytes = 5 [(predefined).cel = {
+    id: "string.max_bytes"
+    expression: "uint(bytes(this).size()) > rules.max_bytes ? 'value length must be at most %s bytes'.format([rules.max_bytes]) : ''"
+  }];
+
+  // `pattern` specifies that the field value must match the specified
+  // regular expression (RE2 syntax), with the expression provided without any
+  // delimiters. If the field value doesn't match the regular expression, an
+  // error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not match regex pattern `^[a-zA-Z]//$`
+  //   string value = 1 [(buf.validate.field).string.pattern = "^[a-zA-Z]//$"];
+  // }
+  // ```
+  optional string pattern = 6 [(predefined).cel = {
+    id: "string.pattern"
+    expression: "!this.matches(rules.pattern) ? 'value does not match regex pattern `%s`'.format([rules.pattern]) : ''"
+  }];
+
+  // `prefix` specifies that the field value must have the
+  //specified substring at the beginning of the string. If the field value
+  // doesn't start with the specified prefix, an error message will be
+  // generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not have prefix `pre`
+  //   string value = 1 [(buf.validate.field).string.prefix = "pre"];
+  // }
+  // ```
+  optional string prefix = 7 [(predefined).cel = {
+    id: "string.prefix"
+    expression: "!this.startsWith(rules.prefix) ? 'value does not have prefix `%s`'.format([rules.prefix]) : ''"
+  }];
+
+  // `suffix` specifies that the field value must have the
+  //specified substring at the end of the string. If the field value doesn't
+  // end with the specified suffix, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not have suffix `post`
+  //   string value = 1 [(buf.validate.field).string.suffix = "post"];
+  // }
+  // ```
+  optional string suffix = 8 [(predefined).cel = {
+    id: "string.suffix"
+    expression: "!this.endsWith(rules.suffix) ? 'value does not have suffix `%s`'.format([rules.suffix]) : ''"
+  }];
+
+  // `contains` specifies that the field value must have the
+  //specified substring anywhere in the string. If the field value doesn't
+  // contain the specified substring, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not contain substring `inside`.
+  //   string value = 1 [(buf.validate.field).string.contains = "inside"];
+  // }
+  // ```
+  optional string contains = 9 [(predefined).cel = {
+    id: "string.contains"
+    expression: "!this.contains(rules.contains) ? 'value does not contain substring `%s`'.format([rules.contains]) : ''"
+  }];
+
+  // `not_contains` specifies that the field value must not have the
+  //specified substring anywhere in the string. If the field value contains
+  // the specified substring, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value contains substring `inside`.
+  //   string value = 1 [(buf.validate.field).string.not_contains = "inside"];
+  // }
+  // ```
+  optional string not_contains = 23 [(predefined).cel = {
+    id: "string.not_contains"
+    expression: "this.contains(rules.not_contains) ? 'value contains substring `%s`'.format([rules.not_contains]) : ''"
+  }];
+
+  // `in` specifies that the field value must be equal to one of the specified
+  // values. If the field value isn't one of the specified values, an error
+  // message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value must be in list ["apple", "banana"]
+  //   string value = 1 [(buf.validate.field).string.in = "apple", (buf.validate.field).string.in = "banana"];
+  // }
+  // ```
+  repeated string in = 10 [(predefined).cel = {
+    id: "string.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` specifies that the field value cannot be equal to any
+  // of the specified values. If the field value is one of the specified values,
+  // an error message will be generated.
+  // ```proto
+  // message MyString {
+  //   // value must not be in list ["orange", "grape"]
+  //   string value = 1 [(buf.validate.field).string.not_in = "orange", (buf.validate.field).string.not_in = "grape"];
+  // }
+  // ```
+  repeated string not_in = 11 [(predefined).cel = {
+    id: "string.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `WellKnown` rules provide advanced rules against common string
+  // patterns.
+  oneof well_known {
+    // `email` specifies that the field value must be a valid email address, for
+    // example "foo@example.com".
+    //
+    // Conforms to the definition for a valid email address from the [HTML standard](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address).
+    // Note that this standard willfully deviates from [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322),
+    // which allows many unexpected forms of email addresses and will easily match
+    // a typographical error.
+    //
+    // If the field value isn't a valid email address, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid email address
+    //   string value = 1 [(buf.validate.field).string.email = true];
+    // }
+    // ```
+    bool email = 12 [
+      (predefined).cel = {
+        id: "string.email"
+        message: "value must be a valid email address"
+        expression: "!rules.email || this == '' || this.isEmail()"
+      },
+      (predefined).cel = {
+        id: "string.email_empty"
+        message: "value is empty, which is not a valid email address"
+        expression: "!rules.email || this != ''"
+      }
+    ];
+
+    // `hostname` specifies that the field value must be a valid hostname, for
+    // example "foo.example.com".
+    //
+    // A valid hostname follows the rules below:
+    // - The name consists of one or more labels, separated by a dot (".").
+    // - Each label can be 1 to 63 alphanumeric characters.
+    // - A label can contain hyphens ("-"), but must not start or end with a hyphen.
+    // - The right-most label must not be digits only.
+    // - The name can have a trailing dot—for example, "foo.example.com.".
+    // - The name can be 253 characters at most, excluding the optional trailing dot.
+    //
+    // If the field value isn't a valid hostname, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid hostname
+    //   string value = 1 [(buf.validate.field).string.hostname = true];
+    // }
+    // ```
+    bool hostname = 13 [
+      (predefined).cel = {
+        id: "string.hostname"
+        message: "value must be a valid hostname"
+        expression: "!rules.hostname || this == '' || this.isHostname()"
+      },
+      (predefined).cel = {
+        id: "string.hostname_empty"
+        message: "value is empty, which is not a valid hostname"
+        expression: "!rules.hostname || this != ''"
+      }
+    ];
+
+    // `ip` specifies that the field value must be a valid IP (v4 or v6) address.
+    //
+    // IPv4 addresses are expected in the dotted decimal format—for example, "192.168.5.21".
+    // IPv6 addresses are expected in their text representation—for example, "::1",
+    // or "2001:0DB8:ABCD:0012::0".
+    //
+    // Both formats are well-defined in the internet standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986).
+    // Zone identifiers for IPv6 addresses (for example, "fe80::a%en1") are supported.
+    //
+    // If the field value isn't a valid IP address, an error message will be
+    // generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IP address
+    //   string value = 1 [(buf.validate.field).string.ip = true];
+    // }
+    // ```
+    bool ip = 14 [
+      (predefined).cel = {
+        id: "string.ip"
+        message: "value must be a valid IP address"
+        expression: "!rules.ip || this == '' || this.isIp()"
+      },
+      (predefined).cel = {
+        id: "string.ip_empty"
+        message: "value is empty, which is not a valid IP address"
+        expression: "!rules.ip || this != ''"
+      }
+    ];
+
+    // `ipv4` specifies that the field value must be a valid IPv4 address—for
+    // example "192.168.5.21". If the field value isn't a valid IPv4 address, an
+    // error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv4 address
+    //   string value = 1 [(buf.validate.field).string.ipv4 = true];
+    // }
+    // ```
+    bool ipv4 = 15 [
+      (predefined).cel = {
+        id: "string.ipv4"
+        message: "value must be a valid IPv4 address"
+        expression: "!rules.ipv4 || this == '' || this.isIp(4)"
+      },
+      (predefined).cel = {
+        id: "string.ipv4_empty"
+        message: "value is empty, which is not a valid IPv4 address"
+        expression: "!rules.ipv4 || this != ''"
+      }
+    ];
+
+    // `ipv6` specifies that the field value must be a valid IPv6 address—for
+    // example "::1", or "d7a:115c:a1e0:ab12:4843:cd96:626b:430b". If the field
+    // value is not a valid IPv6 address, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv6 address
+    //   string value = 1 [(buf.validate.field).string.ipv6 = true];
+    // }
+    // ```
+    bool ipv6 = 16 [
+      (predefined).cel = {
+        id: "string.ipv6"
+        message: "value must be a valid IPv6 address"
+        expression: "!rules.ipv6 || this == '' || this.isIp(6)"
+      },
+      (predefined).cel = {
+        id: "string.ipv6_empty"
+        message: "value is empty, which is not a valid IPv6 address"
+        expression: "!rules.ipv6 || this != ''"
+      }
+    ];
+
+    // `uri` specifies that the field value must be a valid URI, for example
+    // "https://example.com/foo/bar?baz=quux#frag".
+    //
+    // URI is defined in the internet standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986).
+    // Zone Identifiers in IPv6 address literals are supported ([RFC 6874](https://datatracker.ietf.org/doc/html/rfc6874)).
+    //
+    // If the field value isn't a valid URI, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid URI
+    //   string value = 1 [(buf.validate.field).string.uri = true];
+    // }
+    // ```
+    bool uri = 17 [
+      (predefined).cel = {
+        id: "string.uri"
+        message: "value must be a valid URI"
+        expression: "!rules.uri || this == '' || this.isUri()"
+      },
+      (predefined).cel = {
+        id: "string.uri_empty"
+        message: "value is empty, which is not a valid URI"
+        expression: "!rules.uri || this != ''"
+      }
+    ];
+
+    // `uri_ref` specifies that the field value must be a valid URI Reference—either
+    // a URI such as "https://example.com/foo/bar?baz=quux#frag", or a Relative
+    // Reference such as "./foo/bar?query".
+    //
+    // URI, URI Reference, and Relative Reference are defined in the internet
+    // standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). Zone
+    // Identifiers in IPv6 address literals are supported ([RFC 6874](https://datatracker.ietf.org/doc/html/rfc6874)).
+    //
+    // If the field value isn't a valid URI Reference, an error message will be
+    // generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid URI Reference
+    //   string value = 1 [(buf.validate.field).string.uri_ref = true];
+    // }
+    // ```
+    bool uri_ref = 18 [(predefined).cel = {
+      id: "string.uri_ref"
+      message: "value must be a valid URI Reference"
+      expression: "!rules.uri_ref || this.isUriRef()"
+    }];
+
+    // `address` specifies that the field value must be either a valid hostname
+    // (for example, "example.com"), or a valid IP (v4 or v6) address (for example,
+    // "192.168.0.1", or "::1"). If the field value isn't a valid hostname or IP,
+    // an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid hostname, or ip address
+    //   string value = 1 [(buf.validate.field).string.address = true];
+    // }
+    // ```
+    bool address = 21 [
+      (predefined).cel = {
+        id: "string.address"
+        message: "value must be a valid hostname, or ip address"
+        expression: "!rules.address || this == '' || this.isHostname() || this.isIp()"
+      },
+      (predefined).cel = {
+        id: "string.address_empty"
+        message: "value is empty, which is not a valid hostname, or ip address"
+        expression: "!rules.address || this != ''"
+      }
+    ];
+
+    // `uuid` specifies that the field value must be a valid UUID as defined by
+    // [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2). If the
+    // field value isn't a valid UUID, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid UUID
+    //   string value = 1 [(buf.validate.field).string.uuid = true];
+    // }
+    // ```
+    bool uuid = 22 [
+      (predefined).cel = {
+        id: "string.uuid"
+        message: "value must be a valid UUID"
+        expression: "!rules.uuid || this == '' || this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')"
+      },
+      (predefined).cel = {
+        id: "string.uuid_empty"
+        message: "value is empty, which is not a valid UUID"
+        expression: "!rules.uuid || this != ''"
+      }
+    ];
+
+    // `tuuid` (trimmed UUID) specifies that the field value must be a valid UUID as
+    // defined by [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2) with all dashes
+    // omitted. If the field value isn't a valid UUID without dashes, an error message
+    // will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid trimmed UUID
+    //   string value = 1 [(buf.validate.field).string.tuuid = true];
+    // }
+    // ```
+    bool tuuid = 33 [
+      (predefined).cel = {
+        id: "string.tuuid"
+        message: "value must be a valid trimmed UUID"
+        expression: "!rules.tuuid || this == '' || this.matches('^[0-9a-fA-F]{32}$')"
+      },
+      (predefined).cel = {
+        id: "string.tuuid_empty"
+        message: "value is empty, which is not a valid trimmed UUID"
+        expression: "!rules.tuuid || this != ''"
+      }
+    ];
+
+    // `ip_with_prefixlen` specifies that the field value must be a valid IP
+    // (v4 or v6) address with prefix length—for example, "192.168.5.21/16" or
+    // "2001:0DB8:ABCD:0012::F1/64". If the field value isn't a valid IP with
+    // prefix length, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IP with prefix length
+    //    string value = 1 [(buf.validate.field).string.ip_with_prefixlen = true];
+    // }
+    // ```
+    bool ip_with_prefixlen = 26 [
+      (predefined).cel = {
+        id: "string.ip_with_prefixlen"
+        message: "value must be a valid IP prefix"
+        expression: "!rules.ip_with_prefixlen || this == '' || this.isIpPrefix()"
+      },
+      (predefined).cel = {
+        id: "string.ip_with_prefixlen_empty"
+        message: "value is empty, which is not a valid IP prefix"
+        expression: "!rules.ip_with_prefixlen || this != ''"
+      }
+    ];
+
+    // `ipv4_with_prefixlen` specifies that the field value must be a valid
+    // IPv4 address with prefix length—for example, "192.168.5.21/16". If the
+    // field value isn't a valid IPv4 address with prefix length, an error
+    // message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv4 address with prefix length
+    //    string value = 1 [(buf.validate.field).string.ipv4_with_prefixlen = true];
+    // }
+    // ```
+    bool ipv4_with_prefixlen = 27 [
+      (predefined).cel = {
+        id: "string.ipv4_with_prefixlen"
+        message: "value must be a valid IPv4 address with prefix length"
+        expression: "!rules.ipv4_with_prefixlen || this == '' || this.isIpPrefix(4)"
+      },
+      (predefined).cel = {
+        id: "string.ipv4_with_prefixlen_empty"
+        message: "value is empty, which is not a valid IPv4 address with prefix length"
+        expression: "!rules.ipv4_with_prefixlen || this != ''"
+      }
+    ];
+
+    // `ipv6_with_prefixlen` specifies that the field value must be a valid
+    // IPv6 address with prefix length—for example, "2001:0DB8:ABCD:0012::F1/64".
+    // If the field value is not a valid IPv6 address with prefix length,
+    // an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv6 address prefix length
+    //    string value = 1 [(buf.validate.field).string.ipv6_with_prefixlen = true];
+    // }
+    // ```
+    bool ipv6_with_prefixlen = 28 [
+      (predefined).cel = {
+        id: "string.ipv6_with_prefixlen"
+        message: "value must be a valid IPv6 address with prefix length"
+        expression: "!rules.ipv6_with_prefixlen || this == '' || this.isIpPrefix(6)"
+      },
+      (predefined).cel = {
+        id: "string.ipv6_with_prefixlen_empty"
+        message: "value is empty, which is not a valid IPv6 address with prefix length"
+        expression: "!rules.ipv6_with_prefixlen || this != ''"
+      }
+    ];
+
+    // `ip_prefix` specifies that the field value must be a valid IP (v4 or v6)
+    // prefix—for example, "192.168.0.0/16" or "2001:0DB8:ABCD:0012::0/64".
+    //
+    // The prefix must have all zeros for the unmasked bits. For example,
+    // "2001:0DB8:ABCD:0012::0/64" designates the left-most 64 bits for the
+    // prefix, and the remaining 64 bits must be zero.
+    //
+    // If the field value isn't a valid IP prefix, an error message will be
+    // generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IP prefix
+    //    string value = 1 [(buf.validate.field).string.ip_prefix = true];
+    // }
+    // ```
+    bool ip_prefix = 29 [
+      (predefined).cel = {
+        id: "string.ip_prefix"
+        message: "value must be a valid IP prefix"
+        expression: "!rules.ip_prefix || this == '' || this.isIpPrefix(true)"
+      },
+      (predefined).cel = {
+        id: "string.ip_prefix_empty"
+        message: "value is empty, which is not a valid IP prefix"
+        expression: "!rules.ip_prefix || this != ''"
+      }
+    ];
+
+    // `ipv4_prefix` specifies that the field value must be a valid IPv4
+    // prefix, for example "192.168.0.0/16".
+    //
+    // The prefix must have all zeros for the unmasked bits. For example,
+    // "192.168.0.0/16" designates the left-most 16 bits for the prefix,
+    // and the remaining 16 bits must be zero.
+    //
+    // If the field value isn't a valid IPv4 prefix, an error message
+    // will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv4 prefix
+    //    string value = 1 [(buf.validate.field).string.ipv4_prefix = true];
+    // }
+    // ```
+    bool ipv4_prefix = 30 [
+      (predefined).cel = {
+        id: "string.ipv4_prefix"
+        message: "value must be a valid IPv4 prefix"
+        expression: "!rules.ipv4_prefix || this == '' || this.isIpPrefix(4, true)"
+      },
+      (predefined).cel = {
+        id: "string.ipv4_prefix_empty"
+        message: "value is empty, which is not a valid IPv4 prefix"
+        expression: "!rules.ipv4_prefix || this != ''"
+      }
+    ];
+
+    // `ipv6_prefix` specifies that the field value must be a valid IPv6 prefix—for
+    // example, "2001:0DB8:ABCD:0012::0/64".
+    //
+    // The prefix must have all zeros for the unmasked bits. For example,
+    // "2001:0DB8:ABCD:0012::0/64" designates the left-most 64 bits for the
+    // prefix, and the remaining 64 bits must be zero.
+    //
+    // If the field value is not a valid IPv6 prefix, an error message will be
+    // generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv6 prefix
+    //    string value = 1 [(buf.validate.field).string.ipv6_prefix = true];
+    // }
+    // ```
+    bool ipv6_prefix = 31 [
+      (predefined).cel = {
+        id: "string.ipv6_prefix"
+        message: "value must be a valid IPv6 prefix"
+        expression: "!rules.ipv6_prefix || this == '' || this.isIpPrefix(6, true)"
+      },
+      (predefined).cel = {
+        id: "string.ipv6_prefix_empty"
+        message: "value is empty, which is not a valid IPv6 prefix"
+        expression: "!rules.ipv6_prefix || this != ''"
+      }
+    ];
+
+    // `host_and_port` specifies that the field value must be valid host/port
+    // pair—for example, "example.com:8080".
+    //
+    // The host can be one of:
+    //- An IPv4 address in dotted decimal format—for example, "192.168.5.21".
+    //- An IPv6 address enclosed in square brackets—for example, "[2001:0DB8:ABCD:0012::F1]".
+    //- A hostname—for example, "example.com".
+    //
+    // The port is separated by a colon. It must be non-empty, with a decimal number
+    // in the range of 0-65535, inclusive.
+    bool host_and_port = 32 [
+      (predefined).cel = {
+        id: "string.host_and_port"
+        message: "value must be a valid host (hostname or IP address) and port pair"
+        expression: "!rules.host_and_port || this == '' || this.isHostAndPort(true)"
+      },
+      (predefined).cel = {
+        id: "string.host_and_port_empty"
+        message: "value is empty, which is not a valid host and port pair"
+        expression: "!rules.host_and_port || this != ''"
+      }
+    ];
+
+    // `well_known_regex` specifies a common well-known pattern
+    // defined as a regex. If the field value doesn't match the well-known
+    // regex, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid HTTP header value
+    //   string value = 1 [(buf.validate.field).string.well_known_regex = KNOWN_REGEX_HTTP_HEADER_VALUE];
+    // }
+    // ```
+    //
+    // #### KnownRegex
+    //
+    // `well_known_regex` contains some well-known patterns.
+    //
+    // | Name                          | Number | Description                               |
+    // |-------------------------------|--------|-------------------------------------------|
+    // | KNOWN_REGEX_UNSPECIFIED       | 0      |                                           |
+    // | KNOWN_REGEX_HTTP_HEADER_NAME  | 1      | HTTP header name as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2)  |
+    // | KNOWN_REGEX_HTTP_HEADER_VALUE | 2      | HTTP header value as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4) |
+    KnownRegex well_known_regex = 24 [
+      (predefined).cel = {
+        id: "string.well_known_regex.header_name"
+        message: "value must be a valid HTTP header name"
+        expression:
+            "rules.well_known_regex != 1 || this == '' || this.matches(!has(rules.strict) || rules.strict ?"
+                "'^:?[0-9a-zA-Z!#$%&\\'*+-.^_|~\\x60]+$' :"
+                "'^[^\\u0000\\u000A\\u000D]+$')"
+      },
+      (predefined).cel = {
+        id: "string.well_known_regex.header_name_empty"
+        message: "value is empty, which is not a valid HTTP header name"
+        expression: "rules.well_known_regex != 1 || this != ''"
+      },
+      (predefined).cel = {
+        id: "string.well_known_regex.header_value"
+        message: "value must be a valid HTTP header value"
+        expression:
+            "rules.well_known_regex != 2 || this.matches(!has(rules.strict) || rules.strict ?"
+                "'^[^\\u0000-\\u0008\\u000A-\\u001F\\u007F]*$' :"
+                "'^[^\\u0000\\u000A\\u000D]*$')"
+      }
+    ];
+  }
+
+  // This applies to regexes `HTTP_HEADER_NAME` and `HTTP_HEADER_VALUE` to
+  // enable strict header validation. By default, this is true, and HTTP header
+  // validations are [RFC-compliant](https://datatracker.ietf.org/doc/html/rfc7230#section-3). Setting to false will enable looser
+  // validations that only disallow `\r\n\0` characters, which can be used to
+  // bypass header matching rules.
+  //
+  // ```proto
+  // message MyString {
+  //   // The field `value` must have be a valid HTTP headers, but not enforced with strict rules.
+  //   string value = 1 [(buf.validate.field).string.strict = false];
+  // }
+  // ```
+  optional bool strict = 25;
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyString {
+  //   string value = 1 [
+  //     (buf.validate.field).string.example = "hello",
+  //     (buf.validate.field).string.example = "world"
+  //   ];
+  // }
+  // ```
+  repeated string example = 34 [(predefined).cel = {
+    id: "string.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// KnownRegex contains some well-known patterns.
+enum KnownRegex {
+  KNOWN_REGEX_UNSPECIFIED = 0;
+
+  // HTTP header name as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2).
+  KNOWN_REGEX_HTTP_HEADER_NAME = 1;
+
+  // HTTP header value as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4).
+  KNOWN_REGEX_HTTP_HEADER_VALUE = 2;
+}
+
+// BytesRules describe the rules applied to `bytes` values. These rules
+// may also be applied to the `google.protobuf.BytesValue` Well-Known-Type.
+message BytesRules {
+  // `const` requires the field value to exactly match the specified bytes
+  // value. If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must be "\x01\x02\x03\x04"
+  //   bytes value = 1 [(buf.validate.field).bytes.const = "\x01\x02\x03\x04"];
+  // }
+  // ```
+  optional bytes const = 1 [(predefined).cel = {
+    id: "bytes.const"
+    expression: "this != getField(rules, 'const') ? 'value must be %x'.format([getField(rules, 'const')]) : ''"
+  }];
+
+  // `len` requires the field value to have the specified length in bytes.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value length must be 4 bytes.
+  //   optional bytes value = 1 [(buf.validate.field).bytes.len = 4];
+  // }
+  // ```
+  optional uint64 len = 13 [(predefined).cel = {
+    id: "bytes.len"
+    expression: "uint(this.size()) != rules.len ? 'value length must be %s bytes'.format([rules.len]) : ''"
+  }];
+
+  // `min_len` requires the field value to have at least the specified minimum
+  // length in bytes.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value length must be at least 2 bytes.
+  //   optional bytes value = 1 [(buf.validate.field).bytes.min_len = 2];
+  // }
+  // ```
+  optional uint64 min_len = 2 [(predefined).cel = {
+    id: "bytes.min_len"
+    expression: "uint(this.size()) < rules.min_len ? 'value length must be at least %s bytes'.format([rules.min_len]) : ''"
+  }];
+
+  // `max_len` requires the field value to have at most the specified maximum
+  // length in bytes.
+  // If the field value exceeds the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must be at most 6 bytes.
+  //   optional bytes value = 1 [(buf.validate.field).bytes.max_len = 6];
+  // }
+  // ```
+  optional uint64 max_len = 3 [(predefined).cel = {
+    id: "bytes.max_len"
+    expression: "uint(this.size()) > rules.max_len ? 'value must be at most %s bytes'.format([rules.max_len]) : ''"
+  }];
+
+  // `pattern` requires the field value to match the specified regular
+  // expression ([RE2 syntax](https://github.com/google/re2/wiki/Syntax)).
+  // The value of the field must be valid UTF-8 or validation will fail with a
+  // runtime error.
+  // If the field value doesn't match the pattern, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must match regex pattern "^[a-zA-Z0-9]+$".
+  //   optional bytes value = 1 [(buf.validate.field).bytes.pattern = "^[a-zA-Z0-9]+$"];
+  // }
+  // ```
+  optional string pattern = 4 [(predefined).cel = {
+    id: "bytes.pattern"
+    expression: "!string(this).matches(rules.pattern) ? 'value must match regex pattern `%s`'.format([rules.pattern]) : ''"
+  }];
+
+  // `prefix` requires the field value to have the specified bytes at the
+  // beginning of the string.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value does not have prefix \x01\x02
+  //   optional bytes value = 1 [(buf.validate.field).bytes.prefix = "\x01\x02"];
+  // }
+  // ```
+  optional bytes prefix = 5 [(predefined).cel = {
+    id: "bytes.prefix"
+    expression: "!this.startsWith(rules.prefix) ? 'value does not have prefix %x'.format([rules.prefix]) : ''"
+  }];
+
+  // `suffix` requires the field value to have the specified bytes at the end
+  // of the string.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value does not have suffix \x03\x04
+  //   optional bytes value = 1 [(buf.validate.field).bytes.suffix = "\x03\x04"];
+  // }
+  // ```
+  optional bytes suffix = 6 [(predefined).cel = {
+    id: "bytes.suffix"
+    expression: "!this.endsWith(rules.suffix) ? 'value does not have suffix %x'.format([rules.suffix]) : ''"
+  }];
+
+  // `contains` requires the field value to have the specified bytes anywhere in
+  // the string.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```protobuf
+  // message MyBytes {
+  //   // value does not contain \x02\x03
+  //   optional bytes value = 1 [(buf.validate.field).bytes.contains = "\x02\x03"];
+  // }
+  // ```
+  optional bytes contains = 7 [(predefined).cel = {
+    id: "bytes.contains"
+    expression: "!this.contains(rules.contains) ? 'value does not contain %x'.format([rules.contains]) : ''"
+  }];
+
+  // `in` requires the field value to be equal to one of the specified
+  // values. If the field value doesn't match any of the specified values, an
+  // error message is generated.
+  //
+  // ```protobuf
+  // message MyBytes {
+  //   // value must in ["\x01\x02", "\x02\x03", "\x03\x04"]
+  //   optional bytes value = 1 [(buf.validate.field).bytes.in = {"\x01\x02", "\x02\x03", "\x03\x04"}];
+  // }
+  // ```
+  repeated bytes in = 8 [(predefined).cel = {
+    id: "bytes.in"
+    expression: "getField(rules, 'in').size() > 0 && !(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to be not equal to any of the specified
+  // values.
+  // If the field value matches any of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must not in ["\x01\x02", "\x02\x03", "\x03\x04"]
+  //   optional bytes value = 1 [(buf.validate.field).bytes.not_in = {"\x01\x02", "\x02\x03", "\x03\x04"}];
+  // }
+  // ```
+  repeated bytes not_in = 9 [(predefined).cel = {
+    id: "bytes.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // WellKnown rules provide advanced rules against common byte
+  // patterns
+  oneof well_known {
+    // `ip` ensures that the field `value` is a valid IP address (v4 or v6) in byte format.
+    // If the field value doesn't meet this rule, an error message is generated.
+    //
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid IP address
+    //   optional bytes value = 1 [(buf.validate.field).bytes.ip = true];
+    // }
+    // ```
+    bool ip = 10 [
+      (predefined).cel = {
+        id: "bytes.ip"
+        message: "value must be a valid IP address"
+        expression: "!rules.ip || this.size() == 0 || this.size() == 4 || this.size() == 16"
+      },
+      (predefined).cel = {
+        id: "bytes.ip_empty"
+        message: "value is empty, which is not a valid IP address"
+        expression: "!rules.ip || this.size() != 0"
+      }
+    ];
+
+    // `ipv4` ensures that the field `value` is a valid IPv4 address in byte format.
+    // If the field value doesn't meet this rule, an error message is generated.
+    //
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid IPv4 address
+    //   optional bytes value = 1 [(buf.validate.field).bytes.ipv4 = true];
+    // }
+    // ```
+    bool ipv4 = 11 [
+      (predefined).cel = {
+        id: "bytes.ipv4"
+        message: "value must be a valid IPv4 address"
+        expression: "!rules.ipv4 || this.size() == 0 || this.size() == 4"
+      },
+      (predefined).cel = {
+        id: "bytes.ipv4_empty"
+        message: "value is empty, which is not a valid IPv4 address"
+        expression: "!rules.ipv4 || this.size() != 0"
+      }
+    ];
+
+    // `ipv6` ensures that the field `value` is a valid IPv6 address in byte format.
+    // If the field value doesn't meet this rule, an error message is generated.
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid IPv6 address
+    //   optional bytes value = 1 [(buf.validate.field).bytes.ipv6 = true];
+    // }
+    // ```
+    bool ipv6 = 12 [
+      (predefined).cel = {
+        id: "bytes.ipv6"
+        message: "value must be a valid IPv6 address"
+        expression: "!rules.ipv6 || this.size() == 0 || this.size() == 16"
+      },
+      (predefined).cel = {
+        id: "bytes.ipv6_empty"
+        message: "value is empty, which is not a valid IPv6 address"
+        expression: "!rules.ipv6 || this.size() != 0"
+      }
+    ];
+  }
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyBytes {
+  //   bytes value = 1 [
+  //     (buf.validate.field).bytes.example = "\x01\x02",
+  //     (buf.validate.field).bytes.example = "\x02\x03"
+  //   ];
+  // }
+  // ```
+  repeated bytes example = 14 [(predefined).cel = {
+    id: "bytes.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// EnumRules describe the rules applied to `enum` values.
+message EnumRules {
+  // `const` requires the field value to exactly match the specified enum value.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must be exactly MY_ENUM_VALUE1.
+  //   MyEnum value = 1 [(buf.validate.field).enum.const = 1];
+  // }
+  // ```
+  optional int32 const = 1 [(predefined).cel = {
+    id: "enum.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+
+  // `defined_only` requires the field value to be one of the defined values for
+  // this enum, failing on any undefined value.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must be a defined value of MyEnum.
+  //   MyEnum value = 1 [(buf.validate.field).enum.defined_only = true];
+  // }
+  // ```
+  optional bool defined_only = 2;
+
+  // `in` requires the field value to be equal to one of the
+  //specified enum values. If the field value doesn't match any of the
+  //specified values, an error message is generated.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must be equal to one of the specified values.
+  //   MyEnum value = 1 [(buf.validate.field).enum = { in: [1, 2]}];
+  // }
+  // ```
+  repeated int32 in = 3 [(predefined).cel = {
+    id: "enum.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` requires the field value to be not equal to any of the
+  //specified enum values. If the field value matches one of the specified
+  // values, an error message is generated.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must not be equal to any of the specified values.
+  //   MyEnum value = 1 [(buf.validate.field).enum = { not_in: [1, 2]}];
+  // }
+  // ```
+  repeated int32 not_in = 4 [(predefined).cel = {
+    id: "enum.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //     (buf.validate.field).enum.example = 1,
+  //     (buf.validate.field).enum.example = 2
+  // }
+  // ```
+  repeated int32 example = 5 [(predefined).cel = {
+    id: "enum.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// RepeatedRules describe the rules applied to `repeated` values.
+message RepeatedRules {
+  // `min_items` requires that this field must contain at least the specified
+  // minimum number of items.
+  //
+  // Note that `min_items = 1` is equivalent to setting a field as `required`.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // value must contain at least  2 items
+  //   repeated string value = 1 [(buf.validate.field).repeated.min_items = 2];
+  // }
+  // ```
+  optional uint64 min_items = 1 [(predefined).cel = {
+    id: "repeated.min_items"
+    expression: "uint(this.size()) < rules.min_items ? 'value must contain at least %d item(s)'.format([rules.min_items]) : ''"
+  }];
+
+  // `max_items` denotes that this field must not exceed a
+  // certain number of items as the upper limit. If the field contains more
+  // items than specified, an error message will be generated, requiring the
+  // field to maintain no more than the specified number of items.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // value must contain no more than 3 item(s)
+  //   repeated string value = 1 [(buf.validate.field).repeated.max_items = 3];
+  // }
+  // ```
+  optional uint64 max_items = 2 [(predefined).cel = {
+    id: "repeated.max_items"
+    expression: "uint(this.size()) > rules.max_items ? 'value must contain no more than %s item(s)'.format([rules.max_items]) : ''"
+  }];
+
+  // `unique` indicates that all elements in this field must
+  // be unique. This rule is strictly applicable to scalar and enum
+  // types, with message types not being supported.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // repeated value must contain unique items
+  //   repeated string value = 1 [(buf.validate.field).repeated.unique = true];
+  // }
+  // ```
+  optional bool unique = 3 [(predefined).cel = {
+    id: "repeated.unique"
+    message: "repeated value must contain unique items"
+    expression: "!rules.unique || this.unique()"
+  }];
+
+  // `items` details the rules to be applied to each item
+  // in the field. Even for repeated message fields, validation is executed
+  // against each item unless `ignore` is specified.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // The items in the field `value` must follow the specified rules.
+  //   repeated string value = 1 [(buf.validate.field).repeated.items = {
+  //     string: {
+  //       min_len: 3
+  //       max_len: 10
+  //     }
+  //   }];
+  // }
+  // ```
+  //
+  // Note that the `required` rule does not apply. Repeated items
+  // cannot be unset.
+  optional FieldRules items = 4;
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// MapRules describe the rules applied to `map` values.
+message MapRules {
+  // Specifies the minimum number of key-value pairs allowed. If the field has
+  // fewer key-value pairs than specified, an error message is generated.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The field `value` must have at least 2 key-value pairs.
+  //   map<string, string> value = 1 [(buf.validate.field).map.min_pairs = 2];
+  // }
+  // ```
+  optional uint64 min_pairs = 1 [(predefined).cel = {
+    id: "map.min_pairs"
+    expression: "uint(this.size()) < rules.min_pairs ? 'map must be at least %d entries'.format([rules.min_pairs]) : ''"
+  }];
+
+  // Specifies the maximum number of key-value pairs allowed. If the field has
+  // more key-value pairs than specified, an error message is generated.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The field `value` must have at most 3 key-value pairs.
+  //   map<string, string> value = 1 [(buf.validate.field).map.max_pairs = 3];
+  // }
+  // ```
+  optional uint64 max_pairs = 2 [(predefined).cel = {
+    id: "map.max_pairs"
+    expression: "uint(this.size()) > rules.max_pairs ? 'map must be at most %d entries'.format([rules.max_pairs]) : ''"
+  }];
+
+  // Specifies the rules to be applied to each key in the field.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The keys in the field `value` must follow the specified rules.
+  //   map<string, string> value = 1 [(buf.validate.field).map.keys = {
+  //     string: {
+  //       min_len: 3
+  //       max_len: 10
+  //     }
+  //   }];
+  // }
+  // ```
+  //
+  // Note that the `required` rule does not apply. Map keys cannot be unset.
+  optional FieldRules keys = 4;
+
+  // Specifies the rules to be applied to the value of each key in the
+  // field. Message values will still have their validations evaluated unless
+  // `ignore` is specified.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The values in the field `value` must follow the specified rules.
+  //   map<string, string> value = 1 [(buf.validate.field).map.values = {
+  //     string: {
+  //       min_len: 5
+  //       max_len: 20
+  //     }
+  //   }];
+  // }
+  // ```
+  // Note that the `required` rule does not apply. Map values cannot be unset.
+  optional FieldRules values = 5;
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// AnyRules describe rules applied exclusively to the `google.protobuf.Any` well-known type.
+message AnyRules {
+  // `in` requires the field's `type_url` to be equal to one of the
+  //specified values. If it doesn't match any of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyAny {
+  //   //  The `value` field must have a `type_url` equal to one of the specified values.
+  //   google.protobuf.Any value = 1 [(buf.validate.field).any = {
+  //       in: ["type.googleapis.com/MyType1", "type.googleapis.com/MyType2"]
+  //   }];
+  // }
+  // ```
+  repeated string in = 2;
+
+  // requires the field's type_url to be not equal to any of the specified values. If it matches any of the specified values, an error message is generated.
+  //
+  // ```proto
+  // message MyAny {
+  //   //  The `value` field must not have a `type_url` equal to any of the specified values.
+  //   google.protobuf.Any value = 1 [(buf.validate.field).any = {
+  //       not_in: ["type.googleapis.com/ForbiddenType1", "type.googleapis.com/ForbiddenType2"]
+  //   }];
+  // }
+  // ```
+  repeated string not_in = 3;
+}
+
+// DurationRules describe the rules applied exclusively to the `google.protobuf.Duration` well-known type.
+message DurationRules {
+  // `const` dictates that the field must match the specified value of the `google.protobuf.Duration` type exactly.
+  // If the field's value deviates from the specified value, an error message
+  // will be generated.
+  //
+  // ```proto
+  // message MyDuration {
+  //   // value must equal 5s
+  //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.const = "5s"];
+  // }
+  // ```
+  optional google.protobuf.Duration const = 2 [(predefined).cel = {
+    id: "duration.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // `lt` stipulates that the field must be less than the specified value of the `google.protobuf.Duration` type,
+    // exclusive. If the field's value is greater than or equal to the specified
+    // value, an error message will be generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // value must be less than 5s
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.lt = "5s"];
+    // }
+    // ```
+    google.protobuf.Duration lt = 3 [(predefined).cel = {
+      id: "duration.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` indicates that the field must be less than or equal to the specified
+    // value of the `google.protobuf.Duration` type, inclusive. If the field's value is greater than the specified value,
+    // an error message will be generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // value must be less than or equal to 10s
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.lte = "10s"];
+    // }
+    // ```
+    google.protobuf.Duration lte = 4 [(predefined).cel = {
+      id: "duration.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the duration field value to be greater than the specified
+    // value (exclusive). If the value of `gt` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // duration must be greater than 5s [duration.gt]
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.gt = { seconds: 5 }];
+    //
+    //   // duration must be greater than 5s and less than 10s [duration.gt_lt]
+    //   google.protobuf.Duration another_value = 2 [(buf.validate.field).duration = { gt: { seconds: 5 }, lt: { seconds: 10 } }];
+    //
+    //   // duration must be greater than 10s or less than 5s [duration.gt_lt_exclusive]
+    //   google.protobuf.Duration other_value = 3 [(buf.validate.field).duration = { gt: { seconds: 10 }, lt: { seconds: 5 } }];
+    // }
+    // ```
+    google.protobuf.Duration gt = 5 [
+      (predefined).cel = {
+        id: "duration.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the duration field value to be greater than or equal to the
+    // specified value (exclusive). If the value of `gte` is larger than a
+    // specified `lt` or `lte`, the range is reversed, and the field value must
+    // be outside the specified range. If the field value doesn't meet the
+    // required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //  // duration must be greater than or equal to 5s [duration.gte]
+    //  google.protobuf.Duration value = 1 [(buf.validate.field).duration.gte = { seconds: 5 }];
+    //
+    //  // duration must be greater than or equal to 5s and less than 10s [duration.gte_lt]
+    //  google.protobuf.Duration another_value = 2 [(buf.validate.field).duration = { gte: { seconds: 5 }, lt: { seconds: 10 } }];
+    //
+    //  // duration must be greater than or equal to 10s or less than 5s [duration.gte_lt_exclusive]
+    //  google.protobuf.Duration other_value = 3 [(buf.validate.field).duration = { gte: { seconds: 10 }, lt: { seconds: 5 } }];
+    // }
+    // ```
+    google.protobuf.Duration gte = 6 [
+      (predefined).cel = {
+        id: "duration.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` asserts that the field must be equal to one of the specified values of the `google.protobuf.Duration` type.
+  // If the field's value doesn't correspond to any of the specified values,
+  // an error message will be generated.
+  //
+  // ```proto
+  // message MyDuration {
+  //   // value must be in list [1s, 2s, 3s]
+  //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.in = ["1s", "2s", "3s"]];
+  // }
+  // ```
+  repeated google.protobuf.Duration in = 7 [(predefined).cel = {
+    id: "duration.in"
+    expression: "!(this in getField(rules, 'in')) ? 'value must be in list %s'.format([getField(rules, 'in')]) : ''"
+  }];
+
+  // `not_in` denotes that the field must not be equal to
+  // any of the specified values of the `google.protobuf.Duration` type.
+  // If the field's value matches any of these values, an error message will be
+  // generated.
+  //
+  // ```proto
+  // message MyDuration {
+  //   // value must not be in list [1s, 2s, 3s]
+  //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.not_in = ["1s", "2s", "3s"]];
+  // }
+  // ```
+  repeated google.protobuf.Duration not_in = 8 [(predefined).cel = {
+    id: "duration.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyDuration {
+  //   google.protobuf.Duration value = 1 [
+  //     (buf.validate.field).duration.example = { seconds: 1 },
+  //     (buf.validate.field).duration.example = { seconds: 2 },
+  //   ];
+  // }
+  // ```
+  repeated google.protobuf.Duration example = 9 [(predefined).cel = {
+    id: "duration.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// TimestampRules describe the rules applied exclusively to the `google.protobuf.Timestamp` well-known type.
+message TimestampRules {
+  // `const` dictates that this field, of the `google.protobuf.Timestamp` type, must exactly match the specified value. If the field value doesn't correspond to the specified timestamp, an error message will be generated.
+  //
+  // ```proto
+  // message MyTimestamp {
+  //   // value must equal 2023-05-03T10:00:00Z
+  //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.const = {seconds: 1727998800}];
+  // }
+  // ```
+  optional google.protobuf.Timestamp const = 2 [(predefined).cel = {
+    id: "timestamp.const"
+    expression: "this != getField(rules, 'const') ? 'value must equal %s'.format([getField(rules, 'const')]) : ''"
+  }];
+  oneof less_than {
+    // requires the duration field value to be less than the specified value (field < value). If the field value doesn't meet the required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // duration must be less than 'P3D' [duration.lt]
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.lt = { seconds: 259200 }];
+    // }
+    // ```
+    google.protobuf.Timestamp lt = 3 [(predefined).cel = {
+      id: "timestamp.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // requires the timestamp field value to be less than or equal to the specified value (field <= value). If the field value doesn't meet the required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // timestamp must be less than or equal to '2023-05-14T00:00:00Z' [timestamp.lte]
+    //   google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.lte = { seconds: 1678867200 }];
+    // }
+    // ```
+    google.protobuf.Timestamp lte = 4 [(predefined).cel = {
+      id: "timestamp.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+
+    // `lt_now` specifies that this field, of the `google.protobuf.Timestamp` type, must be less than the current time. `lt_now` can only be used with the `within` rule.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //  // value must be less than now
+    //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.lt_now = true];
+    // }
+    // ```
+    bool lt_now = 7 [(predefined).cel = {
+      id: "timestamp.lt_now"
+      expression: "(rules.lt_now && this > now) ? 'value must be less than now' : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the timestamp field value to be greater than the specified
+    // value (exclusive). If the value of `gt` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // timestamp must be greater than '2023-01-01T00:00:00Z' [timestamp.gt]
+    //   google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.gt = { seconds: 1672444800 }];
+    //
+    //   // timestamp must be greater than '2023-01-01T00:00:00Z' and less than '2023-01-02T00:00:00Z' [timestamp.gt_lt]
+    //   google.protobuf.Timestamp another_value = 2 [(buf.validate.field).timestamp = { gt: { seconds: 1672444800 }, lt: { seconds: 1672531200 } }];
+    //
+    //   // timestamp must be greater than '2023-01-02T00:00:00Z' or less than '2023-01-01T00:00:00Z' [timestamp.gt_lt_exclusive]
+    //   google.protobuf.Timestamp other_value = 3 [(buf.validate.field).timestamp = { gt: { seconds: 1672531200 }, lt: { seconds: 1672444800 } }];
+    // }
+    // ```
+    google.protobuf.Timestamp gt = 5 [
+      (predefined).cel = {
+        id: "timestamp.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the timestamp field value to be greater than or equal to the
+    // specified value (exclusive). If the value of `gte` is larger than a
+    // specified `lt` or `lte`, the range is reversed, and the field value
+    // must be outside the specified range. If the field value doesn't meet
+    // the required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // timestamp must be greater than or equal to '2023-01-01T00:00:00Z' [timestamp.gte]
+    //   google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.gte = { seconds: 1672444800 }];
+    //
+    //   // timestamp must be greater than or equal to '2023-01-01T00:00:00Z' and less than '2023-01-02T00:00:00Z' [timestamp.gte_lt]
+    //   google.protobuf.Timestamp another_value = 2 [(buf.validate.field).timestamp = { gte: { seconds: 1672444800 }, lt: { seconds: 1672531200 } }];
+    //
+    //   // timestamp must be greater than or equal to '2023-01-02T00:00:00Z' or less than '2023-01-01T00:00:00Z' [timestamp.gte_lt_exclusive]
+    //   google.protobuf.Timestamp other_value = 3 [(buf.validate.field).timestamp = { gte: { seconds: 1672531200 }, lt: { seconds: 1672444800 } }];
+    // }
+    // ```
+    google.protobuf.Timestamp gte = 6 [
+      (predefined).cel = {
+        id: "timestamp.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+
+    // `gt_now` specifies that this field, of the `google.protobuf.Timestamp` type, must be greater than the current time. `gt_now` can only be used with the `within` rule.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // value must be greater than now
+    //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.gt_now = true];
+    // }
+    // ```
+    bool gt_now = 8 [(predefined).cel = {
+      id: "timestamp.gt_now"
+      expression: "(rules.gt_now && this < now) ? 'value must be greater than now' : ''"
+    }];
+  }
+
+  // `within` specifies that this field, of the `google.protobuf.Timestamp` type, must be within the specified duration of the current time. If the field value isn't within the duration, an error message is generated.
+  //
+  // ```proto
+  // message MyTimestamp {
+  //   // value must be within 1 hour of now
+  //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.within = {seconds: 3600}];
+  // }
+  // ```
+  optional google.protobuf.Duration within = 9 [(predefined).cel = {
+    id: "timestamp.within"
+    expression: "this < now-rules.within || this > now+rules.within ? 'value must be within %s of now'.format([rules.within]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyTimestamp {
+  //   google.protobuf.Timestamp value = 1 [
+  //     (buf.validate.field).timestamp.example = { seconds: 1672444800 },
+  //     (buf.validate.field).timestamp.example = { seconds: 1672531200 },
+  //   ];
+  // }
+  // ```
+  repeated google.protobuf.Timestamp example = 10 [(predefined).cel = {
+    id: "timestamp.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// `Violations` is a collection of `Violation` messages. This message type is returned by
+// Protovalidate when a proto message fails to meet the requirements set by the `Rule` validation rules.
+// Each individual violation is represented by a `Violation` message.
+message Violations {
+  // `violations` is a repeated field that contains all the `Violation` messages corresponding to the violations detected.
+  repeated Violation violations = 1;
+}
+
+// `Violation` represents a single instance where a validation rule, expressed
+// as a `Rule`, was not met. It provides information about the field that
+// caused the violation, the specific rule that wasn't fulfilled, and a
+// human-readable error message.
+//
+// For example, consider the following message:
+//
+// ```proto
+// message User {
+//     int32 age = 1 [(buf.validate.field).cel = {
+//         id: "user.age",
+//         expression: "this < 18 ? 'User must be at least 18 years old' : ''",
+//     }];
+// }
+// ```
+//
+// It could produce the following violation:
+//
+// ```json
+// {
+//   "ruleId": "user.age",
+//   "message": "User must be at least 18 years old",
+//   "field": {
+//     "elements": [
+//       {
+//         "fieldNumber": 1,
+//         "fieldName": "age",
+//         "fieldType": "TYPE_INT32"
+//       }
+//     ]
+//   },
+//   "rule": {
+//     "elements": [
+//       {
+//         "fieldNumber": 23,
+//         "fieldName": "cel",
+//         "fieldType": "TYPE_MESSAGE",
+//         "index": "0"
+//       }
+//     ]
+//   }
+// }
+// ```
+message Violation {
+  // `field` is a machine-readable path to the field that failed validation.
+  // This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+  //
+  // For example, consider the following message:
+  //
+  // ```proto
+  // message Message {
+  //   bool a = 1 [(buf.validate.field).required = true];
+  // }
+  // ```
+  //
+  // It could produce the following violation:
+  //
+  // ```textproto
+  // violation {
+  //   field { element { field_number: 1, field_name: "a", field_type: 8 } }
+  //   ...
+  // }
+  // ```
+  optional FieldPath field = 5;
+
+  // `rule` is a machine-readable path that points to the specific rule that failed validation.
+  // This will be a nested field starting from the FieldRules of the field that failed validation.
+  // For custom rules, this will provide the path of the rule, e.g. `cel[0]`.
+  //
+  // For example, consider the following message:
+  //
+  // ```proto
+  // message Message {
+  //   bool a = 1 [(buf.validate.field).required = true];
+  //   bool b = 2 [(buf.validate.field).cel = {
+  //     id: "custom_rule",
+  //     expression: "!this ? 'b must be true': ''"
+  //   }]
+  // }
+  // ```
+  //
+  // It could produce the following violations:
+  //
+  // ```textproto
+  // violation {
+  //   rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+  //   ...
+  // }
+  // violation {
+  //   rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+  //   ...
+  // }
+  // ```
+  optional FieldPath rule = 6;
+
+  // `rule_id` is the unique identifier of the `Rule` that was not fulfilled.
+  // This is the same `id` that was specified in the `Rule` message, allowing easy tracing of which rule was violated.
+  optional string rule_id = 2;
+
+  // `message` is a human-readable error message that describes the nature of the violation.
+  // This can be the default error message from the violated `Rule`, or it can be a custom message that gives more context about the violation.
+  optional string message = 3;
+
+  // `for_key` indicates whether the violation was caused by a map key, rather than a value.
+  optional bool for_key = 4;
+
+  reserved 1;
+  reserved "field_path";
+}
+
+// `FieldPath` provides a path to a nested protobuf field.
+//
+// This message provides enough information to render a dotted field path even without protobuf descriptors.
+// It also provides enough information to resolve a nested field through unknown wire data.
+message FieldPath {
+  // `elements` contains each element of the path, starting from the root and recursing downward.
+  repeated FieldPathElement elements = 1;
+}
+
+// `FieldPathElement` provides enough information to nest through a single protobuf field.
+//
+// If the selected field is a map or repeated field, the `subscript` value selects a specific element from it.
+// A path that refers to a value nested under a map key or repeated field index will have a `subscript` value.
+// The `field_type` field allows unambiguous resolution of a field even if descriptors are not available.
+message FieldPathElement {
+  // `field_number` is the field number this path element refers to.
+  optional int32 field_number = 1;
+
+  // `field_name` contains the field name this path element refers to.
+  // This can be used to display a human-readable path even if the field number is unknown.
+  optional string field_name = 2;
+
+  // `field_type` specifies the type of this field. When using reflection, this value is not needed.
+  //
+  // This value is provided to make it possible to traverse unknown fields through wire data.
+  // When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+  //
+  // [1]: https://protobuf.dev/programming-guides/encoding/#packed
+  // [2]: https://protobuf.dev/programming-guides/encoding/#groups
+  //
+  // N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+  // can be explicitly used in Protocol Buffers 2023 Edition.
+  optional google.protobuf.FieldDescriptorProto.Type field_type = 3;
+
+  // `key_type` specifies the map key type of this field. This value is useful when traversing
+  // unknown fields through wire data: specifically, it allows handling the differences between
+  // different integer encodings.
+  optional google.protobuf.FieldDescriptorProto.Type key_type = 4;
+
+  // `value_type` specifies map value type of this field. This is useful if you want to display a
+  // value inside unknown fields through wire data.
+  optional google.protobuf.FieldDescriptorProto.Type value_type = 5;
+
+  // `subscript` contains a repeated index or map key, if this path element nests into a repeated or map field.
+  oneof subscript {
+    // `index` specifies a 0-based index into a repeated field.
+    uint64 index = 6;
+
+    // `bool_key` specifies a map key of type bool.
+    bool bool_key = 7;
+
+    // `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+    int64 int_key = 8;
+
+    // `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+    uint64 uint_key = 9;
+
+    // `string_key` specifies a map key of type string.
+    string string_key = 10;
+  }
+}