ERP-node/popdocs/sessions/2026-02-09.md

250 lines
12 KiB
Markdown

# 2026-02-09 작업 기록
## 요약
POP 컴포넌트 정의서 v8.0 완성, 모달 화면 설계 방식 확정, 기존 시스템 호환성 검증, **POP 뷰어 실제 컴포넌트 렌더링 버그 수정**, **POP 뷰어 스크롤 수정**
---
## 완료
### POP 컴포넌트 정의서 작성 (POPUPDATE_2.md)
- [x] 9개 컴포넌트 정의 (pop-text, pop-dashboard, pop-table, pop-button, pop-icon, pop-search, pop-field, pop-lookup, pop-system)
- [x] POP 헌법 8조 작성 (공통 규칙)
- [x] 공통 인프라 설계 (DataSourceConfig, ColumnBinding, JoinConfig, useDataSource, usePopEvent, PopActionConfig)
- [x] 컴포넌트 간 통신 시퀀스 다이어그램 5개 작성
- [x] 구현 우선순위 6단계(Phase 0~6) 정리
- [x] v7.0 POPUPDATE_2.md 생성 및 커밋/푸시 (ksh-v2-work)
### 모달 화면 설계 방식 확정 (v8.0)
- [x] pop-lookup 모달 화면 두 가지 방식 정의
- 방식 A (인라인 모달): DataSourceConfig 기반, 단순 목록 선택용
- 방식 B (외부 화면 참조): 별도 screen_id 연결, 복잡한 화면/재사용 목적
- [x] POP 헌법 제9조 추가 (모달 화면의 설계)
- [x] PopActionConfig의 modal 타입 구체화
- [x] 인라인 vs 외부 참조 시퀀스 다이어그램 추가
### 기존 시스템 호환성 검증
- [x] DB 스키마 확인 (screen_layouts_v2, screen_layouts_pop)
- layout_data JSONB 유연 구조 -> modalConfig 저장 가능
- DB 마이그레이션 불필요
- [x] 백엔드 API 확인 (saveLayoutPop, getLayoutPop)
- 기존 API 그대로 사용 가능
- 새로운 API 불필요
- [x] 프론트엔드 참조 패턴 확인 (TabsWidget)
- 탭의 screenId 참조 방식을 모달에 차용 가능
- 디자이너 탭 내부 컴포넌트 편집 패턴 존재
---
## 대화 핵심
### 컴포넌트 설계 토론 (이전 세션 연속)
**주요 결정들**:
1. **컴포넌트 9개 확정**: 기존 7개에서 pop-lookup, pop-system 추가
2. **역할 분리 원칙**: 조회용(pop-search) vs 저장용(pop-field), 이동(pop-icon) vs 값 선택(pop-lookup)
3. **시스템 설정도 컴포넌트**: pop-system으로 통합 (디자이너가 배치 여부 결정)
4. **모달 화면 이중 방식**: 인라인(설정만으로 완결) + 외부 참조(별도 화면)
### 모달 설계 방식 결정
**사용자 관심사**:
> 참조 화면에서 검색 -> 거래처 모달 -> 거래처 선택 -> 품목 출력, 이런 연결 구조를 어떻게 만들지?
**결론**:
- 단순 선택: pop-lookup 인라인 모달 (설정만으로 완결)
- 복잡한 화면: 별도 POP 화면을 만들어 screenId로 참조
### 호환성 검증
**사용자 요청**:
> 반영하기 전에 실제 백엔드나 프론트엔드 로직상 가능한지, DB 스키마나 컬럼 형식도 맞는지 확인해줘
**검증 결과**:
| 항목 | 결과 |
|------|------|
| DB screen_layouts_v2 | JSONB -> 유연하게 확장 가능 |
| DB screen_layouts_pop | 동일 구조, 모달 화면도 별도 screen_id로 저장 가능 |
| 백엔드 saveLayoutPop/getLayoutPop | 기존 API 그대로 사용 가능 |
| 프론트 TabsWidget | screenId 참조 패턴 이미 존재 (차용 가능) |
| 프론트 detectLinkedModals | 화면 간 참조 관계 추적에 활용 가능 |
---
## 변경 파일
| 파일 | 변경 내용 |
|------|----------|
| `POPUPDATE_2.md` | v7.0 -> v8.0 업데이트 (모달 설계, 헌법 제9조, 호환성 검증) |
---
## 중단점
> **다음 작업**: Phase 0 공통 인프라 구현
> - ColumnBinding, JoinConfig, DataSourceConfig 타입 정의
> - useDataSource 훅 (CRUD 포함)
> - usePopEvent 훅 (데이터 전달 포함)
> - PopActionConfig 타입 정의
> - POPUPDATE_2.md의 "구현 우선순위" 섹션 참조
---
## 다음 작업자 참고
1. **POPUPDATE_2.md**가 컴포넌트 정의서의 최신본 (v8.0)
2. **기존 popdocs/components-spec.md**는 v4 기준이라 갱신 필요
3. **구현 순서**: Phase 0 (공통 인프라) -> Phase 1 (pop-dashboard) -> Phase 2 (pop-button, pop-icon) -> ...
4. **모달 구현 시**: TabsWidget의 screenId 참조 패턴을 참고할 것
---
## pop-dashboard 토의를 위한 사전 정보
> 다음 세션에서 대시보드 컴포넌트를 토의할 때 이 섹션을 먼저 읽으세요.
### 정의서 위치
- POPUPDATE_2.md 240~255행: pop-dashboard 정의 (서브타입, 이벤트, 설정)
- 서브타입: kpi-card, chart, gauge, stat-card
- Phase 1에서 KPI 카드 서브타입부터 구현 예정
### 기존 대시보드 코드 (이미 존재함 - 반드시 확인)
POP 대시보드 프로토타입과 관리자 대시보드가 이미 구현되어 있음. 재사용/참고 판단 필요.
**POP 대시보드 (프로토타입 - 하드코딩):**
| 파일 | 역할 | 핵심 내용 |
|------|------|----------|
| `frontend/components/pop/dashboard/PopDashboard.tsx` | POP 대시보드 메인 | 테마(dark/light), 헤더/KPI/메뉴/활동/공지/푸터 조합 |
| `frontend/components/pop/dashboard/KpiBar.tsx` | KPI 게이지 바 | SVG 원형 게이지 + 퍼센트 + 값 + 단위 (목표달성률, 생산실적, 불량률, 가동설비) |
| `frontend/components/pop/dashboard/types.ts` | 타입 정의 | KpiItem(label, value, unit, percentage, color), MenuItem, ActivityItem 등 |
| `frontend/components/pop/dashboard/data.ts` | 샘플 데이터 | KPI 4종(목표달성률 83%, 생산실적 1250EA, 불량률 0.8%, 가동설비 8/10) |
| `frontend/components/pop/dashboard/MenuGrid.tsx` | 메뉴 그리드 | 생산/자재/품질/설비/안전 5개 메뉴 카드 |
| `frontend/components/pop/dashboard/DashboardHeader.tsx` | 헤더 | 회사명, 사용자, 날씨, 시간, 테마 토글 |
| `frontend/components/pop/dashboard/DashboardFooter.tsx` | 푸터 | 회사명, 버전, 긴급연락처 |
| `frontend/components/pop/dashboard/dashboard.css` | 스타일 | CSS 전용 (Tailwind 아님), dark/light 테마 |
**현재 상태**: 하드코딩 샘플 데이터. API 연동 없음. 컴포넌트 시스템과 미연결.
**관리자 대시보드 (별도 시스템):**
| 파일 | 역할 |
|------|------|
| `frontend/lib/api/dashboard.ts` | 대시보드 CRUD API (dashboardApi) |
| `frontend/contexts/DashboardContext.tsx` | 위젯 간 데이터 공유 (selectedDate) |
| `frontend/components/admin/dashboard/DashboardCanvas.tsx` | 관리자용 대시보드 캔버스 |
| `frontend/components/admin/dashboard/DashboardSaveModal.tsx` | 대시보드 저장 모달 |
| `frontend/components/dashboard/DashboardViewer.tsx` | 대시보드 뷰어 |
| `frontend/lib/registry/components/DashboardRenderer.tsx` | 대시보드 렌더러 (기존 위젯 시스템) |
| `frontend/components/screen/config-panels/DashboardConfigPanel.tsx` | 대시보드 설정 패널 |
**dashboardApi 제공 기능**: CRUD(create/get/update/delete), executeQuery(SQL 실행), getTableSchema(스키마 조회)
### 토의 시 결정해야 할 것
1. **기존 KpiBar.tsx 재사용 여부**: SVG 게이지 UI를 pop-dashboard kpi-card에 그대로 쓸지, 새로 만들지
2. **기존 dashboardApi 활용 여부**: executeQuery/getTableSchema를 useDataSource에서 쓸지, 별도 API를 만들지
3. **하드코딩 -> DataSourceConfig 전환**: 기존 data.ts 샘플을 DB 연동으로 어떻게 바꿀지
4. **기존 dashboard.css -> Tailwind 전환**: POP 대시보드 스타일을 Tailwind/shadcn으로 전환할지
5. **관리자 대시보드와의 관계**: 별도 시스템으로 유지할지, POP 컴포넌트 시스템으로 통합할지
---
---
## POP 뷰어 실제 컴포넌트 렌더링 버그 수정
### 문제
설계 화면(디자이너)에서는 이미지/텍스트/타이틀이 정상 표시되지만, 뷰어(`/pop/screens/4114`)에 접속하면 "pop-text 1", "pop-text 2" 같은 라벨만 보이는 플레이스홀더 상태.
### 원인 (2가지)
| # | 원인 | 파일 | 라인 |
|---|------|------|------|
| A | `renderActualComponent()` 함수가 레지스트리의 실제 컴포넌트를 사용하지 않고 라벨만 반환 | PopRenderer.tsx | 555-564 |
| B | 뷰어 페이지에서 `import "@/lib/registry/pop-components"` 누락으로 레지스트리 초기화 안 됨 | page.tsx | (없음) |
### 수정 내용
| 파일 | 변경 |
|------|------|
| `frontend/app/(pop)/pop/screens/[screenId]/page.tsx` | `import "@/lib/registry/pop-components"` 추가 (PopRenderer import 앞에 배치) |
| `frontend/components/pop/designer/renderers/PopRenderer.tsx` | `renderActualComponent()` 함수를 레지스트리에서 실제 컴포넌트를 조회하여 렌더링하도록 교체 |
### 검증
- 린트 에러 0건
- 자체 검증 5항목 전부 통과 (중복 정의, import 일치, props 일치 등)
### 미해결: datetime 실시간 업데이트 기본값 문제
- `DateTimeDisplay` 컴포넌트의 `isRealtime` 기본값이 `true`가 아닌 문제 발견
- 설정 패널 UI는 `?? true`로 기본 "켜짐" 표시하나, 실제 컴포넌트는 `!config?.isRealtime`으로 `undefined`를 "꺼짐"으로 처리
- DB에 `isRealtime` 필드가 저장되지 않은 기존 데이터에서 시간이 멈춰 보임
- 별도 작업으로 수정 예정
---
## 이번 작업에서 배운 것
### side-effect import 순서의 중요성
`import "@/lib/registry/pop-components"`와 같은 side-effect import는 반드시 해당 레지스트리를 사용하는 컴포넌트(`PopRenderer`) import보다 **앞에** 위치해야 한다. JavaScript 모듈은 import 순서대로 실행되므로, 순서가 뒤바뀌면 빈 레지스트리를 참조할 수 있다.
### UI 기본값과 로직 기본값의 불일치 패턴
설정 패널에서 `config?.isRealtime ?? true`로 UI를 "켜짐"으로 보여주지만, 실제 컴포넌트에서 `!config?.isRealtime`으로 체크하면 `undefined``false`로 평가되어 동작하지 않는다. **UI 기본값과 로직 기본값은 반드시 동일한 패턴(`?? true`)을 사용해야 한다.**
### 다음에 비슷한 작업할 때 주의할 점
- 새 POP 컴포넌트를 레지스트리에 등록할 때, 뷰어 페이지(`page.tsx`)에도 해당 컴포넌트의 초기화 import가 포함되는지 반드시 확인
- optional config 필드의 기본값은 "정의하는 곳(설정 패널)"과 "사용하는 곳(렌더 컴포넌트)" 모두에서 동일하게 처리
---
---
## POP 뷰어 스크롤 수정
### 문제
뷰어(`/pop/screens/4114`)에서 화면 높이를 초과하는 컴포넌트가 잘려서 안 보임. 설계(디자이너)에서는 스크롤되지만 뷰어에서는 스크롤 불가.
### 원인
| # | 컨테이너 (라인) | 현재 클래스 | 문제 |
|---|----------------|-------------|------|
| 1 | 최외곽 (185) | `h-screen ... overflow-hidden` | 넘치는 콘텐츠를 잘라냄 |
| 2 | 컨텐츠 영역 (266) | 프리뷰 모드에만 `overflow-auto` | 일반 모드에서 스크롤 불가 |
| 3 | 백색 배경 (275) | 일반 모드에 `min-h-full` 없음 | 짧은 콘텐츠 시 배경 불완전 |
### 수정 내용
| 라인 | 변경 전 | 변경 후 |
|------|---------|---------|
| 185 | `overflow-hidden` 포함 | `overflow-hidden` 제거 |
| 266 | 프리뷰 모드에만 `overflow-auto` | `overflow-auto` 공통 적용 |
| 275 | 일반 모드 `w-full`만 | `w-full min-h-full` |
### 검증
- 린트 에러 0건
- 새 변수/함수/타입 추가 없음 (CSS 클래스만 변경)
---
## 이번 작업에서 배운 것 (스크롤 수정)
### Flexbox + overflow 조합에서 스크롤 동작 원리
- 부모에 `overflow-hidden`이 있으면, 자식에 아무리 `overflow-auto`를 넣어도 스크롤이 작동하지 않음
- `h-screen` + `overflow-hidden`은 뷰포트 높이로 잘라내는 "뚜껑" 역할
- 스크롤을 허용하려면 부모의 `overflow-hidden`을 제거하고, 실제 스크롤이 필요한 자식에 `overflow-auto`를 넣어야 함
### 프리뷰 모드와 일반 모드의 CSS 분기 주의
- 조건부 클래스(`isPreviewMode ? "overflow-auto" : ""`)로 특정 모드에만 스크롤을 넣으면, 다른 모드에서 스크롤이 빠지는 문제가 발생
- 공통으로 필요한 속성은 조건문 밖에 배치해야 함
---
## 관련 링크
- 컴포넌트 정의서: [POPUPDATE_2.md](../../POPUPDATE_2.md)
- 구현 계획: [PLAN.MD](../../PLAN.MD)
- 이전 세션: [sessions/2026-02-06.md](./2026-02-06.md)