Files
sam-react-prod/claudedocs/dev/[REF] page-builder-implementation.md
유병철 9464a368ba refactor: 모달 Content 컴포넌트 분리 및 파일 입력 UI 공통화
- 모달 컴포넌트에서 Content 분리하여 재사용성 향상
  - EstimateDocumentContent, DirectConstructionContent 등
  - WorkLogContent, QuotePreviewContent, ReceivingReceiptContent
- 파일 입력 공통 UI 컴포넌트 추가
  - file-dropzone, file-input, file-list, image-upload
- 폼 컴포넌트 코드 정리 및 중복 제거 (-4,056줄)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 15:07:17 +09:00

9.2 KiB

페이지 빌더 (Page Builder) 구현 문서

작성일: 2026-01-22 상태: 개발 중 (테스트 버전) 경로: /dev/page-builder Git 상태: .gitignore에 등록되어 버전 관리 제외 (테스트용)


1. 개요

1.1 목적

품목기준관리(Item Master Data Management)의 폼 구조를 시각적으로(WYSIWYG) 편집할 수 있는 Framer 스타일의 페이지 빌더입니다.

1.2 핵심 기능

  • 드래그 앤 드롭으로 섹션/필드 배치
  • 실시간 미리보기 (데스크탑/태블릿/모바일)
  • API 연동: 품목기준관리 API와 동기화
  • 조건부 표시 설정 (필드 값에 따른 섹션/필드 표시/숨김)
  • Undo/Redo 지원
  • JSON 내보내기/가져오기

1.3 접근 방법

URL: http://localhost:3000/dev/page-builder

2. 파일 구조

src/app/[locale]/(protected)/dev/page-builder/
├── page.tsx                    # 페이지 진입점
├── PageBuilderClient.tsx       # 메인 클라이언트 컴포넌트
├── PLAN.md                     # 초기 기획 문서
│
├── components/
│   ├── index.ts                # 컴포넌트 배럴 export
│   ├── ComponentPalette.tsx    # 좌측 컴포넌트 팔레트 (섹션/필드 드래그)
│   ├── BuilderCanvas.tsx       # 중앙 캔버스 (드롭 영역, 미리보기)
│   ├── PropertyPanel.tsx       # 우측 속성 패널 (섹션/필드 편집)
│   ├── PageSelector.tsx        # 페이지 목록 관리
│   └── ConditionEditor.tsx     # 조건부 표시 설정 UI
│
├── hooks/
│   ├── usePageBuilder.ts       # 섹션/필드 CRUD, 선택 상태 관리
│   ├── usePageManager.ts       # 페이지 CRUD, API 연동, 저장/로드
│   ├── useHistory.ts           # Undo/Redo 히스토리 관리
│   └── useItemMasterSync.ts    # (미사용) 초기 API 동기화 시도
│
├── types/
│   ├── index.ts                # 타입 배럴 export
│   ├── builder.types.ts        # BuilderPage, BuilderSection, BuilderField 등
│   └── constants.ts            # 필드 타입, 섹션 타입 옵션 상수
│
└── utils/
    ├── index.ts                # 유틸 배럴 export
    └── transformers.ts         # API ↔ Builder 타입 변환 함수

3. 핵심 타입 정의

3.1 BuilderPage

interface BuilderPage {
  id: string;
  name: string;           // 페이지 이름 (예: "소모품 등록")
  itemType: ItemType;     // 품목 유형 (FG, PT, SM, RM, CS)
  sections: BuilderSection[];
  createdAt: string;
  updatedAt: string;
}

3.2 BuilderSection

interface BuilderSection {
  id: string;
  title: string;
  description?: string;
  sectionType: SectionType;   // BASIC, BOM, CERTIFICATION 등
  columns: 1 | 2 | 3;         // 레이아웃 열 수
  isCollapsible?: boolean;
  isDefaultOpen?: boolean;
  fields: BuilderField[];
  displayCondition?: DisplayCondition;  // 조건부 표시
  order: number;
}

3.3 BuilderField

interface BuilderField {
  id: string;
  name: string;               // 필드 라벨
  fieldKey: string;           // API 키 (예: "item_name")
  inputType: FieldInputType;  // textbox, number, dropdown 등
  required: boolean;
  placeholder?: string;
  defaultValue?: string;
  options?: DropdownOption[]; // 드롭다운용
  colSpan?: 1 | 2 | 3;
  description?: string;
  displayCondition?: DisplayCondition;
  validationRules?: ValidationRule[];
  order: number;
}

3.4 DisplayCondition (조건부 표시)

interface DisplayCondition {
  enabled: boolean;
  logic: 'AND' | 'OR';
  conditions: FieldCondition[];
}

interface FieldCondition {
  fieldKey: string;
  operator: 'equals' | 'not_equals' | 'contains' | 'not_contains';
  expectedValue: string;
}

4. API 연동

4.1 사용하는 API

품목기준관리와 동일한 API 사용:

// src/lib/api/item-master.ts
itemMasterApi.init()                        // 전체 페이지/섹션/필드 조회
itemMasterApi.sections.create(pageId, data) // 섹션 생성
itemMasterApi.sections.update(id, data)     // 섹션 수정
itemMasterApi.sections.delete(id)           // 섹션 삭제
itemMasterApi.fields.create(sectionId, data)// 필드 생성
itemMasterApi.fields.update(id, data)       // 필드 수정
itemMasterApi.fields.delete(id)             // 필드 삭제

