From 06a90b4fd64617667eea031ce4012d167610e7d1 Mon Sep 17 00:00:00 2001 From: "jihoon87.lee" Date: Wed, 4 Feb 2026 09:34:41 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Zod=20=EC=8A=A4=ED=82=A4=EB=A7=88=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20=EC=9D=B8=EC=A6=9D=20=ED=8F=BC=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - auth-schema.ts 생성 - signupSchema, loginSchema, resetPasswordSchema, forgotPasswordSchema 정의 - 타입 안전한 폼 데이터 타입 자동 추론 --- features/auth/schemas/auth-schema.ts | 94 ++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 features/auth/schemas/auth-schema.ts diff --git a/features/auth/schemas/auth-schema.ts b/features/auth/schemas/auth-schema.ts new file mode 100644 index 0000000..00f1842 --- /dev/null +++ b/features/auth/schemas/auth-schema.ts @@ -0,0 +1,94 @@ +import { z } from "zod"; +import { PASSWORD_RULES } from "@/features/auth/constants"; + +/** + * [비밀번호 검증 스키마] + * + * 비밀번호 강도 요구사항: + * - 최소 8자 이상 + * - 대문자 1개 이상 + * - 소문자 1개 이상 + * - 숫자 1개 이상 + * - 특수문자 1개 이상 + */ +const passwordSchema = z + .string() + .min(PASSWORD_RULES.MIN_LENGTH, { + message: `비밀번호는 최소 ${PASSWORD_RULES.MIN_LENGTH}자 이상이어야 합니다.`, + }) + .regex(/[A-Z]/, { + message: "비밀번호에 대문자가 최소 1개 이상 포함되어야 합니다.", + }) + .regex(/[a-z]/, { + message: "비밀번호에 소문자가 최소 1개 이상 포함되어야 합니다.", + }) + .regex(/[0-9]/, { + message: "비밀번호에 숫자가 최소 1개 이상 포함되어야 합니다.", + }) + .regex(/[!@#$%^&*(),.?":{}|<>]/, { + message: "비밀번호에 특수문자가 최소 1개 이상 포함되어야 합니다.", + }); + +/** + * [회원가입 폼 스키마] + * + * 회원가입 시 필요한 필드 검증 + */ +export const signupSchema = z + .object({ + email: z + .string() + .min(1, { message: "이메일을 입력해주세요." }) + .email({ message: "올바른 이메일 형식이 아닙니다." }), + password: passwordSchema, + confirmPassword: z + .string() + .min(1, { message: "비밀번호 확인을 입력해주세요." }), + }) + .refine((data) => data.password === data.confirmPassword, { + message: "비밀번호가 일치하지 않습니다.", + path: ["confirmPassword"], + }); + +/** + * [비밀번호 재설정 폼 스키마] + */ +export const resetPasswordSchema = z + .object({ + password: passwordSchema, + confirmPassword: z + .string() + .min(1, { message: "비밀번호 확인을 입력해주세요." }), + }) + .refine((data) => data.password === data.confirmPassword, { + message: "비밀번호가 일치하지 않습니다.", + path: ["confirmPassword"], + }); + +/** + * [로그인 폼 스키마] + */ +export const loginSchema = z.object({ + email: z + .string() + .min(1, { message: "이메일을 입력해주세요." }) + .email({ message: "올바른 이메일 형식이 아닙니다." }), + password: z.string().min(1, { message: "비밀번호를 입력해주세요." }), + rememberMe: z.boolean().optional(), +}); + +/** + * [비밀번호 찾기 폼 스키마] + */ +export const forgotPasswordSchema = z.object({ + email: z + .string() + .min(1, { message: "이메일을 입력해주세요." }) + .email({ message: "올바른 이메일 형식이 아닙니다." }), +}); + +// TypeScript 타입 추론 +export type SignupFormData = z.infer; +export type ResetPasswordFormData = z.infer; +export type LoginFormData = z.infer; +export type ForgotPasswordFormData = z.infer;