import { z } from "zod"; import type { PageableList, PageableParams } from "@/shared/model"; export const USER_STATE_CODE = { 대기: "00", 정상: "01", 정지: "07", 탈퇴: "08", 삭제: "09", } as const; export type UserStateCode = (typeof USER_STATE_CODE)[keyof typeof USER_STATE_CODE]; // 사용자 검색 파라미터 export interface UserSearchParams extends PageableParams { keywordType?: string; keyword?: string; userStateCode?: string; aprvYn?: string; grpId?: string; frDateYmd?: string; toDateYmd?: string; userName?: string; } // 사용자 목록 응답 인터페이스 export interface UserListResponse { userId: string; userName: string; email: string; roleId: string; roleName: string; userStateCode: UserStateCode; userStateCodeName: string; lastLoginDate: string; loginFailCount: number; userUnqId: string; mphn: string; telno: string; aprvYn: string; regDt: string; laeSeCd: string; laeSeNm: string; ogdpSeCd: string; ogdpSeNm: string; instSeCd: string; instSeNm: string; aprvYmd: string; } // 사용자 상세 응답 인터페이스 export interface UserDetailResponse { regDt: string; mdfcnDt: string; rgtr: string; mdfr: string; userUnqId: string; userId: string; userName: string; email: string; encryptedPassword: string; refreshToken: string; userStateCode: UserStateCode; lastLoginDate: string; loginFailCount: number; pswdHnt: string; pswdAns: string; mphn: string; telno: string; zip: string; addr: string; daddr: string; laeSeCd: string; ogdpSeCd: string; aprvYn: string; autzrId: string; expryYmd: string; lastPswdChgDt: string; googleId: string; kakaoId: string; naverId: string; isSocialUser: boolean; hasPassword: boolean; twoFactorEnabled: boolean; adminRoleYn: string; instSeCd: string; aprvYmd: string; enoCd: string; dtlInstCd: string; laeSeNm: string; ogdpSeNm: string; instSeNm: string; userStateNm: string; pswdHntNm: string; ecoNm: string; dtlInstNm: string; } // 사용자 상태 통계 응답 인터페이스 export interface UserSttsStatsResponse { sttsCd: string; sttsNm: string; cnt: number; } // 관리자 목록 응답 인터페이스 export interface AdminUserListResponse { userUnqId: string; userId: string; userName: string; groupId: string; groupNm: string; userStateCode: string; userStateCodeName: string; laeSeCd: string; laeSeNm: string; ogdpSeCd: string; ogdpSeNm: string; instSeCd: string; instSeNm: string; dtlInstCd: string; dtlInstNm: string; mdfr: string; mdfrNm: string; mdfcnDt: string; } // 사용자 수정 요청 스키마 export const userUpdateSchema = z.object({ userId: z.string().optional(), userName: z.string(), email: z.string().email().optional(), password: z .string() .regex( /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/, "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.", ) .optional(), roleId: z.string().optional(), userStateCode: z.string(), pswdHnt: z.string().max(10), pswdAns: z.string().max(100).optional(), mphn: z.string().max(11).optional(), telno: z.string().max(11).optional(), zip: z.string().max(5).optional(), addr: z.string().max(200).optional(), daddr: z.string().max(200).optional(), laeSeCd: z.string().max(10), ogdpSeCd: z.string().max(10), aprvYn: z.string(), autzrId: z.string().uuid().optional(), expryYmd: z.string().max(8), instSeCd: z.string().optional(), dtlInstCd: z.string().optional(), aprvYmd: z.string().max(8).optional(), enoCd: z.string().optional(), }); // 사용자 비밀번호 변경 스키마 export const userPasswordUpdateSchema = z .object({ password: z.string().optional(), provider: z.string().optional(), token: z.string().optional(), newPassword: z .string() .regex( /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/, "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.", ), newPasswordConfirm: z.string(), }) .refine((data) => data.newPassword === data.newPasswordConfirm, { message: "비밀번호가 일치하지 않습니다.", path: ["newPasswordConfirm"], }); // 사용자 비밀번호 찾기 변경 스키마 export const userFindPasswordUpdateSchema = z.object({ tokenValue: z.string(), password: z .string() .regex( /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/, "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.", ), }); // 사용자 비밀번호 확인 스키마 export const userPasswordMatchSchema = z.object({ password: z .string() .regex( /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/, "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.", ), }); // 사용자 회원정보 변경 스키마 export const userUpdateInfoSchema = z.object({ password: z .string() .regex( /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/, "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.", ) .optional(), provider: z.string().optional(), token: z.string().optional(), userName: z.string(), email: z.string().email().optional(), }); // 사용자 저장 스키마 export const userSaveSchema = z.object({ userId: z.string(), userName: z.string(), email: z.string().email().optional(), password: z .string() .regex( /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,20}$/, "비밀번호는 8~20자, 영문/숫자/특수기호를 모두 포함해야 합니다.", ), pswdHnt: z.string().max(10), pswdAns: z.string().max(100).optional(), mphn: z.string().max(11).optional(), telno: z.string().max(11).optional(), zip: z.string().max(5).optional(), addr: z.string().max(200).optional(), daddr: z.string().max(200).optional(), laeSeCd: z.string().max(10), ogdpSeCd: z.string().max(10), expryYmd: z.string().max(8), instSeCd: z.string().optional(), dtlInstCd: z.string().optional(), enoCd: z.string().optional(), }); // 사용자 비밀번호 찾기 저장 스키마 export const userFindPasswordSaveSchema = z.object({ userName: z.string(), emailAddr: z.string().email(), mainUrl: z.string(), changePasswordUrl: z.string(), }); // 사용자 인증 요청 스키마 export const userVerifySchema = z.object({ password: z .string() .regex(/((?=.*[0-9])(?=.*[a-zA-Z])(?=.*\W)(?=\S+$).{8,20})|()/) .optional(), provider: z.string().optional(), token: z.string().optional(), }); // 사용자 이메일 요청 스키마 export const userEmailSchema = z.object({ userId: z.string().optional(), email: z.string().email(), }); // 사용자 ID 요청 스키마 export const userIdSchema = z.object({ userId: z.string(), }); // Zod 스키마 타입 정의 export type UserUpdateData = z.infer; export type UserPasswordUpdateData = z.infer; export type UserFindPasswordUpdateData = z.infer< typeof userFindPasswordUpdateSchema >; export type UserPasswordMatchData = z.infer; export type UserUpdateInfoData = z.infer; export type UserSaveData = z.infer; export type UserFindPasswordSaveData = z.infer< typeof userFindPasswordSaveSchema >; export type UserVerifyData = z.infer; export type UserEmailData = z.infer; export type UserIdData = z.infer; // 페이지네이션 타입 정의 export type UserList = PageableList; export type UserSttsStatsList = UserSttsStatsResponse[]; export type AdminUserList = PageableList; // 사용자 서비스 인터페이스 export interface UserService { // 사용자 목록 조회 findPageUser: (params: UserSearchParams) => Promise; // 사용자 단건 조회 findByUserUnqId: (userUnqId: string) => Promise; // 로그인한 사용자 정보 조회 findByUserUnqIdByLogin: () => Promise; // 사용자 회원상태 통계 조회 selectUserSttsStats: () => Promise; // 사용자 저장 saveUser: (data: UserSaveData) => Promise; // 사용자 수정 updateUser: (userUnqId: string, data: UserUpdateData) => Promise; // 사용자 삭제 deleteUser: (userUnqId: string) => Promise; // 사용자 계정잠금 처리 lockUser: (userUnqId: string) => Promise; // 사용자 계정잠금 해제처리 unlockUser: (userUnqId: string) => Promise; // 리프레시 토큰 정보 재발급 refreshToken: () => Promise; // 사용자 비밀번호 변경 updatePassword: (data: UserPasswordUpdateData) => Promise; // 사용자 비밀번호 초기화(관리자용) initializePassword: ( userUnqId: string, data: UserPasswordUpdateData, ) => Promise; // 사용자 비밀번호 찾기 변경 changePassword: (data: UserFindPasswordUpdateData) => Promise; // 사용자 비밀번호 확인 matchPassword: (data: UserPasswordMatchData) => Promise; // 사용자 비밀번호 찾기 findPasswordUser: (data: UserFindPasswordSaveData) => Promise; // 사용자 비밀번호 찾기 유효성 확인 validPassword: (token: string) => Promise; // 사용자 회원정보 변경 updateInfo: (userUnqId: string, data: UserUpdateInfoData) => Promise; // 사용자 승인처리 applyUser: (userUnqId: string) => Promise; // 사용자 회원탈퇴 leaveUser: (data: UserVerifyData) => Promise; // 사용자 이메일 중복 체크 existsEmail: (data: UserEmailData) => Promise; // 사용자 아이디 중복 체크 existsUserId: (data: UserIdData) => Promise; // 관리자 목록 조회 findPageAdminUser: (params: UserSearchParams) => Promise; }