테이블 생성규칙
This commit is contained in:
parent
6476a83d86
commit
c32bd8a4bf
|
|
@ -0,0 +1,368 @@
|
||||||
|
# 테이블 타입 관리 SQL 작성 가이드
|
||||||
|
|
||||||
|
테이블 타입 관리에서 테이블 생성 시 적용되는 컬럼, 타입, 메타데이터 등록 로직을 기반으로 한 SQL 작성 가이드입니다.
|
||||||
|
|
||||||
|
## 핵심 원칙
|
||||||
|
|
||||||
|
1. **모든 비즈니스 컬럼은 `VARCHAR(500)`로 통일**: 날짜 타입 외 모든 컬럼은 `VARCHAR(500)`
|
||||||
|
2. **날짜/시간 컬럼만 `TIMESTAMP` 사용**: `created_date`, `updated_date` 등
|
||||||
|
3. **기본 컬럼 5개 자동 포함**: 모든 테이블에 id, created_date, updated_date, writer, company_code 필수
|
||||||
|
4. **3개 메타데이터 테이블 등록 필수**: `table_labels`, `column_labels`, `table_type_columns`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 테이블 생성 DDL 템플릿
|
||||||
|
|
||||||
|
### 기본 구조
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE "테이블명" (
|
||||||
|
-- 시스템 기본 컬럼 (자동 포함)
|
||||||
|
"id" varchar(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
||||||
|
"created_date" timestamp DEFAULT now(),
|
||||||
|
"updated_date" timestamp DEFAULT now(),
|
||||||
|
"writer" varchar(500) DEFAULT NULL,
|
||||||
|
"company_code" varchar(500),
|
||||||
|
|
||||||
|
-- 사용자 정의 컬럼 (모두 VARCHAR(500))
|
||||||
|
"컬럼1" varchar(500),
|
||||||
|
"컬럼2" varchar(500),
|
||||||
|
"컬럼3" varchar(500)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 예시: 고객 테이블 생성
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE "customer_info" (
|
||||||
|
"id" varchar(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
||||||
|
"created_date" timestamp DEFAULT now(),
|
||||||
|
"updated_date" timestamp DEFAULT now(),
|
||||||
|
"writer" varchar(500) DEFAULT NULL,
|
||||||
|
"company_code" varchar(500),
|
||||||
|
|
||||||
|
"customer_name" varchar(500),
|
||||||
|
"customer_code" varchar(500),
|
||||||
|
"phone" varchar(500),
|
||||||
|
"email" varchar(500),
|
||||||
|
"address" varchar(500),
|
||||||
|
"status" varchar(500),
|
||||||
|
"registration_date" varchar(500)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 메타데이터 테이블 등록
|
||||||
|
|
||||||
|
테이블 생성 시 반드시 아래 3개 테이블에 메타데이터를 등록해야 합니다.
|
||||||
|
|
||||||
|
### 2.1 table_labels (테이블 메타데이터)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date)
|
||||||
|
VALUES ('테이블명', '테이블 라벨', '테이블 설명', now(), now())
|
||||||
|
ON CONFLICT (table_name)
|
||||||
|
DO UPDATE SET
|
||||||
|
table_label = EXCLUDED.table_label,
|
||||||
|
description = EXCLUDED.description,
|
||||||
|
updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 table_type_columns (컬럼 타입 정보)
|
||||||
|
|
||||||
|
**필수 컬럼**: `table_name`, `column_name`, `company_code`, `input_type`, `display_order`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 기본 컬럼 등록 (display_order: -5 ~ -1)
|
||||||
|
INSERT INTO table_type_columns (
|
||||||
|
table_name, column_name, company_code, input_type, detail_settings,
|
||||||
|
is_nullable, display_order, created_date, updated_date
|
||||||
|
) VALUES
|
||||||
|
('테이블명', 'id', '*', 'text', '{}', 'Y', -5, now(), now()),
|
||||||
|
('테이블명', 'created_date', '*', 'date', '{}', 'Y', -4, now(), now()),
|
||||||
|
('테이블명', 'updated_date', '*', 'date', '{}', 'Y', -3, now(), now()),
|
||||||
|
('테이블명', 'writer', '*', 'text', '{}', 'Y', -2, now(), now()),
|
||||||
|
('테이블명', 'company_code', '*', 'text', '{}', 'Y', -1, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name, company_code)
|
||||||
|
DO UPDATE SET
|
||||||
|
input_type = EXCLUDED.input_type,
|
||||||
|
display_order = EXCLUDED.display_order,
|
||||||
|
updated_date = now();
|
||||||
|
|
||||||
|
-- 사용자 정의 컬럼 등록 (display_order: 0부터 시작)
|
||||||
|
INSERT INTO table_type_columns (
|
||||||
|
table_name, column_name, company_code, input_type, detail_settings,
|
||||||
|
is_nullable, display_order, created_date, updated_date
|
||||||
|
) VALUES
|
||||||
|
('테이블명', '컬럼1', '*', 'text', '{}', 'Y', 0, now(), now()),
|
||||||
|
('테이블명', '컬럼2', '*', 'number', '{}', 'Y', 1, now(), now()),
|
||||||
|
('테이블명', '컬럼3', '*', 'code', '{"codeCategory":"카테고리코드"}', 'Y', 2, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name, company_code)
|
||||||
|
DO UPDATE SET
|
||||||
|
input_type = EXCLUDED.input_type,
|
||||||
|
detail_settings = EXCLUDED.detail_settings,
|
||||||
|
display_order = EXCLUDED.display_order,
|
||||||
|
updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 column_labels (레거시 호환용 - 필수)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 기본 컬럼 등록
|
||||||
|
INSERT INTO column_labels (
|
||||||
|
table_name, column_name, column_label, input_type, detail_settings,
|
||||||
|
description, display_order, is_visible, created_date, updated_date
|
||||||
|
) VALUES
|
||||||
|
('테이블명', 'id', 'ID', 'text', '{}', '기본키 (자동생성)', -5, true, now(), now()),
|
||||||
|
('테이블명', 'created_date', '생성일시', 'date', '{}', '레코드 생성일시', -4, true, now(), now()),
|
||||||
|
('테이블명', 'updated_date', '수정일시', 'date', '{}', '레코드 수정일시', -3, true, now(), now()),
|
||||||
|
('테이블명', 'writer', '작성자', 'text', '{}', '레코드 작성자', -2, true, now(), now()),
|
||||||
|
('테이블명', 'company_code', '회사코드', 'text', '{}', '회사 구분 코드', -1, true, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name)
|
||||||
|
DO UPDATE SET
|
||||||
|
column_label = EXCLUDED.column_label,
|
||||||
|
input_type = EXCLUDED.input_type,
|
||||||
|
detail_settings = EXCLUDED.detail_settings,
|
||||||
|
description = EXCLUDED.description,
|
||||||
|
display_order = EXCLUDED.display_order,
|
||||||
|
is_visible = EXCLUDED.is_visible,
|
||||||
|
updated_date = now();
|
||||||
|
|
||||||
|
-- 사용자 정의 컬럼 등록
|
||||||
|
INSERT INTO column_labels (
|
||||||
|
table_name, column_name, column_label, input_type, detail_settings,
|
||||||
|
description, display_order, is_visible, created_date, updated_date
|
||||||
|
) VALUES
|
||||||
|
('테이블명', '컬럼1', '컬럼1 라벨', 'text', '{}', '컬럼1 설명', 0, true, now(), now()),
|
||||||
|
('테이블명', '컬럼2', '컬럼2 라벨', 'number', '{}', '컬럼2 설명', 1, true, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name)
|
||||||
|
DO UPDATE SET
|
||||||
|
column_label = EXCLUDED.column_label,
|
||||||
|
input_type = EXCLUDED.input_type,
|
||||||
|
detail_settings = EXCLUDED.detail_settings,
|
||||||
|
description = EXCLUDED.description,
|
||||||
|
display_order = EXCLUDED.display_order,
|
||||||
|
is_visible = EXCLUDED.is_visible,
|
||||||
|
updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Input Type 정의
|
||||||
|
|
||||||
|
### 지원되는 Input Type 목록
|
||||||
|
|
||||||
|
| input_type | 설명 | DB 저장 타입 | UI 컴포넌트 |
|
||||||
|
| ---------- | ------------- | ------------ | -------------------- |
|
||||||
|
| `text` | 텍스트 입력 | VARCHAR(500) | Input |
|
||||||
|
| `number` | 숫자 입력 | VARCHAR(500) | Input (type=number) |
|
||||||
|
| `date` | 날짜/시간 | VARCHAR(500) | DatePicker |
|
||||||
|
| `code` | 공통코드 선택 | VARCHAR(500) | Select (코드 목록) |
|
||||||
|
| `entity` | 엔티티 참조 | VARCHAR(500) | Select (테이블 참조) |
|
||||||
|
| `select` | 선택 목록 | VARCHAR(500) | Select |
|
||||||
|
| `checkbox` | 체크박스 | VARCHAR(500) | Checkbox |
|
||||||
|
| `radio` | 라디오 버튼 | VARCHAR(500) | RadioGroup |
|
||||||
|
| `textarea` | 긴 텍스트 | VARCHAR(500) | Textarea |
|
||||||
|
| `file` | 파일 업로드 | VARCHAR(500) | FileUpload |
|
||||||
|
|
||||||
|
### WebType → InputType 변환 규칙
|
||||||
|
|
||||||
|
```
|
||||||
|
text, textarea, email, tel, url, password → text
|
||||||
|
number, decimal → number
|
||||||
|
date, datetime, time → date
|
||||||
|
select, dropdown → select
|
||||||
|
checkbox, boolean → checkbox
|
||||||
|
radio → radio
|
||||||
|
code → code
|
||||||
|
entity → entity
|
||||||
|
file → text
|
||||||
|
button → text
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Detail Settings 설정
|
||||||
|
|
||||||
|
### 4.1 Code 타입 (공통코드 참조)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"codeCategory": "코드_카테고리_ID"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO table_type_columns (..., input_type, detail_settings, ...)
|
||||||
|
VALUES (..., 'code', '{"codeCategory":"STATUS_CODE"}', ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Entity 타입 (테이블 참조)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"referenceTable": "참조_테이블명",
|
||||||
|
"referenceColumn": "참조_컬럼명(보통 id)",
|
||||||
|
"displayColumn": "표시할_컬럼명"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO table_type_columns (..., input_type, detail_settings, ...)
|
||||||
|
VALUES (..., 'entity', '{"referenceTable":"user_info","referenceColumn":"id","displayColumn":"user_name"}', ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 Select 타입 (정적 옵션)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"options": [
|
||||||
|
{ "label": "옵션1", "value": "value1" },
|
||||||
|
{ "label": "옵션2", "value": "value2" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 전체 예시: 주문 테이블 생성
|
||||||
|
|
||||||
|
### Step 1: DDL 실행
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE "order_info" (
|
||||||
|
"id" varchar(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
||||||
|
"created_date" timestamp DEFAULT now(),
|
||||||
|
"updated_date" timestamp DEFAULT now(),
|
||||||
|
"writer" varchar(500) DEFAULT NULL,
|
||||||
|
"company_code" varchar(500),
|
||||||
|
|
||||||
|
"order_no" varchar(500),
|
||||||
|
"order_date" varchar(500),
|
||||||
|
"customer_id" varchar(500),
|
||||||
|
"total_amount" varchar(500),
|
||||||
|
"status" varchar(500),
|
||||||
|
"notes" varchar(500)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: table_labels 등록
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date)
|
||||||
|
VALUES ('order_info', '주문 정보', '주문 관리 테이블', now(), now())
|
||||||
|
ON CONFLICT (table_name)
|
||||||
|
DO UPDATE SET
|
||||||
|
table_label = EXCLUDED.table_label,
|
||||||
|
description = EXCLUDED.description,
|
||||||
|
updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: table_type_columns 등록
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 기본 컬럼
|
||||||
|
INSERT INTO table_type_columns (table_name, column_name, company_code, input_type, detail_settings, is_nullable, display_order, created_date, updated_date)
|
||||||
|
VALUES
|
||||||
|
('order_info', 'id', '*', 'text', '{}', 'Y', -5, now(), now()),
|
||||||
|
('order_info', 'created_date', '*', 'date', '{}', 'Y', -4, now(), now()),
|
||||||
|
('order_info', 'updated_date', '*', 'date', '{}', 'Y', -3, now(), now()),
|
||||||
|
('order_info', 'writer', '*', 'text', '{}', 'Y', -2, now(), now()),
|
||||||
|
('order_info', 'company_code', '*', 'text', '{}', 'Y', -1, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name, company_code) DO UPDATE SET input_type = EXCLUDED.input_type, display_order = EXCLUDED.display_order, updated_date = now();
|
||||||
|
|
||||||
|
-- 사용자 정의 컬럼
|
||||||
|
INSERT INTO table_type_columns (table_name, column_name, company_code, input_type, detail_settings, is_nullable, display_order, created_date, updated_date)
|
||||||
|
VALUES
|
||||||
|
('order_info', 'order_no', '*', 'text', '{}', 'Y', 0, now(), now()),
|
||||||
|
('order_info', 'order_date', '*', 'date', '{}', 'Y', 1, now(), now()),
|
||||||
|
('order_info', 'customer_id', '*', 'entity', '{"referenceTable":"customer_info","referenceColumn":"id","displayColumn":"customer_name"}', 'Y', 2, now(), now()),
|
||||||
|
('order_info', 'total_amount', '*', 'number', '{}', 'Y', 3, now(), now()),
|
||||||
|
('order_info', 'status', '*', 'code', '{"codeCategory":"ORDER_STATUS"}', 'Y', 4, now(), now()),
|
||||||
|
('order_info', 'notes', '*', 'textarea', '{}', 'Y', 5, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name, company_code) DO UPDATE SET input_type = EXCLUDED.input_type, detail_settings = EXCLUDED.detail_settings, display_order = EXCLUDED.display_order, updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: column_labels 등록 (레거시 호환)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 기본 컬럼
|
||||||
|
INSERT INTO column_labels (table_name, column_name, column_label, input_type, detail_settings, description, display_order, is_visible, created_date, updated_date)
|
||||||
|
VALUES
|
||||||
|
('order_info', 'id', 'ID', 'text', '{}', '기본키', -5, true, now(), now()),
|
||||||
|
('order_info', 'created_date', '생성일시', 'date', '{}', '레코드 생성일시', -4, true, now(), now()),
|
||||||
|
('order_info', 'updated_date', '수정일시', 'date', '{}', '레코드 수정일시', -3, true, now(), now()),
|
||||||
|
('order_info', 'writer', '작성자', 'text', '{}', '레코드 작성자', -2, true, now(), now()),
|
||||||
|
('order_info', 'company_code', '회사코드', 'text', '{}', '회사 구분 코드', -1, true, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name) DO UPDATE SET column_label = EXCLUDED.column_label, input_type = EXCLUDED.input_type, updated_date = now();
|
||||||
|
|
||||||
|
-- 사용자 정의 컬럼
|
||||||
|
INSERT INTO column_labels (table_name, column_name, column_label, input_type, detail_settings, description, display_order, is_visible, created_date, updated_date)
|
||||||
|
VALUES
|
||||||
|
('order_info', 'order_no', '주문번호', 'text', '{}', '주문 식별 번호', 0, true, now(), now()),
|
||||||
|
('order_info', 'order_date', '주문일자', 'date', '{}', '주문 발생 일자', 1, true, now(), now()),
|
||||||
|
('order_info', 'customer_id', '고객', 'entity', '{"referenceTable":"customer_info","referenceColumn":"id","displayColumn":"customer_name"}', '주문 고객', 2, true, now(), now()),
|
||||||
|
('order_info', 'total_amount', '총금액', 'number', '{}', '주문 총 금액', 3, true, now(), now()),
|
||||||
|
('order_info', 'status', '상태', 'code', '{"codeCategory":"ORDER_STATUS"}', '주문 상태', 4, true, now(), now()),
|
||||||
|
('order_info', 'notes', '비고', 'textarea', '{}', '추가 메모', 5, true, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name) DO UPDATE SET column_label = EXCLUDED.column_label, input_type = EXCLUDED.input_type, detail_settings = EXCLUDED.detail_settings, description = EXCLUDED.description, display_order = EXCLUDED.display_order, updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 컬럼 추가 시
|
||||||
|
|
||||||
|
### DDL
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER TABLE "테이블명" ADD COLUMN "새컬럼명" varchar(500);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 메타데이터 등록
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- table_type_columns
|
||||||
|
INSERT INTO table_type_columns (table_name, column_name, company_code, input_type, detail_settings, is_nullable, display_order, created_date, updated_date)
|
||||||
|
VALUES ('테이블명', '새컬럼명', '*', 'text', '{}', 'Y', (SELECT COALESCE(MAX(display_order), 0) + 1 FROM table_type_columns WHERE table_name = '테이블명'), now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name, company_code) DO UPDATE SET input_type = EXCLUDED.input_type, display_order = EXCLUDED.display_order, updated_date = now();
|
||||||
|
|
||||||
|
-- column_labels
|
||||||
|
INSERT INTO column_labels (table_name, column_name, column_label, input_type, detail_settings, description, display_order, is_visible, created_date, updated_date)
|
||||||
|
VALUES ('테이블명', '새컬럼명', '새컬럼 라벨', 'text', '{}', '새컬럼 설명', (SELECT COALESCE(MAX(display_order), 0) + 1 FROM column_labels WHERE table_name = '테이블명'), true, now(), now())
|
||||||
|
ON CONFLICT (table_name, column_name) DO UPDATE SET column_label = EXCLUDED.column_label, input_type = EXCLUDED.input_type, updated_date = now();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 체크리스트
|
||||||
|
|
||||||
|
테이블 생성/수정 시 반드시 확인할 사항:
|
||||||
|
|
||||||
|
- [ ] DDL에 기본 5개 컬럼 포함 (id, created_date, updated_date, writer, company_code)
|
||||||
|
- [ ] 모든 비즈니스 컬럼은 `VARCHAR(500)` 타입 사용
|
||||||
|
- [ ] `table_labels`에 테이블 메타데이터 등록
|
||||||
|
- [ ] `table_type_columns`에 모든 컬럼 등록 (company_code = '\*')
|
||||||
|
- [ ] `column_labels`에 모든 컬럼 등록 (레거시 호환)
|
||||||
|
- [ ] 기본 컬럼 display_order: -5 ~ -1
|
||||||
|
- [ ] 사용자 정의 컬럼 display_order: 0부터 순차
|
||||||
|
- [ ] code/entity 타입은 detail_settings에 참조 정보 포함
|
||||||
|
- [ ] ON CONFLICT 절로 중복 시 UPDATE 처리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 금지 사항
|
||||||
|
|
||||||
|
1. **DB 타입 직접 지정 금지**: NUMBER, INTEGER, DATE 등 DB 타입 직접 사용 금지
|
||||||
|
2. **VARCHAR 길이 변경 금지**: 반드시 `VARCHAR(500)` 사용
|
||||||
|
3. **기본 컬럼 누락 금지**: id, created_date, updated_date, writer, company_code 필수
|
||||||
|
4. **메타데이터 미등록 금지**: 3개 테이블 모두 등록 필수
|
||||||
|
5. **web_type 사용 금지**: 레거시 컬럼이므로 `input_type` 사용
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 참조 파일
|
||||||
|
|
||||||
|
- `backend-node/src/services/ddlExecutionService.ts`: DDL 실행 서비스
|
||||||
|
- `backend-node/src/types/ddl.ts`: DDL 타입 정의
|
||||||
|
- `backend-node/src/controllers/ddlController.ts`: DDL API 컨트롤러
|
||||||
Loading…
Reference in New Issue