ERP-node/코드_채번_규칙_컴포넌트_구현_계획서.md

13 KiB

코드 채번 규칙 컴포넌트 구현 계획서

문서 정보

  • 작성일: 2025-11-03
  • 목적: Shadcn/ui 가이드라인 기반 코드 채번 규칙 컴포넌트 구현
  • 우선순위: 중간
  • 디자인 원칙: 심플하고 깔끔한 UI, 중첩 박스 금지, 일관된 컬러 시스템

1. 기능 요구사항

1.1 핵심 기능

  • 코드 채번 규칙 생성/수정/삭제
  • 동적 규칙 파트 추가/삭제 (최대 6개)
  • 실시간 코드 미리보기
  • 규칙 순서 조정
  • 데이터베이스 저장 및 불러오기

1.2 UI 요구사항

  • 좌측: 코드 목록 (선택적)
  • 우측: 규칙 설정 영역
  • 상단: 코드 미리보기 + 규칙명
  • 중앙: 규칙 카드 리스트
  • 하단: 규칙 추가 + 저장 버튼

2. 디자인 시스템 (Shadcn/ui 기반)

2.1 색상 사용 규칙

// 배경
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 간격 시스템

// 카드 간 간격
gap-6                  // 24px (카드 사이)

// 카드 내부 패딩
p-6                    // 24px (CardContent)

// 폼 필드 간격
space-y-4              // 16px (입력 필드들)
space-y-3              // 12px (모바일)

// 섹션 간격
space-y-6              // 24px (큰 섹션)

2.3 타이포그래피

// 페이지 제목
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 반응형 설정

// 모바일 우선 + 데스크톱 최적화
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 중첩 박스 금지 원칙

잘못된 예시:

<Card>
  <CardContent>
    <div className="border rounded-lg p-4">  {/* 중첩 박스! */}
      <div className="border rounded p-2">  {/* 또 중첩! */}
        내용
      </div>
    </div>
  </CardContent>
</Card>

올바른 예시:

<Card>
  <CardHeader>
    <CardTitle>제목</CardTitle>
  </CardHeader>
  <CardContent className="space-y-4">
    {/* 직접 컨텐츠 배치 */}
    <div>내용 1</div>
    <div>내용 2</div>
  </CardContent>
</Card>

3. 데이터 구조

3.1 타입 정의

// 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 데이터베이스 스키마

-- 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 사용하기

규칙 목록 조회

GET /api/numbering-rules

규칙 생성

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": "-"
}

코드 생성

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. 다음 개선 사항 (선택사항)

  • 규칙 순서 드래그앤드롭으로 변경
  • 규칙 복제 기능
  • 규칙 템플릿 제공 (자주 사용하는 패턴)
  • 코드 검증 로직
  • 테이블 생성 시 자동 채번 컬럼 추가 통합
  • 화면관리에서 입력 폼에 자동 코드 생성 버튼 추가