495 lines
13 KiB
Markdown
495 lines
13 KiB
Markdown
|
|
# 코드 채번 규칙 컴포넌트 구현 계획서
|
||
|
|
|
||
|
|
## 문서 정보
|
||
|
|
- **작성일**: 2025-11-03
|
||
|
|
- **목적**: Shadcn/ui 가이드라인 기반 코드 채번 규칙 컴포넌트 구현
|
||
|
|
- **우선순위**: 중간
|
||
|
|
- **디자인 원칙**: 심플하고 깔끔한 UI, 중첩 박스 금지, 일관된 컬러 시스템
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. 기능 요구사항
|
||
|
|
|
||
|
|
### 1.1 핵심 기능
|
||
|
|
- 코드 채번 규칙 생성/수정/삭제
|
||
|
|
- 동적 규칙 파트 추가/삭제 (최대 6개)
|
||
|
|
- 실시간 코드 미리보기
|
||
|
|
- 규칙 순서 조정
|
||
|
|
- 데이터베이스 저장 및 불러오기
|
||
|
|
|
||
|
|
### 1.2 UI 요구사항
|
||
|
|
- 좌측: 코드 목록 (선택적)
|
||
|
|
- 우측: 규칙 설정 영역
|
||
|
|
- 상단: 코드 미리보기 + 규칙명
|
||
|
|
- 중앙: 규칙 카드 리스트
|
||
|
|
- 하단: 규칙 추가 + 저장 버튼
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. 디자인 시스템 (Shadcn/ui 기반)
|
||
|
|
|
||
|
|
### 2.1 색상 사용 규칙
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
// 배경
|
||
|
|
bg-background // 페이지 배경
|
||
|
|
bg-card // 카드 배경
|
||
|
|
bg-muted // 약한 배경 (미리보기 등)
|
||
|
|
|
||
|
|
// 텍스트
|
||
|
|
text-foreground // 기본 텍스트
|
||
|
|
text-muted-foreground // 보조 텍스트
|
||
|
|
text-primary // 강조 텍스트
|
||
|
|
|
||
|
|
// 테두리
|
||
|
|
border-border // 기본 테두리
|
||
|
|
border-input // 입력 필드 테두리
|
||
|
|
|
||
|
|
// 버튼
|
||
|
|
bg-primary // 주요 버튼 (저장, 추가)
|
||
|
|
bg-destructive // 삭제 버튼
|
||
|
|
variant="outline" // 보조 버튼 (취소)
|
||
|
|
variant="ghost" // 아이콘 버튼
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 간격 시스템
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
// 카드 간 간격
|
||
|
|
gap-6 // 24px (카드 사이)
|
||
|
|
|
||
|
|
// 카드 내부 패딩
|
||
|
|
p-6 // 24px (CardContent)
|
||
|
|
|
||
|
|
// 폼 필드 간격
|
||
|
|
space-y-4 // 16px (입력 필드들)
|
||
|
|
space-y-3 // 12px (모바일)
|
||
|
|
|
||
|
|
// 섹션 간격
|
||
|
|
space-y-6 // 24px (큰 섹션)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.3 타이포그래피
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
// 페이지 제목
|
||
|
|
text-2xl font-semibold
|
||
|
|
|
||
|
|
// 섹션 제목
|
||
|
|
text-lg font-semibold
|
||
|
|
|
||
|
|
// 카드 제목
|
||
|
|
text-base font-semibold
|
||
|
|
|
||
|
|
// 라벨
|
||
|
|
text-sm font-medium
|
||
|
|
|
||
|
|
// 본문 텍스트
|
||
|
|
text-sm text-muted-foreground
|
||
|
|
|
||
|
|
// 작은 텍스트
|
||
|
|
text-xs text-muted-foreground
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.4 반응형 설정
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
// 모바일 우선 + 데스크톱 최적화
|
||
|
|
className="text-xs sm:text-sm" // 폰트 크기
|
||
|
|
className="h-8 sm:h-10" // 입력 필드 높이
|
||
|
|
className="flex-col md:flex-row" // 레이아웃
|
||
|
|
className="gap-2 sm:gap-4" // 간격
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.5 중첩 박스 금지 원칙
|
||
|
|
|
||
|
|
**❌ 잘못된 예시**:
|
||
|
|
```tsx
|
||
|
|
<Card>
|
||
|
|
<CardContent>
|
||
|
|
<div className="border rounded-lg p-4"> {/* 중첩 박스! */}
|
||
|
|
<div className="border rounded p-2"> {/* 또 중첩! */}
|
||
|
|
내용
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
```
|
||
|
|
|
||
|
|
**✅ 올바른 예시**:
|
||
|
|
```tsx
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle>제목</CardTitle>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent className="space-y-4">
|
||
|
|
{/* 직접 컨텐츠 배치 */}
|
||
|
|
<div>내용 1</div>
|
||
|
|
<div>내용 2</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. 데이터 구조
|
||
|
|
|
||
|
|
### 3.1 타입 정의
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// frontend/types/numbering-rule.ts
|
||
|
|
|
||
|
|
import { BaseComponent } from "./screen-management";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 코드 파트 유형
|
||
|
|
*/
|
||
|
|
export type CodePartType =
|
||
|
|
| "prefix" // 접두사 (고정 문자열)
|
||
|
|
| "sequence" // 순번 (자동 증가)
|
||
|
|
| "date" // 날짜 (YYYYMMDD 등)
|
||
|
|
| "year" // 연도 (YYYY)
|
||
|
|
| "month" // 월 (MM)
|
||
|
|
| "custom"; // 사용자 정의
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 생성 방식
|
||
|
|
*/
|
||
|
|
export type GenerationMethod =
|
||
|
|
| "auto" // 자동 생성
|
||
|
|
| "manual"; // 직접 입력
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 날짜 형식
|
||
|
|
*/
|
||
|
|
export type DateFormat =
|
||
|
|
| "YYYY" // 2025
|
||
|
|
| "YY" // 25
|
||
|
|
| "YYYYMM" // 202511
|
||
|
|
| "YYMM" // 2511
|
||
|
|
| "YYYYMMDD" // 20251103
|
||
|
|
| "YYMMDD"; // 251103
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 단일 규칙 파트
|
||
|
|
*/
|
||
|
|
export interface NumberingRulePart {
|
||
|
|
id: string; // 고유 ID
|
||
|
|
order: number; // 순서 (1-6)
|
||
|
|
partType: CodePartType; // 파트 유형
|
||
|
|
generationMethod: GenerationMethod; // 생성 방식
|
||
|
|
|
||
|
|
// 자동 생성 설정
|
||
|
|
autoConfig?: {
|
||
|
|
// 접두사 설정
|
||
|
|
prefix?: string; // 예: "ITM"
|
||
|
|
|
||
|
|
// 순번 설정
|
||
|
|
sequenceLength?: number; // 자릿수 (예: 4 → 0001)
|
||
|
|
startFrom?: number; // 시작 번호 (기본: 1)
|
||
|
|
|
||
|
|
// 날짜 설정
|
||
|
|
dateFormat?: DateFormat; // 날짜 형식
|
||
|
|
};
|
||
|
|
|
||
|
|
// 직접 입력 설정
|
||
|
|
manualConfig?: {
|
||
|
|
value: string; // 입력값
|
||
|
|
placeholder?: string; // 플레이스홀더
|
||
|
|
};
|
||
|
|
|
||
|
|
// 생성된 값 (미리보기용)
|
||
|
|
generatedValue?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 전체 채번 규칙
|
||
|
|
*/
|
||
|
|
export interface NumberingRuleConfig {
|
||
|
|
ruleId: string; // 규칙 ID
|
||
|
|
ruleName: string; // 규칙명
|
||
|
|
description?: string; // 설명
|
||
|
|
parts: NumberingRulePart[]; // 규칙 파트 배열 (최대 6개)
|
||
|
|
|
||
|
|
// 설정
|
||
|
|
separator?: string; // 구분자 (기본: "-")
|
||
|
|
resetPeriod?: "none" | "daily" | "monthly" | "yearly"; // 초기화 주기
|
||
|
|
currentSequence?: number; // 현재 시퀀스
|
||
|
|
|
||
|
|
// 적용 대상
|
||
|
|
tableName?: string; // 적용할 테이블명
|
||
|
|
columnName?: string; // 적용할 컬럼명
|
||
|
|
|
||
|
|
// 메타 정보
|
||
|
|
companyCode?: string;
|
||
|
|
createdAt?: string;
|
||
|
|
updatedAt?: string;
|
||
|
|
createdBy?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 화면관리 컴포넌트 인터페이스
|
||
|
|
*/
|
||
|
|
export interface NumberingRuleComponent extends BaseComponent {
|
||
|
|
type: "numbering-rule";
|
||
|
|
|
||
|
|
// 채번 규칙 설정
|
||
|
|
ruleConfig: NumberingRuleConfig;
|
||
|
|
|
||
|
|
// UI 설정
|
||
|
|
showRuleList?: boolean; // 좌측 목록 표시 여부
|
||
|
|
maxRules?: number; // 최대 규칙 개수 (기본: 6)
|
||
|
|
enableReorder?: boolean; // 순서 변경 허용 여부
|
||
|
|
|
||
|
|
// 스타일
|
||
|
|
cardLayout?: "vertical" | "horizontal"; // 카드 레이아웃
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 데이터베이스 스키마
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- db/migrations/034_create_numbering_rules.sql
|
||
|
|
|
||
|
|
-- 채번 규칙 마스터 테이블
|
||
|
|
CREATE TABLE IF NOT EXISTS numbering_rules (
|
||
|
|
rule_id VARCHAR(50) PRIMARY KEY,
|
||
|
|
rule_name VARCHAR(100) NOT NULL,
|
||
|
|
description TEXT,
|
||
|
|
separator VARCHAR(10) DEFAULT '-',
|
||
|
|
reset_period VARCHAR(20) DEFAULT 'none',
|
||
|
|
current_sequence INTEGER DEFAULT 1,
|
||
|
|
table_name VARCHAR(100),
|
||
|
|
column_name VARCHAR(100),
|
||
|
|
company_code VARCHAR(20) NOT NULL,
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
created_by VARCHAR(50),
|
||
|
|
|
||
|
|
CONSTRAINT fk_company FOREIGN KEY (company_code)
|
||
|
|
REFERENCES company_info(company_code)
|
||
|
|
);
|
||
|
|
|
||
|
|
-- 채번 규칙 상세 테이블
|
||
|
|
CREATE TABLE IF NOT EXISTS numbering_rule_parts (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
rule_id VARCHAR(50) NOT NULL,
|
||
|
|
part_order INTEGER NOT NULL,
|
||
|
|
part_type VARCHAR(50) NOT NULL,
|
||
|
|
generation_method VARCHAR(20) NOT NULL,
|
||
|
|
auto_config JSONB,
|
||
|
|
manual_config JSONB,
|
||
|
|
company_code VARCHAR(20) NOT NULL,
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
|
||
|
|
CONSTRAINT fk_numbering_rule FOREIGN KEY (rule_id)
|
||
|
|
REFERENCES numbering_rules(rule_id) ON DELETE CASCADE,
|
||
|
|
CONSTRAINT fk_company FOREIGN KEY (company_code)
|
||
|
|
REFERENCES company_info(company_code),
|
||
|
|
CONSTRAINT unique_rule_order UNIQUE (rule_id, part_order, company_code)
|
||
|
|
);
|
||
|
|
|
||
|
|
-- 인덱스
|
||
|
|
CREATE INDEX idx_numbering_rules_company ON numbering_rules(company_code);
|
||
|
|
CREATE INDEX idx_numbering_rule_parts_rule ON numbering_rule_parts(rule_id);
|
||
|
|
CREATE INDEX idx_numbering_rules_table ON numbering_rules(table_name, column_name);
|
||
|
|
|
||
|
|
-- 샘플 데이터
|
||
|
|
INSERT INTO numbering_rules (rule_id, rule_name, description, company_code, created_by)
|
||
|
|
VALUES ('SAMPLE_RULE', '샘플 채번 규칙', '제품 코드 자동 생성', '*', 'system')
|
||
|
|
ON CONFLICT (rule_id) DO NOTHING;
|
||
|
|
|
||
|
|
INSERT INTO numbering_rule_parts (rule_id, part_order, part_type, generation_method, auto_config, company_code)
|
||
|
|
VALUES
|
||
|
|
('SAMPLE_RULE', 1, 'prefix', 'auto', '{"prefix": "PROD"}', '*'),
|
||
|
|
('SAMPLE_RULE', 2, 'date', 'auto', '{"dateFormat": "YYYYMMDD"}', '*'),
|
||
|
|
('SAMPLE_RULE', 3, 'sequence', 'auto', '{"sequenceLength": 4, "startFrom": 1}', '*')
|
||
|
|
ON CONFLICT (rule_id, part_order, company_code) DO NOTHING;
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. 구현 순서
|
||
|
|
|
||
|
|
### Phase 1: 타입 정의 및 스키마 생성 ✅
|
||
|
|
1. 타입 정의 파일 생성
|
||
|
|
2. 데이터베이스 마이그레이션 실행
|
||
|
|
3. 샘플 데이터 삽입
|
||
|
|
|
||
|
|
### Phase 2: 백엔드 API 구현
|
||
|
|
1. Controller 생성
|
||
|
|
2. Service 레이어 구현
|
||
|
|
3. API 테스트
|
||
|
|
|
||
|
|
### Phase 3: 프론트엔드 기본 컴포넌트
|
||
|
|
1. NumberingRuleDesigner (메인)
|
||
|
|
2. NumberingRulePreview (미리보기)
|
||
|
|
3. NumberingRuleCard (단일 규칙 카드)
|
||
|
|
|
||
|
|
### Phase 4: 상세 설정 패널
|
||
|
|
1. PartTypeSelector (파트 유형 선택)
|
||
|
|
2. AutoConfigPanel (자동 생성 설정)
|
||
|
|
3. ManualConfigPanel (직접 입력 설정)
|
||
|
|
|
||
|
|
### Phase 5: 화면관리 통합
|
||
|
|
1. ComponentType에 "numbering-rule" 추가
|
||
|
|
2. RealtimePreview 렌더링 추가
|
||
|
|
3. 템플릿 등록
|
||
|
|
4. 속성 패널 구현
|
||
|
|
|
||
|
|
### Phase 6: 테스트 및 최적화
|
||
|
|
1. 기능 테스트
|
||
|
|
2. 반응형 테스트
|
||
|
|
3. 성능 최적화
|
||
|
|
4. 문서화
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. 구현 완료 ✅
|
||
|
|
|
||
|
|
### Phase 1: 타입 정의 및 스키마 생성 ✅
|
||
|
|
- ✅ `frontend/types/numbering-rule.ts` 생성
|
||
|
|
- ✅ `db/migrations/034_create_numbering_rules.sql` 생성 및 실행
|
||
|
|
- ✅ 샘플 데이터 삽입 완료
|
||
|
|
|
||
|
|
### Phase 2: 백엔드 API 구현 ✅
|
||
|
|
- ✅ `backend-node/src/services/numberingRuleService.ts` 생성
|
||
|
|
- ✅ `backend-node/src/controllers/numberingRuleController.ts` 생성
|
||
|
|
- ✅ `app.ts`에 라우터 등록 (`/api/numbering-rules`)
|
||
|
|
- ✅ 백엔드 재시작 완료
|
||
|
|
|
||
|
|
### Phase 3: 프론트엔드 기본 컴포넌트 ✅
|
||
|
|
- ✅ `NumberingRulePreview.tsx` - 코드 미리보기
|
||
|
|
- ✅ `NumberingRuleCard.tsx` - 단일 규칙 카드
|
||
|
|
- ✅ `AutoConfigPanel.tsx` - 자동 생성 설정
|
||
|
|
- ✅ `ManualConfigPanel.tsx` - 직접 입력 설정
|
||
|
|
- ✅ `NumberingRuleDesigner.tsx` - 메인 디자이너
|
||
|
|
|
||
|
|
### Phase 4: 상세 설정 패널 ✅
|
||
|
|
- ✅ 파트 유형별 설정 UI (접두사, 순번, 날짜, 연도, 월, 커스텀)
|
||
|
|
- ✅ 자동 생성 / 직접 입력 모드 전환
|
||
|
|
- ✅ 실시간 미리보기 업데이트
|
||
|
|
|
||
|
|
### Phase 5: 화면관리 시스템 통합 ✅
|
||
|
|
- ✅ `unified-core.ts`에 "numbering-rule" ComponentType 추가
|
||
|
|
- ✅ `screen-management.ts`에 ComponentData 유니온 타입 추가
|
||
|
|
- ✅ `RealtimePreview.tsx`에 렌더링 로직 추가
|
||
|
|
- ✅ `TemplatesPanel.tsx`에 "관리자" 카테고리 및 템플릿 추가
|
||
|
|
- ✅ `NumberingRuleTemplate.ts` 생성
|
||
|
|
|
||
|
|
### Phase 6: 완료 ✅
|
||
|
|
모든 단계가 성공적으로 완료되었습니다!
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. 사용 방법
|
||
|
|
|
||
|
|
### 6.1 화면관리에서 사용하기
|
||
|
|
|
||
|
|
1. **화면관리** 페이지로 이동
|
||
|
|
2. 좌측 **템플릿 패널**에서 **관리자** 카테고리 선택
|
||
|
|
3. **코드 채번 규칙** 템플릿을 캔버스로 드래그
|
||
|
|
4. 규칙 파트 추가 및 설정
|
||
|
|
5. 저장
|
||
|
|
|
||
|
|
### 6.2 API 사용하기
|
||
|
|
|
||
|
|
#### 규칙 목록 조회
|
||
|
|
```bash
|
||
|
|
GET /api/numbering-rules
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 규칙 생성
|
||
|
|
```bash
|
||
|
|
POST /api/numbering-rules
|
||
|
|
{
|
||
|
|
"ruleId": "PROD_CODE",
|
||
|
|
"ruleName": "제품 코드 규칙",
|
||
|
|
"parts": [
|
||
|
|
{
|
||
|
|
"id": "part-1",
|
||
|
|
"order": 1,
|
||
|
|
"partType": "prefix",
|
||
|
|
"generationMethod": "auto",
|
||
|
|
"autoConfig": { "prefix": "PROD" }
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "part-2",
|
||
|
|
"order": 2,
|
||
|
|
"partType": "date",
|
||
|
|
"generationMethod": "auto",
|
||
|
|
"autoConfig": { "dateFormat": "YYYYMMDD" }
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "part-3",
|
||
|
|
"order": 3,
|
||
|
|
"partType": "sequence",
|
||
|
|
"generationMethod": "auto",
|
||
|
|
"autoConfig": { "sequenceLength": 4, "startFrom": 1 }
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"separator": "-"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 코드 생성
|
||
|
|
```bash
|
||
|
|
POST /api/numbering-rules/PROD_CODE/generate
|
||
|
|
|
||
|
|
응답: { "success": true, "data": { "code": "PROD-20251103-0001" } }
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. 구현된 파일 목록
|
||
|
|
|
||
|
|
### 프론트엔드
|
||
|
|
```
|
||
|
|
frontend/
|
||
|
|
├── types/
|
||
|
|
│ └── numbering-rule.ts ✅
|
||
|
|
├── components/
|
||
|
|
│ └── numbering-rule/
|
||
|
|
│ ├── NumberingRuleDesigner.tsx ✅
|
||
|
|
│ ├── NumberingRuleCard.tsx ✅
|
||
|
|
│ ├── NumberingRulePreview.tsx ✅
|
||
|
|
│ ├── AutoConfigPanel.tsx ✅
|
||
|
|
│ └── ManualConfigPanel.tsx ✅
|
||
|
|
└── components/screen/
|
||
|
|
├── RealtimePreview.tsx ✅ (수정됨)
|
||
|
|
├── panels/
|
||
|
|
│ └── TemplatesPanel.tsx ✅ (수정됨)
|
||
|
|
└── templates/
|
||
|
|
└── NumberingRuleTemplate.ts ✅
|
||
|
|
```
|
||
|
|
|
||
|
|
### 백엔드
|
||
|
|
```
|
||
|
|
backend-node/
|
||
|
|
├── src/
|
||
|
|
│ ├── services/
|
||
|
|
│ │ └── numberingRuleService.ts ✅
|
||
|
|
│ ├── controllers/
|
||
|
|
│ │ └── numberingRuleController.ts ✅
|
||
|
|
│ └── app.ts ✅ (수정됨)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 데이터베이스
|
||
|
|
```
|
||
|
|
db/
|
||
|
|
└── migrations/
|
||
|
|
└── 034_create_numbering_rules.sql ✅
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. 다음 개선 사항 (선택사항)
|
||
|
|
|
||
|
|
- [ ] 규칙 순서 드래그앤드롭으로 변경
|
||
|
|
- [ ] 규칙 복제 기능
|
||
|
|
- [ ] 규칙 템플릿 제공 (자주 사용하는 패턴)
|
||
|
|
- [ ] 코드 검증 로직
|
||
|
|
- [ ] 테이블 생성 시 자동 채번 컬럼 추가 통합
|
||
|
|
- [ ] 화면관리에서 입력 폼에 자동 코드 생성 버튼 추가
|
||
|
|
|