2348800e68
Build & Deploy to K8s / build-and-deploy (push) Successful in 9m22s
카테고리/캐스케이딩 시스템 (B/C/D) 전부 폐기:
- BE: mapper/Service/Controller 9세트 삭제 (cascading*, categoryTree, tableCategoryValue, categoryValueCascading, codeMerge)
- FE: 페이지 3 + API 8 + hooks 2 + 폐기 컴포넌트 6 삭제, 14곳 의존성 정리
- DB: 12 테이블 DROP, TABLE_TYPE_COLUMNS.CODE_CATEGORY → CODE_INFO rename
신설 commonCode 마스터-디테일:
- code_info: 1레벨 그룹 마스터
- code_detail: 2~∞ depth 재귀 트리 (parent_detail_id self-FK, depth 자동 계산)
- API: /api/common-codes/{info,detail}
- CodeCategoryFormModal/Panel → CodeInfoFormModal/Panel rename
- code_category 컬럼명 전부 code_info 로 치환 (mapper/Java/FE)
- 옛 commonCode API URL (/categories/...) → getCodeOptions 어댑터 + /detail?code_info=... 전환
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
87 lines
3.5 KiB
TypeScript
87 lines
3.5 KiB
TypeScript
import { z } from "zod";
|
|
|
|
/**
|
|
* 공통코드 (마스터-디테일) zod 스키마
|
|
*
|
|
* 마스터: code_info (그룹)
|
|
* 디테일: code_detail (트리 노드, depth 2 시작)
|
|
*
|
|
* 폼 필드명은 백엔드 컬럼명 (snake_case) 그대로 사용.
|
|
*/
|
|
|
|
/* ───────────────────────── code_info (마스터) ───────────────────────── */
|
|
|
|
export const codeInfoSchema = z.object({
|
|
code_info: z
|
|
.string()
|
|
.min(1, "그룹 코드는 필수입니다")
|
|
.max(50, "그룹 코드는 50자 이하여야 합니다")
|
|
.regex(/^[A-Z0-9_]+$/, "대문자, 숫자, 언더스코어(_)만 사용 가능합니다"),
|
|
code_name: z.string().min(1, "그룹명은 필수입니다").max(100, "그룹명은 100자 이하여야 합니다"),
|
|
code_name_eng: z
|
|
.string()
|
|
.max(100, "영문 그룹명은 100자 이하여야 합니다")
|
|
.optional()
|
|
.or(z.literal("")),
|
|
description: z.string().max(500, "설명은 500자 이하여야 합니다").optional().or(z.literal("")),
|
|
sort_order: z
|
|
.number()
|
|
.min(0, "정렬 순서는 0 이상이어야 합니다")
|
|
.max(9999, "정렬 순서는 9999 이하여야 합니다"),
|
|
});
|
|
|
|
export const createCodeInfoSchema = codeInfoSchema;
|
|
|
|
export const updateCodeInfoSchema = codeInfoSchema.omit({ code_info: true }).extend({
|
|
is_active: z.enum(["Y", "N"]),
|
|
});
|
|
|
|
export type CodeInfoFormData = z.infer<typeof codeInfoSchema>;
|
|
export type CreateCodeInfoData = z.infer<typeof createCodeInfoSchema>;
|
|
export type UpdateCodeInfoData = z.infer<typeof updateCodeInfoSchema>;
|
|
|
|
/* ───────────────────────── code_detail (디테일 트리 노드) ───────────────────────── */
|
|
|
|
export const codeDetailSchema = z.object({
|
|
code_info: z.string().min(1, "그룹은 필수입니다"),
|
|
parent_detail_id: z.number().int().positive().nullable().optional(),
|
|
code_value: z.string().min(1, "코드값은 필수입니다").max(50, "코드값은 50자 이하여야 합니다"),
|
|
code_name: z.string().min(1, "코드명은 필수입니다").max(100, "코드명은 100자 이하여야 합니다"),
|
|
code_name_eng: z
|
|
.string()
|
|
.max(100, "영문 코드명은 100자 이하여야 합니다")
|
|
.optional()
|
|
.or(z.literal("")),
|
|
description: z.string().max(500, "설명은 500자 이하여야 합니다").optional().or(z.literal("")),
|
|
sort_order: z
|
|
.number()
|
|
.min(0, "정렬 순서는 0 이상이어야 합니다")
|
|
.max(9999, "정렬 순서는 9999 이하여야 합니다")
|
|
.optional(),
|
|
});
|
|
|
|
export const createCodeDetailSchema = codeDetailSchema;
|
|
|
|
export const updateCodeDetailSchema = codeDetailSchema.extend({
|
|
is_active: z.enum(["Y", "N"]),
|
|
});
|
|
|
|
export type CodeDetailFormData = z.infer<typeof codeDetailSchema>;
|
|
export type CreateCodeDetailData = z.infer<typeof createCodeDetailSchema>;
|
|
export type UpdateCodeDetailData = z.infer<typeof updateCodeDetailSchema>;
|
|
|
|
/* ───────────────────────── 검색 필터 ───────────────────────── */
|
|
|
|
export const codeInfoFilterSchema = z.object({
|
|
search: z.string().optional(),
|
|
active: z.boolean().optional(),
|
|
});
|
|
|
|
export const codeDetailFilterSchema = z.object({
|
|
search: z.string().optional(),
|
|
active: z.boolean().optional(),
|
|
});
|
|
|
|
export type CodeInfoFilter = z.infer<typeof codeInfoFilterSchema>;
|
|
export type CodeDetailFilter = z.infer<typeof codeDetailFilterSchema>;
|