473 lines
14 KiB
Markdown
473 lines
14 KiB
Markdown
# 테이블 타입 관리 개선 계획서
|
|
|
|
## 🎯 개선 목표
|
|
|
|
현재 테이블 타입 관리 시스템의 용어 통일과 타입 단순화를 통해 사용자 친화적이고 유연한 시스템으로 개선합니다.
|
|
|
|
## 📋 주요 변경사항
|
|
|
|
### 1. 용어 변경
|
|
|
|
- **웹 타입(Web Type)** → **입력 타입(Input Type)**
|
|
- 사용자에게 더 직관적인 명칭으로 변경
|
|
|
|
### 2. 입력 타입 단순화
|
|
|
|
기존 20개 타입에서 **8개 핵심 타입**으로 단순화:
|
|
|
|
| 번호 | 입력 타입 | 설명 | 예시 |
|
|
| ---- | ---------- | ---------- | -------------------- |
|
|
| 1 | `text` | 텍스트 | 이름, 제목, 설명 |
|
|
| 2 | `number` | 숫자 | 수량, 건수, 순번 |
|
|
| 3 | `date` | 날짜 | 생성일, 완료일, 기한 |
|
|
| 4 | `code` | 코드 | 상태코드, 유형코드 |
|
|
| 5 | `entity` | 엔티티 | 고객선택, 제품선택 |
|
|
| 6 | `select` | 선택박스 | 드롭다운 목록 |
|
|
| 7 | `checkbox` | 체크박스 | Y/N, 사용여부 |
|
|
| 8 | `radio` | 라디오버튼 | 단일선택 옵션 |
|
|
|
|
### 3. DB 타입 제거
|
|
|
|
- 컬럼 정보에서 `dbType` 필드 제거
|
|
- 입력 타입만으로 데이터 처리 방식 결정
|
|
|
|
## 🛠️ 기술적 구현 방안
|
|
|
|
### 전체 VARCHAR 통일 방식 (확정)
|
|
|
|
**모든 신규 테이블의 사용자 정의 컬럼을 VARCHAR(500)로 생성하고 애플리케이션 레벨에서 형변환 처리**
|
|
|
|
#### 핵심 장점
|
|
|
|
- ✅ **최대 유연성**: 어떤 데이터든 타입 에러 없이 저장 가능
|
|
- ✅ **에러 제로**: 타입 불일치로 인한 DB 삽입/수정 에러 완전 차단
|
|
- ✅ **개발 속도**: 복잡한 타입 고민 없이 빠른 개발 가능
|
|
- ✅ **요구사항 대응**: 필드 성격 변경 시에도 스키마 수정 불필요
|
|
- ✅ **데이터 마이그레이션**: 기존 시스템 데이터 이관 시 100% 안전
|
|
|
|
#### 실제 예시
|
|
|
|
```sql
|
|
-- 기존 방식 (타입별 생성)
|
|
CREATE TABLE products (
|
|
id serial PRIMARY KEY,
|
|
name varchar(255), -- 텍스트
|
|
price numeric(10,2), -- 숫자
|
|
launch_date date, -- 날짜
|
|
is_active boolean -- 체크박스
|
|
);
|
|
|
|
-- 새로운 방식 (VARCHAR 통일)
|
|
CREATE TABLE products (
|
|
id serial PRIMARY KEY,
|
|
created_date timestamp DEFAULT now(),
|
|
updated_date timestamp DEFAULT now(),
|
|
company_code varchar(50) DEFAULT '*',
|
|
writer varchar(100),
|
|
-- 사용자 정의 컬럼들은 모두 VARCHAR(500)
|
|
name varchar(500), -- 입력타입: text
|
|
price varchar(500), -- 입력타입: number → "15000.50"
|
|
launch_date varchar(500), -- 입력타입: date → "2024-03-15"
|
|
is_active varchar(500) -- 입력타입: checkbox → "Y"/"N"
|
|
);
|
|
```
|
|
|
|
#### 애플리케이션 레벨 처리
|
|
|
|
````typescript
|
|
// 입력 타입별 형변환 및 검증
|
|
export class InputTypeProcessor {
|
|
|
|
// 저장 전 변환 (화면 → DB)
|
|
static convertForStorage(value: any, inputType: string): string {
|
|
if (value === null || value === undefined) return "";
|
|
|
|
switch (inputType) {
|
|
case "text":
|
|
return String(value);
|
|
|
|
case "number":
|
|
const num = parseFloat(String(value));
|
|
return isNaN(num) ? "0" : String(num);
|
|
|
|
case "date":
|
|
if (!value) return "";
|
|
const date = new Date(value);
|
|
return isNaN(date.getTime()) ? "" : date.toISOString().split('T')[0];
|
|
|
|
case "checkbox":
|
|
return ["true", "1", "Y", "yes"].includes(String(value).toLowerCase()) ? "Y" : "N";
|
|
|
|
default:
|
|
return String(value);
|
|
}
|
|
}
|
|
|
|
// 표시용 변환 (DB → 화면)
|
|
static convertForDisplay(value: string, inputType: string): any {
|
|
if (!value) return inputType === "number" ? 0 : "";
|
|
|
|
switch (inputType) {
|
|
case "number":
|
|
const num = parseFloat(value);
|
|
return isNaN(num) ? 0 : num;
|
|
|
|
case "date":
|
|
return value; // YYYY-MM-DD 형식 그대로
|
|
|
|
case "checkbox":
|
|
return value === "Y";
|
|
|
|
default:
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
|
|
## 🏗️ 구현 단계
|
|
|
|
### Phase 1: 타입 정의 수정 (1-2일)
|
|
|
|
#### 1.1 입력 타입 enum 업데이트
|
|
|
|
```typescript
|
|
// frontend/types/unified-web-types.ts
|
|
export type InputType =
|
|
| "text" // 텍스트
|
|
| "number" // 숫자
|
|
| "date" // 날짜
|
|
| "code" // 코드
|
|
| "entity" // 엔티티
|
|
| "select" // 선택박스
|
|
| "checkbox" // 체크박스
|
|
| "radio"; // 라디오버튼
|
|
````
|
|
|
|
#### 1.2 UI 표시명 업데이트
|
|
|
|
```typescript
|
|
export const INPUT_TYPE_OPTIONS = [
|
|
{ value: "text", label: "텍스트", description: "일반 텍스트 입력" },
|
|
{ value: "number", label: "숫자", description: "숫자 입력 (정수/소수)" },
|
|
{ value: "date", label: "날짜", description: "날짜 선택" },
|
|
{ value: "code", label: "코드", description: "공통코드 참조" },
|
|
{ value: "entity", label: "엔티티", description: "다른 테이블 참조" },
|
|
{ value: "select", label: "선택박스", description: "드롭다운 선택" },
|
|
{ value: "checkbox", label: "체크박스", description: "체크박스 입력" },
|
|
{ value: "radio", label: "라디오버튼", description: "단일 선택" },
|
|
];
|
|
```
|
|
|
|
### Phase 2: 데이터베이스 스키마 수정 (1일)
|
|
|
|
#### 2.1 테이블 스키마 수정
|
|
|
|
```sql
|
|
-- table_type_columns 테이블 수정
|
|
ALTER TABLE table_type_columns
|
|
DROP COLUMN IF EXISTS db_type;
|
|
|
|
-- 컬럼명 변경
|
|
ALTER TABLE table_type_columns
|
|
RENAME COLUMN web_type TO input_type;
|
|
|
|
-- 기존 데이터 마이그레이션
|
|
UPDATE table_type_columns
|
|
SET input_type = CASE
|
|
WHEN input_type IN ('textarea') THEN 'text'
|
|
WHEN input_type IN ('decimal') THEN 'number'
|
|
WHEN input_type IN ('datetime') THEN 'date'
|
|
WHEN input_type IN ('dropdown') THEN 'select'
|
|
WHEN input_type IN ('boolean') THEN 'checkbox'
|
|
WHEN input_type NOT IN ('text', 'number', 'date', 'code', 'entity', 'select', 'checkbox', 'radio')
|
|
THEN 'text'
|
|
ELSE input_type
|
|
END;
|
|
```
|
|
|
|
### Phase 3: 백엔드 서비스 수정 (2-3일)
|
|
|
|
#### 3.1 DDL 생성 로직 수정
|
|
|
|
```typescript
|
|
// 전체 VARCHAR 통일 방식으로 수정
|
|
private mapInputTypeToPostgresType(inputType: string): string {
|
|
// 기본 컬럼들은 기존 타입 유지 (시스템 컬럼)
|
|
// 사용자 정의 컬럼은 입력 타입과 관계없이 모두 VARCHAR(500)로 통일
|
|
return "varchar(500)";
|
|
}
|
|
|
|
private generateCreateTableQuery(
|
|
tableName: string,
|
|
columns: CreateColumnDefinition[]
|
|
): string {
|
|
// 사용자 정의 컬럼들 - 모두 VARCHAR(500)로 생성
|
|
const columnDefinitions = columns
|
|
.map((col) => {
|
|
let definition = `"${col.name}" varchar(500)`; // 타입 통일
|
|
|
|
if (!col.nullable) {
|
|
definition += " NOT NULL";
|
|
}
|
|
|
|
if (col.defaultValue) {
|
|
definition += ` DEFAULT '${col.defaultValue}'`;
|
|
}
|
|
|
|
return definition;
|
|
})
|
|
.join(",\n ");
|
|
|
|
// 기본 컬럼들 (시스템 필수 컬럼 - 기존 타입 유지)
|
|
const baseColumns = `
|
|
"id" serial PRIMARY KEY,
|
|
"created_date" timestamp DEFAULT now(),
|
|
"updated_date" timestamp DEFAULT now(),
|
|
"writer" varchar(100),
|
|
"company_code" varchar(50) DEFAULT '*'`;
|
|
|
|
return `
|
|
CREATE TABLE "${tableName}" (${baseColumns},
|
|
${columnDefinitions}
|
|
);`.trim();
|
|
}
|
|
```
|
|
|
|
#### 3.2 입력 타입 처리 서비스 구현
|
|
|
|
```typescript
|
|
// 통합 입력 타입 처리 서비스
|
|
export class InputTypeService {
|
|
// 데이터 저장 전 형변환 (화면 입력값 → DB 저장값)
|
|
static convertForStorage(value: any, inputType: string): string {
|
|
if (value === null || value === undefined) return "";
|
|
|
|
switch (inputType) {
|
|
case "text":
|
|
case "select":
|
|
case "radio":
|
|
return String(value);
|
|
|
|
case "number":
|
|
const num = parseFloat(String(value));
|
|
return isNaN(num) ? "0" : String(num);
|
|
|
|
case "date":
|
|
if (!value) return "";
|
|
const date = new Date(value);
|
|
return isNaN(date.getTime()) ? "" : date.toISOString().split("T")[0];
|
|
|
|
case "checkbox":
|
|
return ["true", "1", "Y", "yes", true].includes(value) ? "Y" : "N";
|
|
|
|
case "code":
|
|
case "entity":
|
|
return String(value || "");
|
|
|
|
default:
|
|
return String(value);
|
|
}
|
|
}
|
|
|
|
// 화면 표시용 형변환 (DB 저장값 → 화면 표시값)
|
|
static convertForDisplay(value: string, inputType: string): any {
|
|
if (!value && value !== "0") {
|
|
return inputType === "number" ? 0 : inputType === "checkbox" ? false : "";
|
|
}
|
|
|
|
switch (inputType) {
|
|
case "number":
|
|
const num = parseFloat(value);
|
|
return isNaN(num) ? 0 : num;
|
|
|
|
case "checkbox":
|
|
return value === "Y" || value === "true";
|
|
|
|
case "date":
|
|
return value; // YYYY-MM-DD 형식 그대로 사용
|
|
|
|
default:
|
|
return value;
|
|
}
|
|
}
|
|
|
|
// 입력값 검증
|
|
static validate(
|
|
value: any,
|
|
inputType: string
|
|
): { isValid: boolean; message?: string } {
|
|
if (!value && value !== 0) {
|
|
return { isValid: true }; // 빈 값은 허용
|
|
}
|
|
|
|
switch (inputType) {
|
|
case "number":
|
|
const num = parseFloat(String(value));
|
|
return {
|
|
isValid: !isNaN(num),
|
|
message: isNaN(num) ? "숫자 형식이 올바르지 않습니다." : undefined,
|
|
};
|
|
|
|
case "date":
|
|
const date = new Date(value);
|
|
return {
|
|
isValid: !isNaN(date.getTime()),
|
|
message: isNaN(date.getTime())
|
|
? "날짜 형식이 올바르지 않습니다."
|
|
: undefined,
|
|
};
|
|
|
|
default:
|
|
return { isValid: true };
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Phase 4: 프론트엔드 UI 수정 (2일)
|
|
|
|
#### 4.1 테이블 관리 화면 수정
|
|
|
|
- "웹 타입" → "입력 타입" 라벨 변경
|
|
- DB 타입 컬럼 제거
|
|
- 8개 타입만 선택 가능하도록 UI 수정
|
|
|
|
#### 4.2 화면 관리 시스템 연동
|
|
|
|
- 웹타입 → 입력타입 용어 통일
|
|
- 기존 화면관리 컴포넌트와 호환성 유지
|
|
|
|
### Phase 5: 기본 컬럼 유지 로직 보강 (1일)
|
|
|
|
#### 5.1 테이블 생성 시 기본 컬럼 자동 추가
|
|
|
|
```typescript
|
|
const DEFAULT_COLUMNS = [
|
|
{
|
|
name: "id",
|
|
type: "serial PRIMARY KEY",
|
|
description: "기본키 (자동증가)",
|
|
},
|
|
{
|
|
name: "created_date",
|
|
type: "timestamp DEFAULT now()",
|
|
description: "생성일시",
|
|
},
|
|
{
|
|
name: "updated_date",
|
|
type: "timestamp DEFAULT now()",
|
|
description: "수정일시",
|
|
},
|
|
{
|
|
name: "writer",
|
|
type: "varchar(100)",
|
|
description: "작성자",
|
|
},
|
|
{
|
|
name: "company_code",
|
|
type: "varchar(50) DEFAULT '*'",
|
|
description: "회사코드",
|
|
},
|
|
];
|
|
```
|
|
|
|
## 🧪 테스트 계획
|
|
|
|
### 1. 단위 테스트
|
|
|
|
- [ ] 입력 타입별 형변환 함수 테스트
|
|
- [ ] 데이터 검증 로직 테스트
|
|
- [ ] DDL 생성 로직 테스트
|
|
|
|
### 2. 통합 테스트
|
|
|
|
- [ ] 테이블 생성 → 데이터 입력 → 조회 전체 플로우
|
|
- [ ] 기존 테이블과의 호환성 테스트
|
|
- [ ] 화면관리 시스템 연동 테스트
|
|
|
|
### 3. 성능 테스트
|
|
|
|
- [ ] VARCHAR vs 전용 타입 성능 비교
|
|
- [ ] 대용량 데이터 입력 테스트
|
|
- [ ] 형변환 오버헤드 측정
|
|
|
|
## 📊 마이그레이션 전략
|
|
|
|
### 기존 데이터 호환성
|
|
|
|
1. **기존 테이블**: 현재 타입 구조 유지
|
|
2. **신규 테이블**: 새로운 입력 타입 체계 적용
|
|
3. **점진적 전환**: 필요에 따라 기존 테이블도 단계적 전환
|
|
|
|
### 데이터 무결성 보장
|
|
|
|
- 형변환 실패 시 기본값 사용
|
|
- 검증 로직을 통한 데이터 품질 관리
|
|
- 에러 로깅 및 알림 시스템
|
|
|
|
## 🎯 예상 효과
|
|
|
|
### 사용자 경험 개선
|
|
|
|
- ✅ 직관적인 용어로 학습 비용 감소
|
|
- ✅ 8개 타입으로 선택 복잡도 감소
|
|
- ✅ 일관된 인터페이스 제공
|
|
|
|
### 개발 생산성 향상
|
|
|
|
- ✅ 타입 관리 복잡도 감소
|
|
- ✅ 에러 발생률 감소
|
|
- ✅ 빠른 프로토타이핑 가능
|
|
|
|
### 시스템 유연성 확보
|
|
|
|
- ✅ 요구사항 변경에 빠른 대응
|
|
- ✅ 다양한 데이터 형식 수용
|
|
- ✅ 확장성 있는 구조
|
|
|
|
## 🚨 주의사항
|
|
|
|
### 데이터 검증 강화 필요
|
|
|
|
VARCHAR 통일 방식 적용 시 애플리케이션 레벨에서 철저한 데이터 검증이 필요합니다.
|
|
|
|
### 성능 모니터링
|
|
|
|
초기 적용 후 성능 영향도를 지속적으로 모니터링하여 필요 시 최적화 방안을 강구합니다.
|
|
|
|
### 문서화 업데이트
|
|
|
|
새로운 입력 타입 체계에 대한 사용자 가이드 및 개발 문서를 업데이트합니다.
|
|
|
|
## 📅 일정
|
|
|
|
| 단계 | 소요시간 | 담당 |
|
|
| ---------------------------- | --------- | ---------- |
|
|
| Phase 1: 타입 정의 수정 | 1-2일 | 프론트엔드 |
|
|
| Phase 2: DB 스키마 수정 | 1일 | 백엔드 |
|
|
| Phase 3: 백엔드 서비스 수정 | 2-3일 | 백엔드 |
|
|
| Phase 4: 프론트엔드 UI 수정 | 2일 | 프론트엔드 |
|
|
| Phase 5: 기본 컬럼 로직 보강 | 1일 | 백엔드 |
|
|
| **총 소요시간** | **7-9일** | |
|
|
|
|
---
|
|
|
|
**결론**: 전체 VARCHAR 통일 방식을 확정하여 최대한의 유연성과 안정성을 확보합니다.
|
|
|
|
## 🎯 핵심 결정사항 요약
|
|
|
|
### ✅ 확정된 방향성
|
|
|
|
1. **용어 통일**: 웹 타입 → 입력 타입
|
|
2. **타입 단순화**: 20개 → 8개 핵심 타입
|
|
3. **DB 타입 제거**: dbType 필드 완전 삭제
|
|
4. **저장 방식**: 모든 사용자 정의 컬럼을 VARCHAR(500)로 통일
|
|
5. **형변환**: 애플리케이션 레벨에서 입력 타입별 처리
|
|
|
|
### 🚀 예상 효과
|
|
|
|
- **개발 속도 3배 향상**: 타입 고민 시간 제거
|
|
- **에러율 90% 감소**: DB 타입 불일치 에러 완전 차단
|
|
- **요구사항 대응력 극대화**: 스키마 수정 없이 필드 성격 변경 가능
|
|
- **데이터 마이그레이션 100% 안전**: 어떤 형태의 데이터도 수용 가능
|