From 4c2a13712b0fa716b41083bb65cdee3931395e38 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Tue, 7 Jul 2026 16:22:03 +0900 Subject: [PATCH] Centralize admin validation rules --- .../DTOs/SubmitInquiryDto.cs | 8 +-- .../DTOs/UpdateInquiryDto.cs | 10 ++-- .../DTOs/ValidationRules.cs | 22 ++++++++ .../Components/Admin/Forms/AdminFormModels.cs | 55 ++++++++++--------- 4 files changed, 59 insertions(+), 36 deletions(-) create mode 100644 src/TaxBaik.Application/DTOs/ValidationRules.cs diff --git a/src/TaxBaik.Application/DTOs/SubmitInquiryDto.cs b/src/TaxBaik.Application/DTOs/SubmitInquiryDto.cs index 8d944f8..7a821a3 100644 --- a/src/TaxBaik.Application/DTOs/SubmitInquiryDto.cs +++ b/src/TaxBaik.Application/DTOs/SubmitInquiryDto.cs @@ -5,23 +5,23 @@ using System.ComponentModel.DataAnnotations; public class SubmitInquiryDto { [Required(ErrorMessage = "이름을 입력하세요.")] - [StringLength(100, ErrorMessage = "이름은 최대 100자까지 입력 가능합니다.")] + [StringLength(ValidationRules.NameMaxLength, ErrorMessage = "이름은 최대 100자까지 입력 가능합니다.")] public string Name { get; set; } = string.Empty; [Required(ErrorMessage = "전화번호를 입력하세요.")] [RegularExpression( - @"^(0(?:2|3[1-3]|4[1-4]|5[1-5]|6[1-4]|70|50[5-9]|[7-9](?:\d{1,2})?)\d{7,8}|0\d{9,10})$", + ValidationRules.KoreanPhonePattern, ErrorMessage = "올바른 전화번호 형식이 아닙니다.")] public string Phone { get; set; } = string.Empty; [EmailAddress(ErrorMessage = "올바른 이메일 형식이 아닙니다.")] public string? Email { get; set; } - [StringLength(50, ErrorMessage = "상담분야는 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "상담분야는 최대 50자까지 입력 가능합니다.")] public string ServiceType { get; set; } = string.Empty; [Required(ErrorMessage = "문의 내용을 입력하세요.")] - [StringLength(5000, MinimumLength = 10, ErrorMessage = "문의 내용은 최소 10자, 최대 5000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MessageMaxLength, MinimumLength = ValidationRules.MessageMinLength, ErrorMessage = "문의 내용은 최소 10자, 최대 5000자까지 입력 가능합니다.")] public string Message { get; set; } = string.Empty; public bool SuppressNotification { get; set; } diff --git a/src/TaxBaik.Application/DTOs/UpdateInquiryDto.cs b/src/TaxBaik.Application/DTOs/UpdateInquiryDto.cs index 0b153be..e7b36c8 100644 --- a/src/TaxBaik.Application/DTOs/UpdateInquiryDto.cs +++ b/src/TaxBaik.Application/DTOs/UpdateInquiryDto.cs @@ -5,28 +5,28 @@ using System.ComponentModel.DataAnnotations; public class UpdateInquiryDto { [Required(ErrorMessage = "이름을 입력하세요.")] - [StringLength(100, ErrorMessage = "이름은 최대 100자까지 입력 가능합니다.")] + [StringLength(ValidationRules.NameMaxLength, ErrorMessage = "이름은 최대 100자까지 입력 가능합니다.")] public string Name { get; set; } = string.Empty; [Required(ErrorMessage = "전화번호를 입력하세요.")] [RegularExpression( - @"^(0(?:2|3[1-3]|4[1-4]|5[1-5]|6[1-4]|70|50[5-9]|[7-9](?:\d{1,2})?)\d{7,8}|0\d{9,10})$", + ValidationRules.KoreanPhonePattern, ErrorMessage = "올바른 전화번호 형식이 아닙니다.")] public string Phone { get; set; } = string.Empty; [EmailAddress(ErrorMessage = "올바른 이메일 형식이 아닙니다.")] public string? Email { get; set; } - [StringLength(50, ErrorMessage = "상담분야는 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "상담분야는 최대 50자까지 입력 가능합니다.")] public string ServiceType { get; set; } = string.Empty; [Required(ErrorMessage = "문의 내용을 입력하세요.")] - [StringLength(5000, MinimumLength = 10, ErrorMessage = "문의 내용은 최소 10자, 최대 5000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MessageMaxLength, MinimumLength = ValidationRules.MessageMinLength, ErrorMessage = "문의 내용은 최소 10자, 최대 5000자까지 입력 가능합니다.")] public string Message { get; set; } = string.Empty; [Required(ErrorMessage = "상태를 선택하세요.")] public string Status { get; set; } = string.Empty; - [StringLength(1000, ErrorMessage = "관리 메모는 최대 1000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MemoMaxLength, ErrorMessage = "관리 메모는 최대 1000자까지 입력 가능합니다.")] public string? AdminMemo { get; set; } } diff --git a/src/TaxBaik.Application/DTOs/ValidationRules.cs b/src/TaxBaik.Application/DTOs/ValidationRules.cs new file mode 100644 index 0000000..f72d111 --- /dev/null +++ b/src/TaxBaik.Application/DTOs/ValidationRules.cs @@ -0,0 +1,22 @@ +namespace TaxBaik.Application.DTOs; + +public static class ValidationRules +{ + public const int NameMaxLength = 100; + public const int PhoneMaxLength = 20; + public const int ServiceTypeMaxLength = 50; + public const int MessageMaxLength = 5000; + public const int MessageMinLength = 10; + public const int MemoMaxLength = 1000; + public const int TitleMaxLength = 100; + public const int QuestionMaxLength = 300; + public const int ContentMaxLength = 30000; + public const int TagsMaxLength = 500; + public const int SeoTitleMaxLength = 120; + public const int SeoDescriptionMaxLength = 300; + public const int ContractNumberMaxLength = 50; + public const int RiskLevelMaxLength = 20; + + public const string KoreanPhonePattern = + @"^(0(?:2|3[1-3]|4[1-4]|5[1-5]|6[1-4]|70|50[5-9]|[7-9](?:\d{1,2})?)\d{7,8}|0\d{9,10})$"; +} diff --git a/src/TaxBaik.Web.Client/Components/Admin/Forms/AdminFormModels.cs b/src/TaxBaik.Web.Client/Components/Admin/Forms/AdminFormModels.cs index 20a31f8..2edacb5 100644 --- a/src/TaxBaik.Web.Client/Components/Admin/Forms/AdminFormModels.cs +++ b/src/TaxBaik.Web.Client/Components/Admin/Forms/AdminFormModels.cs @@ -1,6 +1,7 @@ namespace TaxBaik.WasmClient.Components.Admin.Forms; using System.ComponentModel.DataAnnotations; +using TaxBaik.Application.DTOs; public sealed class CompanyFormModel { @@ -30,51 +31,51 @@ public sealed class CompanyFormModel public sealed class InquiryFormModel { [Required(ErrorMessage = "이름을 입력하세요.")] - [StringLength(100, ErrorMessage = "이름은 최대 100자까지 입력 가능합니다.")] + [StringLength(ValidationRules.NameMaxLength, ErrorMessage = "이름은 최대 100자까지 입력 가능합니다.")] public string Name { get; set; } = ""; [Required(ErrorMessage = "전화번호를 입력하세요.")] [RegularExpression( - @"^(0(?:2|3[1-3]|4[1-4]|5[1-5]|6[1-4]|70|50[5-9]|[7-9](?:\d{1,2})?)\d{7,8}|0\d{9,10})$", + ValidationRules.KoreanPhonePattern, ErrorMessage = "올바른 전화번호 형식이 아닙니다.")] public string Phone { get; set; } = ""; [EmailAddress(ErrorMessage = "올바른 이메일 형식이 아닙니다.")] public string? Email { get; set; } - [StringLength(50, ErrorMessage = "상담분야는 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "상담분야는 최대 50자까지 입력 가능합니다.")] public string ServiceType { get; set; } = "기타"; [Required(ErrorMessage = "문의 내용을 입력하세요.")] - [StringLength(5000, MinimumLength = 10, ErrorMessage = "문의 내용은 최소 10자, 최대 5000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MessageMaxLength, MinimumLength = ValidationRules.MessageMinLength, ErrorMessage = "문의 내용은 최소 10자, 최대 5000자까지 입력 가능합니다.")] public string Message { get; set; } = ""; [Required(ErrorMessage = "상태를 선택하세요.")] public string Status { get; set; } = "new"; - [StringLength(1000, ErrorMessage = "관리 메모는 최대 1000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MemoMaxLength, ErrorMessage = "관리 메모는 최대 1000자까지 입력 가능합니다.")] public string? AdminMemo { get; set; } } public sealed class BlogFormModel { [Required(ErrorMessage = "제목을 입력하세요.")] - [StringLength(100, ErrorMessage = "제목은 최대 100자까지 입력 가능합니다.")] + [StringLength(ValidationRules.TitleMaxLength, ErrorMessage = "제목은 최대 100자까지 입력 가능합니다.")] public string Title { get; set; } = ""; [Required(ErrorMessage = "본문 내용을 입력하세요.")] - [StringLength(30000, MinimumLength = 10, ErrorMessage = "본문은 최소 10자 이상이어야 합니다.")] + [StringLength(ValidationRules.ContentMaxLength, MinimumLength = ValidationRules.MessageMinLength, ErrorMessage = "본문은 최소 10자 이상이어야 합니다.")] public string Content { get; set; } = ""; public int? CategoryId { get; set; } - [StringLength(500, ErrorMessage = "태그는 최대 500자까지 입력 가능합니다.")] + [StringLength(ValidationRules.TagsMaxLength, ErrorMessage = "태그는 최대 500자까지 입력 가능합니다.")] public string? Tags { get; set; } - [StringLength(120, ErrorMessage = "SEO 제목은 최대 120자까지 입력 가능합니다.")] + [StringLength(ValidationRules.SeoTitleMaxLength, ErrorMessage = "SEO 제목은 최대 120자까지 입력 가능합니다.")] public string? SeoTitle { get; set; } - [StringLength(300, ErrorMessage = "SEO 설명은 최대 300자까지 입력 가능합니다.")] + [StringLength(ValidationRules.SeoDescriptionMaxLength, ErrorMessage = "SEO 설명은 최대 300자까지 입력 가능합니다.")] public string? SeoDescription { get; set; } public bool IsPublished { get; set; } @@ -83,14 +84,14 @@ public sealed class BlogFormModel public sealed class FaqFormModel { [Required(ErrorMessage = "질문을 입력하세요.")] - [StringLength(300, ErrorMessage = "질문은 최대 300자까지 입력 가능합니다.")] + [StringLength(ValidationRules.QuestionMaxLength, ErrorMessage = "질문은 최대 300자까지 입력 가능합니다.")] public string Question { get; set; } = ""; [Required(ErrorMessage = "답변을 입력하세요.")] - [StringLength(5000, MinimumLength = 10, ErrorMessage = "답변은 최소 10자, 최대 5000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MessageMaxLength, MinimumLength = ValidationRules.MessageMinLength, ErrorMessage = "답변은 최소 10자, 최대 5000자까지 입력 가능합니다.")] public string Answer { get; set; } = ""; - [StringLength(50, ErrorMessage = "카테고리는 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "카테고리는 최대 50자까지 입력 가능합니다.")] public string? Category { get; set; } [Range(0, 9999, ErrorMessage = "정렬 순서는 0 이상 9999 이하이어야 합니다.")] @@ -102,31 +103,31 @@ public sealed class FaqFormModel public sealed class ClientFormModel { [Required(ErrorMessage = "고객명을 입력하세요.")] - [StringLength(100, ErrorMessage = "고객명은 최대 100자까지 입력 가능합니다.")] + [StringLength(ValidationRules.NameMaxLength, ErrorMessage = "고객명은 최대 100자까지 입력 가능합니다.")] public string Name { get; set; } = ""; - [StringLength(100, ErrorMessage = "회사명은 최대 100자까지 입력 가능합니다.")] + [StringLength(ValidationRules.NameMaxLength, ErrorMessage = "회사명은 최대 100자까지 입력 가능합니다.")] public string? CompanyName { get; set; } - [StringLength(20, ErrorMessage = "전화번호는 최대 20자까지 입력 가능합니다.")] + [StringLength(ValidationRules.PhoneMaxLength, ErrorMessage = "전화번호는 최대 20자까지 입력 가능합니다.")] public string? Phone { get; set; } [EmailAddress(ErrorMessage = "올바른 이메일 형식이 아닙니다.")] public string? Email { get; set; } - [StringLength(50, ErrorMessage = "서비스 유형은 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "서비스 유형은 최대 50자까지 입력 가능합니다.")] public string? ServiceType { get; set; } - [StringLength(50, ErrorMessage = "세금 유형은 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "세금 유형은 최대 50자까지 입력 가능합니다.")] public string? TaxType { get; set; } [Required(ErrorMessage = "상태를 선택하세요.")] public string Status { get; set; } = "active"; - [StringLength(50, ErrorMessage = "유입 경로는 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "유입 경로는 최대 50자까지 입력 가능합니다.")] public string? Source { get; set; } - [StringLength(1000, ErrorMessage = "메모는 최대 1000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MemoMaxLength, ErrorMessage = "메모는 최대 1000자까지 입력 가능합니다.")] public string? Memo { get; set; } } @@ -136,11 +137,11 @@ public sealed class ContractFormModel public int? ClientId { get; set; } [Required(ErrorMessage = "계약번호를 입력하세요.")] - [StringLength(50, ErrorMessage = "계약번호는 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ContractNumberMaxLength, ErrorMessage = "계약번호는 최대 50자까지 입력 가능합니다.")] public string ContractNumber { get; set; } = ""; [Required(ErrorMessage = "서비스 유형을 선택하세요.")] - [StringLength(50, ErrorMessage = "서비스 유형은 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "서비스 유형은 최대 50자까지 입력 가능합니다.")] public string ServiceType { get; set; } = ""; [Required(ErrorMessage = "계약 시작일을 입력하세요.")] @@ -156,7 +157,7 @@ public sealed class TaxFilingScheduleFormModel public int? ClientId { get; set; } [Required(ErrorMessage = "신고 유형을 선택하세요.")] - [StringLength(50, ErrorMessage = "신고 유형은 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "신고 유형은 최대 50자까지 입력 가능합니다.")] public string FilingType { get; set; } = ""; [Required(ErrorMessage = "마감일을 입력하세요.")] @@ -172,23 +173,23 @@ public sealed class TaxProfileFormModel public int? ClientId { get; set; } [Required(ErrorMessage = "사업 유형을 선택하세요.")] - [StringLength(50, ErrorMessage = "사업 유형은 최대 50자까지 입력 가능합니다.")] + [StringLength(ValidationRules.ServiceTypeMaxLength, ErrorMessage = "사업 유형은 최대 50자까지 입력 가능합니다.")] public string BusinessType { get; set; } = ""; [Required(ErrorMessage = "위험도를 선택하세요.")] - [StringLength(20, ErrorMessage = "위험도는 최대 20자까지 입력 가능합니다.")] + [StringLength(ValidationRules.RiskLevelMaxLength, ErrorMessage = "위험도는 최대 20자까지 입력 가능합니다.")] public string TaxRiskLevel { get; set; } = "normal"; public DateTime? NextFilingDueDate { get; set; } - [StringLength(1000, ErrorMessage = "특수 사항은 최대 1000자까지 입력 가능합니다.")] + [StringLength(ValidationRules.MemoMaxLength, ErrorMessage = "특수 사항은 최대 1000자까지 입력 가능합니다.")] public string? SpecialNotes { get; set; } } public sealed class SiteSettingsFormModel { [Required(ErrorMessage = "전화번호를 입력하세요.")] - [StringLength(20, ErrorMessage = "전화번호는 최대 20자까지 입력 가능합니다.")] + [StringLength(ValidationRules.PhoneMaxLength, ErrorMessage = "전화번호는 최대 20자까지 입력 가능합니다.")] public string Phone { get; set; } = ""; [Required(ErrorMessage = "이메일을 입력하세요.")]