# POP 화면 시스템 아키텍처 **최종 업데이트: 2026-02-04** POP(Point of Production) 화면은 모바일/태블릿 환경에 최적화된 터치 기반 화면 시스템입니다. 이 문서는 POP 화면 구현에 관련된 모든 파일과 그 역할을 정리합니다. --- ## 목차 1. [폴더 구조 개요](#1-폴더-구조-개요) 2. [App 라우팅 (app/(pop))](#2-app-라우팅-apppop) 3. [컴포넌트 (components/pop)](#3-컴포넌트-componentspop) 4. [라이브러리 (lib)](#4-라이브러리-lib) 5. [버전별 레이아웃 시스템](#5-버전별-레이아웃-시스템) 6. [데이터 흐름](#6-데이터-흐름) --- ## 1. 폴더 구조 개요 ``` frontend/ ├── app/(pop)/ # Next.js App Router - POP 라우팅 │ ├── layout.tsx # POP 전용 레이아웃 │ └── pop/ │ ├── page.tsx # POP 대시보드 (메인) │ ├── screens/[screenId]/ # 개별 POP 화면 뷰어 │ ├── test-v4/ # v4 렌더러 테스트 페이지 │ └── work/ # 작업 화면 │ ├── components/pop/ # POP 컴포넌트 라이브러리 │ ├── designer/ # 디자이너 모듈 │ │ ├── panels/ # 편집 패널 (좌측/우측) │ │ ├── renderers/ # 레이아웃 렌더러 │ │ └── types/ # 타입 정의 │ ├── management/ # 화면 관리 모듈 │ └── dashboard/ # 대시보드 모듈 │ └── lib/ ├── api/popScreenGroup.ts # POP 화면 그룹 API ├── registry/PopComponentRegistry.ts # 컴포넌트 레지스트리 └── schemas/popComponentConfig.ts # 컴포넌트 설정 스키마 ``` --- ## 2. App 라우팅 (app/(pop)) ### `app/(pop)/layout.tsx` POP 전용 레이아웃. 데스크톱 레이아웃과 분리되어 터치 최적화 환경 제공. ### `app/(pop)/pop/page.tsx` **경로**: `/pop` POP 메인 대시보드. 메뉴 그리드, KPI, 공지사항 등을 표시. ### `app/(pop)/pop/screens/[screenId]/page.tsx` **경로**: `/pop/screens/:screenId` **역할**: 개별 POP 화면 뷰어 (디자인 모드 X, 실행 모드) **핵심 기능**: - v3/v4 레이아웃 자동 감지 및 렌더링 - 반응형 모드 감지 (태블릿/모바일, 가로/세로) - 프리뷰 모드 지원 (`?preview=true`) ```typescript // 레이아웃 버전 감지 및 렌더링 if (popLayoutV4) { // v4: PopFlexRenderer 사용 } else if (popLayoutV3) { // v3: PopLayoutRenderer 사용 } ``` ### `app/(pop)/pop/test-v4/page.tsx` **경로**: `/pop/test-v4` **역할**: v4 레이아웃 시스템 테스트 페이지 **구성**: - 왼쪽: 컴포넌트 팔레트 (PopPanel) - 중앙: v4 캔버스 (PopCanvasV4) - 오른쪽: 속성 패널 (ComponentEditorPanelV4) --- ## 3. 컴포넌트 (components/pop) ### 3.1 디자이너 모듈 (`designer/`) #### `PopDesigner.tsx` **역할**: POP 화면 디자이너 메인 컴포넌트 **핵심 기능**: - v3/v4 모드 전환 (상단 탭) - 레이아웃 로드/저장 - 컴포넌트 추가/삭제/수정 - 드래그 앤 드롭 (react-dnd) **상태 관리**: ```typescript const [layoutMode, setLayoutMode] = useState<"v3" | "v4">("v3"); const [layoutV3, setLayoutV3] = useState(...); const [layoutV4, setLayoutV4] = useState(...); const [selectedComponentId, setSelectedComponentId] = useState(null); ``` **레이아웃**: ``` ┌─────────────────────────────────────────────────┐ │ 툴바 (뒤로가기, 화면명, 모드전환, 저장) │ ├──────────┬──────────────────────────┬──────────┤ │ 왼쪽 │ 중앙 캔버스 │ 오른쪽 │ │ 패널 │ │ 패널 │ │ (20%) │ (60%) │ (20%) │ │ │ │ (v4만) │ └──────────┴──────────────────────────┴──────────┘ ``` #### `PopCanvas.tsx` (v3용) **역할**: v3 레이아웃용 CSS Grid 기반 캔버스 **핵심 기능**: - 4개 모드 전환 (태블릿 가로/세로, 모바일 가로/세로) - 그리드 기반 컴포넌트 배치 - 드래그로 위치/크기 조정 #### `PopCanvasV4.tsx` (v4용) **역할**: v4 레이아웃용 Flexbox 기반 캔버스 **핵심 기능**: - 단일 캔버스 + 뷰포트 프리뷰 - 3가지 프리셋 (모바일 375px, 태블릿 768px, 데스크톱 1024px) - 너비 슬라이더로 반응형 테스트 - 줌 컨트롤 (30%~150%) ```typescript const VIEWPORT_PRESETS = [ { id: "mobile", label: "모바일", width: 375, height: 667 }, { id: "tablet", label: "태블릿", width: 768, height: 1024 }, { id: "desktop", label: "데스크톱", width: 1024, height: 768 }, ]; ``` --- ### 3.2 패널 모듈 (`designer/panels/`) #### `PopPanel.tsx` **역할**: 왼쪽 패널 - 컴포넌트 팔레트 & 편집 탭 **탭 구성**: 1. **컴포넌트 탭**: 드래그 가능한 6개 컴포넌트 2. **편집 탭**: 선택된 컴포넌트 설정 **컴포넌트 팔레트**: ```typescript const COMPONENT_PALETTE = [ { type: "pop-field", label: "필드", description: "텍스트, 숫자 등 데이터 입력" }, { type: "pop-button", label: "버튼", description: "저장, 삭제 등 액션 실행" }, { type: "pop-list", label: "리스트", description: "데이터 목록" }, { type: "pop-indicator", label: "인디케이터", description: "KPI, 상태 표시" }, { type: "pop-scanner", label: "스캐너", description: "바코드/QR 스캔" }, { type: "pop-numpad", label: "숫자패드", description: "숫자 입력 전용" }, ]; ``` **드래그 아이템 타입**: ```typescript export const DND_ITEM_TYPES = { COMPONENT: "component" }; export interface DragItemComponent { type: typeof DND_ITEM_TYPES.COMPONENT; componentType: PopComponentType; } ``` #### `ComponentEditorPanelV4.tsx` **역할**: v4 오른쪽 패널 - 컴포넌트/컨테이너 속성 편집 **3개 탭**: 1. **크기 탭**: 너비/높이 제약 (fixed/fill/hug) 2. **설정 탭**: 라벨, 타입별 설정 3. **데이터 탭**: 데이터 바인딩 (미구현) **크기 제약 편집**: ```typescript // 너비/높이 모드 type SizeMode = "fixed" | "fill" | "hug"; // fixed: 고정 px 값 // fill: 남은 공간 채움 (flex: 1) // hug: 내용에 맞춤 (width: auto) ``` **컨테이너 설정**: - 방향 (horizontal/vertical) - 줄바꿈 (wrap) - 간격 (gap) - 패딩 (padding) - 정렬 (alignItems, justifyContent) --- ### 3.3 렌더러 모듈 (`designer/renderers/`) #### `PopLayoutRenderer.tsx` (v3용) **역할**: v3 레이아웃을 CSS Grid로 렌더링 **입력**: - `layout`: PopLayoutDataV3 - `modeKey`: 현재 모드 (tablet_landscape 등) - `isDesignMode`: 디자인 모드 여부 #### `PopFlexRenderer.tsx` (v4용) **역할**: v4 레이아웃을 Flexbox로 렌더링 **핵심 기능**: - 컨테이너 재귀 렌더링 - 반응형 규칙 적용 (breakpoint) - 크기 제약 → CSS 스타일 변환 - 컴포넌트 숨김 처리 (hideBelow) **크기 제약 변환 로직**: ```typescript function calculateSizeStyle(size: PopSizeConstraintV4): React.CSSProperties { const style: React.CSSProperties = {}; // 너비 switch (size.width) { case "fixed": style.width = `${size.fixedWidth}px`; style.flexShrink = 0; break; case "fill": style.flex = 1; style.minWidth = size.minWidth || 0; break; case "hug": style.width = "auto"; style.flexShrink = 0; break; } // 높이 switch (size.height) { case "fixed": style.height = `${size.fixedHeight}px`; break; case "fill": style.flexGrow = 1; break; case "hug": style.height = "auto"; break; } return style; } ``` #### `ComponentRenderer.tsx` **역할**: 개별 컴포넌트 렌더링 (디자인 모드용 플레이스홀더) --- ### 3.4 타입 정의 (`designer/types/`) #### `pop-layout.ts` **역할**: POP 레이아웃 전체 타입 시스템 정의 **파일 크기**: 1442줄 (v1~v4 모든 버전 포함) 상세 내용은 [버전별 레이아웃 시스템](#5-버전별-레이아웃-시스템) 참조. --- ### 3.5 관리 모듈 (`management/`) #### `PopCategoryTree.tsx` POP 화면 카테고리 트리 컴포넌트 #### `PopScreenSettingModal.tsx` POP 화면 설정 모달 #### `PopScreenPreview.tsx` POP 화면 미리보기 #### `PopScreenFlowView.tsx` 화면 간 플로우 시각화 --- ### 3.6 대시보드 모듈 (`dashboard/`) | 파일 | 역할 | |------|------| | `PopDashboard.tsx` | 대시보드 메인 컴포넌트 | | `DashboardHeader.tsx` | 상단 헤더 (로고, 시간, 사용자) | | `DashboardFooter.tsx` | 하단 푸터 | | `MenuGrid.tsx` | 메뉴 그리드 (앱 아이콘 형태) | | `KpiBar.tsx` | KPI 요약 바 | | `NoticeBanner.tsx` | 공지 배너 | | `NoticeList.tsx` | 공지 목록 | | `ActivityList.tsx` | 최근 활동 목록 | --- ## 4. 라이브러리 (lib) ### `lib/api/popScreenGroup.ts` **역할**: POP 화면 그룹 API 클라이언트 **API 함수**: ```typescript // 조회 getPopScreenGroups(searchTerm?: string): Promise // 생성 createPopScreenGroup(data: CreatePopScreenGroupRequest): Promise<...> // 수정 updatePopScreenGroup(id: number, data: UpdatePopScreenGroupRequest): Promise<...> // 삭제 deletePopScreenGroup(id: number): Promise<...> // 루트 그룹 확보 ensurePopRootGroup(): Promise<...> ``` **트리 변환 유틸리티**: ```typescript // 플랫 리스트 → 트리 구조 buildPopGroupTree(groups: PopScreenGroup[]): PopScreenGroup[] ``` ### `lib/registry/PopComponentRegistry.ts` **역할**: POP 컴포넌트 중앙 레지스트리 **주요 메서드**: ```typescript class PopComponentRegistry { static registerComponent(definition: PopComponentDefinition): void static unregisterComponent(id: string): void static getComponent(id: string): PopComponentDefinition | undefined static getComponentByUrl(url: string): PopComponentDefinition | undefined static getAllComponents(): PopComponentDefinition[] static getComponentsByCategory(category: PopComponentCategory): PopComponentDefinition[] static getComponentsByDevice(device: "mobile" | "tablet"): PopComponentDefinition[] static searchComponents(query: string): PopComponentDefinition[] } ``` **카테고리**: ```typescript type PopComponentCategory = | "display" // 데이터 표시 (카드, 리스트, 배지) | "input" // 입력 (스캐너, 터치 입력) | "action" // 액션 (버튼, 스와이프) | "layout" // 레이아웃 (컨테이너, 그리드) | "feedback"; // 피드백 (토스트, 로딩) ``` ### `lib/schemas/popComponentConfig.ts` **역할**: POP 컴포넌트 설정 스키마 (Zod 기반) **제공 내용**: - 컴포넌트별 기본값 (`popCardListDefaults`, `popTouchButtonDefaults` 등) - 컴포넌트별 Zod 스키마 (`popCardListOverridesSchema` 등) - URL → 기본값/스키마 조회 함수 --- ## 5. 버전별 레이아웃 시스템 ### v1.0 (deprecated) - 단일 모드 - 섹션 중첩 구조 - CSS Grid ### v2.0 (deprecated) - 4개 모드 (태블릿/모바일 x 가로/세로) - 섹션 + 컴포넌트 분리 - CSS Grid ### v3.0 (현재 기본) - 4개 모드 - **섹션 제거**, 컴포넌트 직접 배치 - CSS Grid ```typescript interface PopLayoutDataV3 { version: "pop-3.0"; layouts: { tablet_landscape: { componentPositions: Record }; tablet_portrait: { componentPositions: Record }; mobile_landscape: { componentPositions: Record }; mobile_portrait: { componentPositions: Record }; }; components: Record; dataFlow: PopDataFlow; settings: PopGlobalSettings; } ``` ### v4.0 (신규, 권장) - **단일 소스** (1번 설계 → 모든 화면 자동 적응) - **제약 기반** (fixed/fill/hug) - **Flexbox** 렌더링 - **반응형 규칙** (breakpoint) ```typescript interface PopLayoutDataV4 { version: "pop-4.0"; root: PopContainerV4; // 루트 컨테이너 (스택) components: Record; dataFlow: PopDataFlow; settings: PopGlobalSettingsV4; } interface PopContainerV4 { id: string; type: "stack"; direction: "horizontal" | "vertical"; wrap: boolean; gap: number; alignItems: "start" | "center" | "end" | "stretch"; justifyContent: "start" | "center" | "end" | "space-between"; padding?: number; responsive?: PopResponsiveRuleV4[]; // 반응형 규칙 children: (string | PopContainerV4)[]; // 컴포넌트 ID 또는 중첩 컨테이너 } interface PopSizeConstraintV4 { width: "fixed" | "fill" | "hug"; height: "fixed" | "fill" | "hug"; fixedWidth?: number; fixedHeight?: number; minWidth?: number; maxWidth?: number; minHeight?: number; } ``` ### 버전 비교표 | 항목 | v3 | v4 | |------|----|----| | 설계 횟수 | 4번 (모드별) | 1번 | | 위치 지정 | col, row, colSpan, rowSpan | 제약 (fill/fixed/hug) | | 렌더링 | CSS Grid | Flexbox | | 반응형 | 수동 (모드 전환) | 자동 (breakpoint 규칙) | | 복잡도 | 높음 | 낮음 | --- ## 6. 데이터 흐름 ### 화면 로드 흐름 ``` [사용자 접속] ↓ [/pop/screens/:screenId] ↓ [screenApi.getLayoutPop(screenId)] ↓ [레이아웃 버전 감지] ├── v4 → PopFlexRenderer ├── v3 → PopLayoutRenderer └── v1/v2 → ensureV3Layout() → v3로 변환 ``` ### 디자이너 저장 흐름 ``` [사용자 편집] ↓ [hasChanges = true] ↓ [저장 버튼 클릭] ↓ [screenApi.saveLayoutPop(screenId, layoutV3 | layoutV4)] ↓ [hasChanges = false] ``` ### 컴포넌트 드래그 앤 드롭 흐름 ``` [PopPanel의 컴포넌트 드래그] ↓ [DragItemComponent { type: "component", componentType: "pop-button" }] ↓ [캔버스 Drop 감지] ↓ [v3: handleDropComponentV3(type, gridPosition)] [v4: handleDropComponentV4(type, containerId)] ↓ [레이아웃 상태 업데이트] ↓ [hasChanges = true] ``` --- ## 관련 문서 - [PLAN.md](./PLAN.md) - 개발 계획 및 로드맵 - [components-spec.md](./components-spec.md) - 컴포넌트 상세 스펙 - [CHANGELOG.md](./CHANGELOG.md) - 변경 이력 --- *이 문서는 POP 화면 시스템의 구조를 이해하고 유지보수하기 위한 참조용으로 작성되었습니다.*