4.2 API 모드 토글

  • API 모드 ON: 백엔드 API에서 데이터 로드/저장
  • API 모드 OFF: localStorage에서 로드/저장 (오프라인 테스트용)
  • 설정은 localStorage에 저장되어 새로고침 후에도 유지

4.3 동기화 로직 (usePageManager.ts)

const syncPageToAPI = async (page: BuilderPage) => {
  // 1. 원본 데이터와 현재 데이터 비교
  // 2. 삭제된 섹션/필드 → API DELETE 호출
  // 3. 새로 추가된 섹션/필드 → API CREATE 호출
  // 4. 수정된 섹션/필드 → API UPDATE 호출
  // 5. 완료 후 API에서 최신 데이터 다시 로드
};

4.4 타입 변환 (transformers.ts)

// API → Builder 변환
transformPagesToBuilder(apiData): BuilderPage[]

// Builder → API 변환
transformSectionToAPI(section): APISectionCreateData
transformFieldToAPI(field): APIFieldCreateData

// ID 구분 (API ID는 숫자, 로컬 ID는 문자열)
isApiId(id: string): boolean  // "123" → true, "section_abc123" → false

5. 주요 컴포넌트 설명

5.1 PageBuilderClient.tsx

메인 컴포넌트로 전체 레이아웃 구성:

  • 상단: 툴바 (미리보기 모드, Undo/Redo, 저장 버튼들)
  • 좌측: PageSelector + ComponentPalette
  • 중앙: BuilderCanvas
  • 우측: PropertyPanel

주요 상태:

const [isAPIMode, setIsAPIMode] = useState(true);     // API 모드
const [previewMode, setPreviewMode] = useState<'desktop' | 'tablet' | 'mobile'>('desktop');

5.2 PageSelector.tsx

페이지 목록 관리:

  • 페이지 선택/생성/삭제/복제/이름변경
  • 호버 시 액션 버튼 표시 (배경색 포함으로 긴 제목도 가리지 않음)

5.3 BuilderCanvas.tsx

드래그 앤 드롭 캔버스:

  • 섹션 드롭 → 새 섹션 추가
  • 필드 드롭 → 해당 섹션에 필드 추가
  • 요소 클릭 → 선택 (PropertyPanel에서 편집)

5.4 PropertyPanel.tsx

선택된 요소의 속성 편집:

  • 섹션: 제목, 설명, 타입, 열 수, 접기 설정, 조건부 표시
  • 필드: 이름, 키, 타입, 필수여부, 옵션, 조건부 표시

5.5 ConditionEditor.tsx

조건부 표시 설정 UI:

  • 다른 필드 값에 따라 현재 섹션/필드 표시/숨김
  • AND/OR 논리 연산 지원
  • 여러 조건 추가 가능

6. 사용 방법

6.1 기본 워크플로우

  1. /dev/page-builder 접속
  2. API 모드 ON 확인 (우측 상단 토글)
  3. 좌측에서 페이지 선택 (소모품, 원자재 등)
  4. 컴포넌트 팔레트에서 섹션/필드를 캔버스로 드래그
  5. 캔버스에서 요소 클릭 → 우측 패널에서 속성 편집
  6. "API 저장" 버튼 클릭 → 백엔드에 저장
  7. 품목기준관리 페이지에서 변경사항 확인

6.2 저장 버튼 종류

버튼 기능
API 저장 (초록색) 현재 페이지를 백엔드 API에 저장
현재 페이지 저장 (JSON) 현재 페이지를 JSON 파일로 다운로드
전체 저장 모든 페이지를 JSON 파일로 다운로드
가져오기 JSON 파일에서 페이지 데이터 로드

6.3 Undo/Redo

  • 실행 취소: 마지막 작업 취소
  • 다시 실행: 취소한 작업 복원
  • 히스토리는 세션 동안만 유지

7. 테스트 완료 항목

7.1 API 연동 테스트 (2026-01-22)

테스트 결과
페이지 빌더에서 섹션 제목 수정 "기본정보" → "기본정보 (빌더테스트)"
API 저장 버튼 클릭 PUT /api/proxy/item-master/sections/92 (200 OK)
품목기준관리 페이지 반영 확인 변경된 제목 표시 확인

7.2 UI 수정 (2026-01-22)

  • 페이지 목록 호버 버튼에 배경색 추가 (긴 제목 가림 방지)

8. 알려진 이슈 / TODO

8.1 현재 이슈

  • 새 섹션/필드 생성 후 order 값 자동 계산 필요
  • BOM 섹션 타입 특수 처리 (자재명세표)
  • 드래그 앤 드롭 순서 변경 시 API order 업데이트

8.2 향후 개선 사항

  • 실시간 미리보기에서 실제 폼 렌더링 (DynamicItemForm 연동)
  • 필드 유효성 검사 규칙 편집 UI
  • 섹션/필드 복사-붙여넣기
  • 다중 선택 및 일괄 편집
  • 변경사항 diff 뷰어

8.3 Git 관련

  • 현재 .gitignore에 등록되어 있음: src/app/**/dev/page-builder/
  • 정식 배포 시 gitignore에서 제거 필요

9. 관련 파일

9.1 품목기준관리 (연동 대상)

src/app/[locale]/(protected)/master-data/item-master-data-management/page.tsx
src/components/items/ItemMasterDataManagement/
src/lib/api/item-master.ts

9.2 동적 품목 폼 (렌더링 대상)

src/components/items/DynamicItemForm/

10. 참고 문서

  • 초기 기획: src/app/[locale]/(protected)/dev/page-builder/PLAN.md
  • API 문서: claudedocs/api/item-master-api.md (있다면)

마지막 업데이트: 2026-01-22