Files
invyone/frontend/types/table-management.ts
T
DDD1542 2348800e68
Build & Deploy to K8s / build-and-deploy (push) Successful in 9m22s
refactor(common-code): 마스터-디테일 재설계 — code_info(그룹) + code_detail(재귀 트리)
카테고리/캐스케이딩 시스템 (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>
2026-05-15 16:50:50 +09:00

510 lines
14 KiB
TypeScript

/**
* 🗄️ 테이블 타입관리 시스템 전용 타입 정의
*
* 데이터베이스 테이블 스키마, 컬럼 타입, 웹타입 매핑 등 테이블 관리에서만 사용하는 타입들
*/
import {
DynamicWebType,
CompanyCode,
ActiveStatus,
TimestampFields,
BaseApiResponse,
PaginatedResponse,
ConditionOperator,
} from "./v2-core";
// ===== 기본 테이블 정보 =====
/**
* 테이블 정보
*/
export interface TableInfo {
table_name: string;
display_name: string;
description: string;
column_count: number;
company_code?: CompanyCode;
is_active?: ActiveStatus;
created_date?: Date;
updated_date?: Date;
}
/**
* 통합된 컬럼 정보 (프론트엔드/백엔드 호환)
*/
export interface V2ColumnInfo {
// 기본 정보
table_name: string;
column_name: string;
display_name: string;
// 데이터 타입
data_type: string; // DB 데이터 타입 (varchar, integer, timestamp 등)
db_type: string; // DB 내부 타입
web_type: DynamicWebType; // 웹 입력 타입 (text, number, date 등)
// 입력 설정
input_type?: "direct" | "auto" | string; // 입력 타입 (direct/auto) + DB input_type 필드 (entity, text, number 등)
detail_settings?: Record<string, unknown>; // JSON 파싱된 객체
description?: string;
// 제약 조건
is_nullable: boolean; // Y/N → boolean 변환
is_primary_key: boolean;
default_value?: string;
// 크기 제한
max_length?: number;
numeric_precision?: number;
numeric_scale?: number;
// 표시 옵션
is_visible?: boolean;
display_order?: number;
// 참조 관계
code_info?: string;
code_value?: string;
reference_table?: string;
reference_column?: string;
display_column?: string;
// 메타데이터
company_code?: CompanyCode;
created_date?: Date;
updated_date?: Date;
}
/**
* 백엔드 호환용 컬럼 타입 정보 (기존 ColumnTypeInfo)
*/
export interface ColumnTypeInfo {
table_name?: string;
column_name: string;
display_name: string;
data_type: string;
db_type: string;
web_type: string; // string 타입 (백엔드 호환)
input_type?: "direct" | "auto";
detail_settings: string; // JSON 문자열
description: string; // 필수 필드
is_nullable: string; // Y/N 문자열
is_primary_key: boolean;
default_value?: string;
max_length?: number;
numeric_precision?: number;
numeric_scale?: number;
code_info?: string;
code_value?: string;
reference_table?: string;
reference_column?: string;
display_column?: string;
display_order?: number;
is_visible?: boolean;
}
/**
* 컬럼 설정 (업데이트용)
*/
export interface ColumnSettings {
column_name?: string; // 컬럼명 (업데이트 시 필요)
column_label: string; // 컬럼 표시명
web_type: string; // 웹 입력 타입
detail_settings: string; // 상세 설정 (JSON 문자열)
code_info: string; // 코드 카테고리
code_value: string; // 코드 값
reference_table: string; // 참조 테이블
reference_column: string; // 참조 컬럼
display_column?: string; // 표시할 컬럼명
display_order?: number; // 표시 순서
is_visible?: boolean; // 표시 여부
}
// ===== 웹타입 표준 정의 =====
/**
* 웹타입 표준 정보 (DB의 web_type_standards 테이블)
*/
export interface WebTypeStandard extends TimestampFields {
web_type: string;
type_name: string;
type_name_eng?: string;
description?: string;
category: string;
default_config?: unknown; // JSON
validation_rules?: unknown; // JSON
default_style?: unknown; // JSON
input_properties?: unknown; // JSON
sort_order?: number;
is_active: ActiveStatus;
component_name?: string;
config_panel?: string;
}
/**
* 프론트엔드용 웹타입 정의 (WebTypeStandard 변환)
*/
export interface WebTypeDefinition {
web_type: string;
type_name: string;
type_name_eng?: string;
description?: string;
category: string;
default_config: Record<string, unknown>;
validation_rules?: Record<string, unknown>;
default_style?: Record<string, unknown>;
input_properties?: Record<string, unknown>;
component_name?: string;
config_panel?: string;
sort_order?: number;
is_active: boolean;
}
// ===== 테이블 라벨 관리 =====
/**
* 테이블 라벨
*/
export interface TableLabels extends TimestampFields {
table_name: string;
table_label?: string;
description?: string;
company_code?: CompanyCode;
}
/**
* 컬럼 라벨
*/
export interface ColumnLabels extends TimestampFields {
id?: number;
table_name: string;
column_name: string;
column_label?: string;
web_type?: string;
detail_settings?: string;
description?: string;
display_order?: number;
is_visible?: boolean;
code_info?: string;
code_value?: string;
reference_table?: string;
reference_column?: string;
display_column?: string;
company_code?: CompanyCode;
}
// ===== 엔티티 조인 관리 =====
/**
* 엔티티 조인 설정
*/
export interface EntityJoinConfig {
source_table: string; // 원본 테이블 (예: companies)
source_column: string; // 원본 컬럼 (예: writer)
reference_table: string; // 참조 테이블 (예: user_info)
reference_column: string; // 조인 키 (예: user_id)
display_column: string; // 표시할 값 (예: user_name)
alias_column: string; // 결과 컬럼명 (예: writer_name)
company_code?: CompanyCode;
}
/**
* 엔티티 조인 응답
*/
export interface EntityJoinResponse {
data: Record<string, unknown>[];
total: number;
page: number;
size: number;
total_pages: number;
entity_join_info?: {
join_configs: EntityJoinConfig[];
strategy: "full_join" | "cache_lookup" | "hybrid";
performance: {
query_time: number;
cache_hit_rate?: number;
hybrid_breakdown?: {
db_joins: number;
cache_joins: number;
};
};
};
}
/**
* 배치 조회 요청
*/
export interface BatchLookupRequest {
table: string;
key: string;
display_column: string;
company_code?: CompanyCode;
}
/**
* 배치 조회 응답
*/
export interface BatchLookupResponse {
key: string;
value: unknown;
}
// ===== 테이블 관계 관리 =====
/**
* 테이블 관계 정의
*/
export interface TableRelationship extends TimestampFields {
relationship_id?: number;
relationship_name?: string;
from_table_name?: string;
from_column_name?: string;
to_table_name?: string;
to_column_name?: string;
relationship_type?: string;
connection_type?: string;
company_code?: CompanyCode;
settings?: unknown; // JSON
is_active?: ActiveStatus;
diagram_id?: number;
}
/**
* 데이터 관계 브릿지
*/
export interface DataRelationshipBridge extends TimestampFields {
bridge_id?: number;
relationship_id?: number;
from_table_name: string;
from_column_name: string;
to_table_name: string;
to_column_name: string;
connection_type: string;
company_code: CompanyCode;
is_active?: ActiveStatus;
bridge_data?: unknown; // JSON
from_key_value?: string;
from_record_id?: string;
to_key_value?: string;
to_record_id?: string;
}
// ===== 컬럼 웹타입 설정 =====
/**
* 컬럼 웹타입 설정
*/
export interface ColumnWebTypeSetting {
table_name: string;
column_name: string;
web_type: DynamicWebType;
detail_settings?: Record<string, unknown>;
code_info?: string;
reference_table?: string;
reference_column?: string;
display_column?: string;
company_code?: CompanyCode;
}
// ===== API 응답 타입들 =====
/**
* 테이블 목록 응답
*/
export interface TableListResponse extends BaseApiResponse<TableInfo[]> {}
/**
* 컬럼 목록 응답
*/
export interface ColumnListResponse extends BaseApiResponse<V2ColumnInfo[]> {}
/**
* 컬럼 타입 정보 응답 (백엔드 호환)
*/
export interface ColumnTypeInfoResponse extends BaseApiResponse<ColumnTypeInfo[]> {}
/**
* 컬럼 설정 응답
*/
export interface ColumnSettingsResponse extends BaseApiResponse<void> {}
/**
* 웹타입 표준 목록 응답
*/
export interface WebTypeStandardListResponse extends BaseApiResponse<WebTypeStandard[]> {}
/**
* 웹타입 정의 목록 응답
*/
export interface WebTypeDefinitionListResponse extends BaseApiResponse<WebTypeDefinition[]> {}
/**
* 테이블 데이터 조회 응답
*/
export interface TableDataResponse extends PaginatedResponse<Record<string, unknown>> {}
// ===== 웹타입 옵션 상수 =====
/**
* 웹타입 옵션 (기존 호환성 유지)
*/
export const WEB_TYPE_OPTIONS = [
{ value: "text", label: "text", description: "일반 텍스트 입력" },
{ value: "number", label: "number", description: "숫자 입력" },
{ value: "decimal", label: "decimal", description: "소수 입력" },
{ value: "date", label: "date", description: "날짜 선택기" },
{ value: "datetime", label: "datetime", description: "날짜시간 선택기" },
{ value: "code", label: "code", description: "코드 선택 (공통코드 지정)" },
{ value: "entity", label: "entity", description: "엔티티 참조 (참조테이블 지정)" },
{ value: "textarea", label: "textarea", description: "여러 줄 텍스트" },
{ value: "select", label: "select", description: "드롭다운 선택" },
{ value: "dropdown", label: "dropdown", description: "드롭다운 선택" },
{ value: "checkbox", label: "checkbox", description: "체크박스" },
{ value: "boolean", label: "boolean", description: "참/거짓" },
{ value: "radio", label: "radio", description: "라디오 버튼" },
{ value: "file", label: "file", description: "파일 업로드" },
{ value: "email", label: "email", description: "이메일 입력" },
{ value: "tel", label: "tel", description: "전화번호 입력" },
{ value: "url", label: "url", description: "URL 입력" },
{ value: "checkbox-group", label: "checkbox-group", description: "체크박스 그룹" },
{ value: "radio-horizontal", label: "radio-horizontal", description: "가로 라디오" },
{ value: "radio-vertical", label: "radio-vertical", description: "세로 라디오" },
] as const;
/**
* 웹타입 (기존 호환성)
*/
export type WebType = (typeof WEB_TYPE_OPTIONS)[number]["value"];
// ===== 변환 유틸리티 함수들 =====
/**
* WebTypeStandard를 WebTypeDefinition으로 변환
*/
export const mapWebTypeStandardToDefinition = (standard: WebTypeStandard): WebTypeDefinition => ({
web_type: standard.web_type,
type_name: standard.type_name,
type_name_eng: standard.type_name_eng || undefined,
description: standard.description || undefined,
category: standard.category || "input",
default_config: (standard.default_config as Record<string, unknown>) || {},
validation_rules: (standard.validation_rules as Record<string, unknown>) || undefined,
default_style: (standard.default_style as Record<string, unknown>) || undefined,
input_properties: (standard.input_properties as Record<string, unknown>) || undefined,
component_name: standard.component_name || undefined,
config_panel: standard.config_panel || undefined,
sort_order: standard.sort_order || 0,
is_active: standard.is_active === "Y",
});
/**
* ColumnTypeInfo를 V2ColumnInfo로 변환
*/
export const mapColumnTypeInfoToV2 = (columnInfo: ColumnTypeInfo): V2ColumnInfo => ({
table_name: columnInfo.table_name || "",
column_name: columnInfo.column_name,
display_name: columnInfo.display_name,
data_type: columnInfo.data_type,
db_type: columnInfo.db_type,
web_type: columnInfo.web_type,
input_type: columnInfo.input_type || "direct",
detail_settings: columnInfo.detail_settings ? JSON.parse(columnInfo.detail_settings) : undefined,
description: columnInfo.description,
is_nullable: columnInfo.is_nullable === "Y",
is_primary_key: columnInfo.is_primary_key,
default_value: columnInfo.default_value,
max_length: columnInfo.max_length,
numeric_precision: columnInfo.numeric_precision,
numeric_scale: columnInfo.numeric_scale,
is_visible: columnInfo.is_visible,
display_order: columnInfo.display_order,
code_info: columnInfo.code_info,
code_value: columnInfo.code_value,
reference_table: columnInfo.reference_table,
reference_column: columnInfo.reference_column,
display_column: columnInfo.display_column,
});
/**
* V2ColumnInfo를 ColumnTypeInfo로 변환
*/
export const mapV2ToColumnTypeInfo = (v2: V2ColumnInfo): ColumnTypeInfo => ({
table_name: v2.table_name,
column_name: v2.column_name,
display_name: v2.display_name,
data_type: v2.data_type,
db_type: v2.db_type,
web_type: v2.web_type,
input_type: v2.input_type as "direct" | "auto" | undefined,
detail_settings: v2.detail_settings ? JSON.stringify(v2.detail_settings) : "{}",
description: v2.description || "",
is_nullable: v2.is_nullable ? "Y" : "N",
is_primary_key: v2.is_primary_key,
default_value: v2.default_value,
max_length: v2.max_length,
numeric_precision: v2.numeric_precision,
numeric_scale: v2.numeric_scale,
is_visible: v2.is_visible,
display_order: v2.display_order,
code_info: v2.code_info,
code_value: v2.code_value,
reference_table: v2.reference_table,
reference_column: v2.reference_column,
display_column: v2.display_column,
});
// ===== 타입 가드 함수들 =====
/**
* 웹타입이 참조 타입인지 확인
*/
export const isReferenceWebType = (webType: string): boolean => {
return ["code", "entity"].includes(webType);
};
/**
* 웹타입이 숫자 타입인지 확인
*/
export const isNumericWebType = (webType: string): boolean => {
return ["number", "decimal"].includes(webType);
};
/**
* 웹타입이 날짜 타입인지 확인
*/
export const isDateWebType = (webType: string): boolean => {
return ["date", "datetime"].includes(webType);
};
/**
* 웹타입이 선택 타입인지 확인
*/
export const isSelectWebType = (webType: string): boolean => {
return ["select", "dropdown", "radio", "checkbox", "boolean"].includes(webType);
};
/**
* 컬럼이 필수 필드인지 확인
*/
export const isRequiredColumn = (column: V2ColumnInfo): boolean => {
return !column.is_nullable || column.is_primary_key;
};
/**
* 컬럼이 시스템 컬럼인지 확인
*/
export const isSystemColumn = (columnName: string): boolean => {
const systemColumns = [
"created_date",
"updated_date",
"created_by",
"updated_by",
"is_active",
"company_code",
"version",
"id",
];
return systemColumns.includes(columnName.toLowerCase());
};