16 KiB
POP 화면 시스템 아키텍처
최종 업데이트: 2026-02-04
POP(Point of Production) 화면은 모바일/태블릿 환경에 최적화된 터치 기반 화면 시스템입니다. 이 문서는 POP 화면 구현에 관련된 모든 파일과 그 역할을 정리합니다.
목차
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) - 뷰포트 감지 및 비율 스케일링
// 뷰포트 너비 감지 (최대 1366px 제한)
const [viewportWidth, setViewportWidth] = useState(1024);
useEffect(() => {
const updateViewportWidth = () => {
setViewportWidth(Math.min(window.innerWidth, 1366));
};
updateViewportWidth();
window.addEventListener("resize", updateViewportWidth);
return () => window.removeEventListener("resize", updateViewportWidth);
}, []);
// 레이아웃 버전 감지 및 렌더링
if (popLayoutV4) {
// v4: PopFlexRenderer 사용 (비율 스케일링 적용)
<div className="mx-auto h-full" style={{ maxWidth: 1366 }}>
<PopFlexRenderer
layout={popLayoutV4}
viewportWidth={viewportWidth}
isDesignMode={false} // 뷰어에서 스케일 적용
/>
</div>
} else if (popLayoutV3) {
// v3: PopLayoutRenderer 사용
<PopLayoutV3Renderer layout={popLayoutV3} modeKey={currentModeKey} />
}
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)
상태 관리:
const [layoutMode, setLayoutMode] = useState<"v3" | "v4">("v3");
const [layoutV3, setLayoutV3] = useState<PopLayoutDataV3>(...);
const [layoutV4, setLayoutV4] = useState<PopLayoutDataV4>(...);
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null);
레이아웃:
┌─────────────────────────────────────────────────┐
│ 툴바 (뒤로가기, 화면명, 모드전환, 저장) │
├──────────┬──────────────────────────┬──────────┤
│ 왼쪽 │ 중앙 캔버스 │ 오른쪽 │
│ 패널 │ │ 패널 │
│ (20%) │ (60%) │ (20%) │
│ │ │ (v4만) │
└──────────┴──────────────────────────┴──────────┘
PopCanvas.tsx (v3용)
역할: v3 레이아웃용 CSS Grid 기반 캔버스
핵심 기능:
- 4개 모드 전환 (태블릿 가로/세로, 모바일 가로/세로)
- 그리드 기반 컴포넌트 배치
- 드래그로 위치/크기 조정
PopCanvasV4.tsx (v4용)
역할: v4 레이아웃용 Flexbox 기반 캔버스
핵심 기능:
- 단일 캔버스 + 뷰포트 프리뷰
- 3가지 프리셋 (모바일 375px, 태블릿 768px, 데스크톱 1024px)
- 너비 슬라이더로 반응형 테스트
- 줌 컨트롤 (30%~150%)
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
역할: 왼쪽 패널 - 컴포넌트 팔레트 & 편집 탭
탭 구성:
- 컴포넌트 탭: 드래그 가능한 6개 컴포넌트
- 편집 탭: 선택된 컴포넌트 설정
컴포넌트 팔레트:
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: "숫자 입력 전용" },
];
드래그 아이템 타입:
export const DND_ITEM_TYPES = { COMPONENT: "component" };
export interface DragItemComponent {
type: typeof DND_ITEM_TYPES.COMPONENT;
componentType: PopComponentType;
}
ComponentEditorPanelV4.tsx
역할: v4 오른쪽 패널 - 컴포넌트/컨테이너 속성 편집
3개 탭:
- 크기 탭: 너비/높이 제약 (fixed/fill/hug)
- 설정 탭: 라벨, 타입별 설정
- 데이터 탭: 데이터 바인딩 (미구현)
크기 제약 편집:
// 너비/높이 모드
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: PopLayoutDataV3modeKey: 현재 모드 (tablet_landscape 등)isDesignMode: 디자인 모드 여부
PopFlexRenderer.tsx (v4용)
역할: v4 레이아웃을 Flexbox로 렌더링 + 비율 스케일링
핵심 기능:
- 컨테이너 재귀 렌더링
- 반응형 규칙 적용 (breakpoint)
- 크기 제약 → CSS 스타일 변환
- 컴포넌트 숨김 처리 (hideBelow)
- 비율 스케일링 (뷰어 모드)
비율 스케일링 시스템:
// 기준 너비 (10인치 태블릿 가로)
const BASE_VIEWPORT_WIDTH = 1024;
// 스케일 계산 (디자인 모드: 1, 뷰어 모드: 실제 비율)
const scale = isDesignMode ? 1 : viewportWidth / BASE_VIEWPORT_WIDTH;
// 예시: 12인치(1366px) 화면
// scale = 1366 / 1024 = 1.33
// 200px 컴포넌트 → 266px
크기 제약 변환 로직 (스케일 적용):
function calculateSizeStyle(
size: PopSizeConstraintV4,
settings: PopGlobalSettingsV4,
scale: number = 1 // 스케일 파라미터 추가
): React.CSSProperties {
const style: React.CSSProperties = {};
// 너비 (스케일 적용)
switch (size.width) {
case "fixed":
style.width = `${size.fixedWidth * scale}px`;
style.flexShrink = 0;
break;
case "fill":
style.flex = 1;
style.minWidth = size.minWidth ? `${size.minWidth * scale}px` : 0;
break;
case "hug":
style.width = "auto";
style.flexShrink = 0;
break;
}
// 높이 (스케일 적용)
switch (size.height) {
case "fixed":
style.height = `${size.fixedHeight * scale}px`;
break;
case "fill":
style.flexGrow = 1;
break;
case "hug":
style.height = "auto";
break;
}
return style;
}
컨테이너 스케일 적용:
// gap, padding도 스케일 적용
const scaledGap = gap * scale;
const scaledPadding = padding ? padding * scale : undefined;
ComponentRenderer.tsx
역할: 개별 컴포넌트 렌더링 (디자인 모드용 플레이스홀더)
3.4 타입 정의 (designer/types/)
pop-layout.ts
역할: POP 레이아웃 전체 타입 시스템 정의
파일 크기: 1442줄 (v1~v4 모든 버전 포함)
상세 내용은 버전별 레이아웃 시스템 참조.
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 함수:
// 조회
getPopScreenGroups(searchTerm?: string): Promise<PopScreenGroup[]>
// 생성
createPopScreenGroup(data: CreatePopScreenGroupRequest): Promise<...>
// 수정
updatePopScreenGroup(id: number, data: UpdatePopScreenGroupRequest): Promise<...>
// 삭제
deletePopScreenGroup(id: number): Promise<...>
// 루트 그룹 확보
ensurePopRootGroup(): Promise<...>
트리 변환 유틸리티:
// 플랫 리스트 → 트리 구조
buildPopGroupTree(groups: PopScreenGroup[]): PopScreenGroup[]
lib/registry/PopComponentRegistry.ts
역할: POP 컴포넌트 중앙 레지스트리
주요 메서드:
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[]
}
카테고리:
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
interface PopLayoutDataV3 {
version: "pop-3.0";
layouts: {
tablet_landscape: { componentPositions: Record<string, GridPosition> };
tablet_portrait: { componentPositions: Record<string, GridPosition> };
mobile_landscape: { componentPositions: Record<string, GridPosition> };
mobile_portrait: { componentPositions: Record<string, GridPosition> };
};
components: Record<string, PopComponentDefinition>;
dataFlow: PopDataFlow;
settings: PopGlobalSettings;
}
v4.0 (신규, 권장)
- 단일 소스 (1번 설계 → 모든 화면 자동 적응)
- 제약 기반 (fixed/fill/hug)
- Flexbox 렌더링
- 반응형 규칙 (breakpoint)
interface PopLayoutDataV4 {
version: "pop-4.0";
root: PopContainerV4; // 루트 컨테이너 (스택)
components: Record<string, PopComponentDefinitionV4>;
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 - 개발 계획 및 로드맵
- components-spec.md - 컴포넌트 상세 스펙
- CHANGELOG.md - 변경 이력
이 문서는 POP 화면 시스템의 구조를 이해하고 유지보수하기 위한 참조용으로 작성되었습니다.