ERP-node/popdocs/ARCHITECTURE.md

15 KiB

POP 화면 시스템 아키텍처

최종 업데이트: 2026-02-04

POP(Point of Production) 화면은 모바일/태블릿 환경에 최적화된 터치 기반 화면 시스템입니다. 이 문서는 POP 화면 구현에 관련된 모든 파일과 그 역할을 정리합니다.


목차

  1. 폴더 구조 개요
  2. App 라우팅 (app/(pop))
  3. 컴포넌트 (components/pop)
  4. 라이브러리 (lib)
  5. 버전별 레이아웃 시스템
  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)
// 레이아웃 버전 감지 및 렌더링
if (popLayoutV4) {
  // v4: PopFlexRenderer 사용
  <PopFlexRenderer layout={popLayoutV4} viewportWidth={...} />
} 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

역할: 왼쪽 패널 - 컴포넌트 팔레트 & 편집 탭

탭 구성:

  1. 컴포넌트 탭: 드래그 가능한 6개 컴포넌트
  2. 편집 탭: 선택된 컴포넌트 설정

컴포넌트 팔레트:

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개 탭:

  1. 크기 탭: 너비/높이 제약 (fixed/fill/hug)
  2. 설정 탭: 라벨, 타입별 설정
  3. 데이터 탭: 데이터 바인딩 (미구현)

크기 제약 편집:

// 너비/높이 모드
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)

크기 제약 변환 로직:

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 모든 버전 포함)

상세 내용은 버전별 레이아웃 시스템 참조.


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]

관련 문서


이 문서는 POP 화면 시스템의 구조를 이해하고 유지보수하기 위한 참조용으로 작성되었습니다.