From c32bd8a4bf4ba572260ff9be9f3c527d76e3912d Mon Sep 17 00:00:00 2001 From: kjs Date: Tue, 30 Dec 2025 10:48:11 +0900 Subject: [PATCH] =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EA=B7=9C=EC=B9=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/table-type-sql-guide.mdc | 368 +++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 .cursor/rules/table-type-sql-guide.mdc diff --git a/.cursor/rules/table-type-sql-guide.mdc b/.cursor/rules/table-type-sql-guide.mdc new file mode 100644 index 00000000..501c3218 --- /dev/null +++ b/.cursor/rules/table-type-sql-guide.mdc @@ -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 컨트롤러