ERP-node/popdocs/ARCHITECTURE.md

530 lines
15 KiB
Markdown
Raw Normal View History

# 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 사용
<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)
**상태 관리**:
```typescript
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%)
```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<PopScreenGroup[]>
// 생성
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<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)
```typescript
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](./PLAN.md) - 개발 계획 및 로드맵
- [components-spec.md](./components-spec.md) - 컴포넌트 상세 스펙
- [CHANGELOG.md](./CHANGELOG.md) - 변경 이력
---
*이 문서는 POP 화면 시스템의 구조를 이해하고 유지보수하기 위한 참조용으로 작성되었습니다.*