feat: 저장 테이블 제외 조건 추가 및 포커싱 개선

- 저장 테이블 쿼리에 table-list와 체크박스가 활성화된 화면, openModalWithData 버튼이 있는 화면을 제외하는 조건 추가
- 화면 그룹 클릭 시 새 그룹 진입 시 포커싱 없이 시작하도록 로직 개선
- 관련 문서에 제외 조건 및 SQL 예시 추가
This commit is contained in:
DDD1542
2026-01-09 17:03:00 +09:00
parent af4072cef1
commit a6569909a2
10 changed files with 4880 additions and 70 deletions
+400 -4
View File
@@ -1117,7 +1117,10 @@ screenSubTables[screenId].subTables.push({
18. [x] 테이블/헤더 둥근 모서리 (rounded-xl, rounded-t-xl)
19. [x] 필터 테이블 조인선 + 참조 테이블 활성화
20. [x] 조인선 색상 상수 통일 (RELATION_COLORS.join.stroke)
21. [ ] **선 교차점 이질감 해결** (계획 중)
21. [x] 필터 연결선 포커싱 제어 (해당 화면 포커싱 시에만 표시)
22. [x] 저장 테이블 제외 조건 추가 (table-list + 체크박스 + openModalWithData)
23. [x] 첫 진입 시 포커싱 없이 시작 (트리에서 화면 클릭 시 그룹만 진입)
24. [ ] **선 교차점 이질감 해결** (계획 중)
22. [ ] 범례 UI 추가 (선택사항)
23. [ ] 엣지 라벨에 관계 유형 표시 (선택사항)
@@ -1142,7 +1145,27 @@ screenSubTables[screenId].subTables.push({
1. `componentConfig.action.type = 'save'` (edit, delete 제외)
2. `componentConfig.targetTable` (modal-repeater-table 등)
3. `action.dataTransfer.targetTable` (데이터 전송 대상)
4. **제외 조건**: `action.targetScreenId IS NOT NULL` (모달 열기 버튼)
**제외 조건:**
1. `action.targetScreenId IS NOT NULL` (모달 열기 버튼)
2. `table-list` + 체크박스 활성화 + `openModalWithData` 버튼이 있는 화면
- 예: "거래처별 품목 추가 모달" - 선택 후 다음 화면으로 넘기는 패턴
- 이 경우 "저장" 버튼은 DB 저장이 아닌 **선택 확인 용도**
```sql
-- 제외 조건 SQL
AND NOT EXISTS (
SELECT 1 FROM screen_layouts sl_list
WHERE sl_list.screen_id = sd.screen_id
AND sl_list.properties->>'componentType' = 'table-list'
AND (sl_list.properties->'componentConfig'->'checkbox'->>'enabled')::boolean = true
)
AND NOT EXISTS (
SELECT 1 FROM screen_layouts sl_modal
WHERE sl_modal.screen_id = sd.screen_id
AND sl_modal.properties->'componentConfig'->'action'->>'type' = 'openModalWithData'
)
```
### 시각적 표현 (구현됨)
@@ -1220,11 +1243,46 @@ transform-origin: top;
- 조인 컬럼 주황색 강조 표시
### 포커싱 제어
- 해당 화면이 포커싱됐을 때만 조인선 활성화
**조인선 (주황색 점선)**
- 해당 화면이 포커싱됐을 때만 활성화
- 다른 화면 포커싱 시 흐리게 처리 (opacity: 0.3)
- 엣지 ID: `edge-filter-join-{screenId}-{sourceTable}-{targetTable}`
**필터 연결선 (파란색 점선)**
- 화면 → 필터 대상 테이블 연결선
- 해당 화면이 포커싱됐을 때만 표시 (opacity: 1)
- 포커스 해제 시 완전히 숨김 (opacity: 0)
- 엣지 ID: `edge-screen-filter-{screenId}-{tableName}`
**styledEdges 처리:**
```typescript
// 필터 조인 엣지 (주황색)
if (edge.id.startsWith("edge-filter-join-")) {
const isActive = focusedScreenId === edgeSourceScreenId;
return {
...edge,
style: {
stroke: isActive ? RELATION_COLORS.join.stroke : RELATION_COLORS.join.strokeLight,
opacity: isActive ? 1 : 0.3,
},
};
}
// 화면 → 필터 대상 테이블 연결선 (파란색)
if (edge.id.startsWith("edge-screen-filter-")) {
const isActive = focusedScreenId === edgeSourceScreenId;
return {
...edge,
style: {
opacity: isActive ? 1 : 0, // 포커스 해제 시 완전히 숨김
},
};
}
```
### 코드 위치
- `ScreenRelationFlow.tsx`: 필터 조인 엣지 생성 로직
- `ScreenRelationFlow.tsx`: 필터 조인 엣지 생성 + styledEdges 처리
- `styledNodes`: 필터 대상 테이블의 조인 참조 테이블 활성화 로직
---
@@ -1245,6 +1303,39 @@ transform-origin: top;
- 기본 색상: `#f97316` (orange-500)
- 강조 색상: `#ea580c` (orange-600)
### 첫 진입 시 포커싱 없이 시작
**문제:**
- 트리에서 화면을 클릭하면 해당 화면이 자동 포커싱됨
- 첫 진입 시 노드 위치가 안정화되기 전에 필터선이 그려져 "망가진" 모습
**해결:**
- 트리에서 화면 클릭 시: 그룹만 진입, 포커싱 없음
- ReactFlow 안에서 화면 클릭 시: 정상 포커싱
**코드 변경:**
```typescript
// page.tsx - onScreenSelectInGroup 콜백
onScreenSelectInGroup={(group, screenId) => {
const isNewGroup = selectedGroup?.id !== group.id;
if (isNewGroup) {
// 새 그룹 진입: 포커싱 없이 시작
setSelectedGroup(group);
setFocusedScreenIdInGroup(null);
} else {
// 같은 그룹 내에서 다른 화면 클릭: 포커싱 유지
setFocusedScreenIdInGroup(screenId);
}
setSelectedScreen(null);
}}
```
**사용자 경험:**
1. 트리에서 화면 클릭 (첫 진입) → 깔끔한 초기 상태 (모든 화면/테이블 동일 밝기)
2. 같은 그룹 내에서 다른 화면 클릭 → 포커싱 + 연결선 표시
3. ReactFlow에서 화면 노드 클릭 → 포커싱 + 연결선 표시
---
## [계획] 선 교차점 이질감 해결
@@ -1286,6 +1377,311 @@ transform-origin: top;
---
## 화면 관리 시스템 업그레이드 현황
### 프로젝트 개요
화면 관리 시스템 업그레이드를 통해 다음 3가지 핵심 기능을 구현:
| 기능 | 설명 | 상태 |
|------|------|------|
| **화면 그룹핑** | 관련 화면들을 그룹으로 묶어 관리 (트리 구조) | 기본 구현 완료 |
| **화면-테이블 관계 시각화** | React Flow를 사용한 노드 기반 시각화 | 기본 구현 완료 |
| **테이블 조인 설정** | 화면 내에서 테이블 간 조인 관계 직접 설정 | 미구현 |
---
### 데이터베이스 테이블 (5개)
| 테이블명 | 용도 | 상태 |
|----------|------|------|
| `screen_groups` | 화면 그룹 정보 | 생성됨 |
| `screen_group_screens` | 화면-그룹 연결 (N:M) | 생성됨 |
| `screen_field_joins` | 화면 필드 조인 설정 | 생성됨 |
| `screen_data_flows` | 화면 간 데이터 흐름 | 생성됨 |
| `screen_table_relations` | 화면-테이블 관계 | 생성됨 |
---
### 백엔드 API 현황
| 파일 | 상태 | 엔드포인트 |
|------|------|-----------|
| `screenGroupController.ts` | 완성됨 | 그룹/화면/조인/흐름/관계 CRUD |
| `screenGroupRoutes.ts` | 완성됨 | `/api/screen-groups/*` |
---
### 프론트엔드 컴포넌트 현황
| 컴포넌트 | 경로 | 상태 |
|----------|------|------|
| `ScreenGroupTreeView.tsx` | `components/screen/` | **완료** |
| `ScreenGroupModal.tsx` | `components/screen/` | **완료** (그룹 CRUD 모달) |
| `ScreenRelationFlow.tsx` | `components/screen/` | **완료** |
| `ScreenNode.tsx` | `components/screen/` | **완료** |
| `FieldJoinPanel.tsx` | `components/screen/panels/` | **완료** (조인 설정) |
| `DataFlowPanel.tsx` | `components/screen/panels/` | **완료** (데이터 흐름 설정) |
| API 클라이언트 | `lib/api/screenGroup.ts` | **완료** |
---
### 구현 완료 목록
| # | 항목 | 완료일 |
|---|------|--------|
| 1 | DB 테이블 5개 생성 및 메타데이터 등록 | - |
| 2 | 백엔드 API 전체 구현 (CRUD) | - |
| 3 | 프론트엔드 API 클라이언트 구현 | - |
| 4 | 트리 뷰 기본 구현 (그룹/화면 표시) | - |
| 5 | React Flow 시각화 기본 구현 (노드 배치, 연결선) | - |
| 6 | 노드 디자인 1차 개선 (정사각형, 흰색 테마) | - |
| 7 | 화면 레이아웃 요약 API 추가 | 2026-01-01 |
| 8 | 화면 노드 미리보기 구현 (폼/그리드/대시보드) | 2026-01-01 |
| 9 | 테이블 노드 개선 (PK/FK 아이콘, 컬럼 목록) | 2026-01-01 |
| 10 | 연결선 스타일 개선 (CRUD 라벨 제거, 1:N 표시) | 2026-01-01 |
---
### 추가 구현 완료 목록
| # | 항목 | 컴포넌트 | 상태 |
|---|------|----------|------|
| 11 | **그룹 관리 UI** | `ScreenGroupModal.tsx` | **완료** |
| 12 | **조인 설정 UI** | `FieldJoinPanel.tsx` (414줄) | **완료** |
| 13 | **데이터 흐름 설정 UI** | `DataFlowPanel.tsx` (462줄) | **완료** |
---
### 미구현 작업 목록 (UI 선택사항)
| # | 항목 | 설명 | 우선순위 |
|---|------|------|----------|
| 1 | **화면 미리보기 고도화** | 실제 컴포넌트 렌더링, 더 상세한 폼 필드 표시 | 낮음 |
| 2 | 범례(Legend) UI 추가 | 관계 유형별 색상 설명 | 낮음 |
| 3 | 뱃지 클릭 시 팝오버 상세정보 | 저장/필터/조인 뱃지 클릭 시 상세 정보 | 낮음 |
| 4 | 선 교차점 이질감 해결 | 배경색 테두리 방식 | 낮음 |
---
## [다음 단계] 노드 플로워 기반 화면-테이블 설정 시스템
### 배경 및 목적
**문제**: 화면 디자이너에 너무 많은 기능이 집중되어 있음
- 조인 설정, 필터 설정, 필드-컬럼 매칭, 저장 테이블 설정 등
**해결책**: 화면 관리 노드 플로워에서 이러한 설정을 **직접** 할 수 있게 함
- 노드 플로워 = 화면-테이블 관계 설정의 **또 다른 UI**
- 시각적으로 설정하고, DB에 저장되면 화면 디자이너/실제 화면에 자동 반영
### 핵심 개념
```
노드 플로워에서 화면/테이블 노드 클릭 (우클릭/더블클릭)
모달/팝업 열림
설정 (조인, 필터, 필드-컬럼 매칭, 저장 테이블 등)
DB 저장 (screen_layouts.properties, screen_field_joins 등)
시각화 자동 반영 (데이터 기반으로 그리니까)
화면 디자이너 자동 반영 (같은 데이터 사용)
실제 화면 자동 반영 (같은 데이터 사용)
```
### 구현 대상 기능
| 기능 | 설명 |
|------|------|
| **테이블 연결 설정** | 화면이 어떤 테이블과 연결되는지 |
| **테이블 조인 설정** | 테이블 간 조인 관계 (LEFT, INNER 등) |
| **필터링 설정** | 마스터-디테일 필터링 관계 |
| **필드-컬럼 매칭** | 화면 필드 ↔ 테이블 컬럼 매핑 |
| **저장 테이블 설정** | 어떤 테이블에 데이터가 저장되는지 |
### 구현 방안 (초안, 미확정)
#### 방안 A: 통합 설정 모달
노드 클릭 시 **하나의 모달**에서 탭으로 모든 설정
```
[화면 노드] 더블클릭
┌─────────────────────────────────┐
│ 수주관리 화면 설정 │
│ │
│ [탭1: 테이블 연결] │
│ [탭2: 조인 설정] │
│ [탭3: 필터 설정] │
│ [탭4: 필드-컬럼 매칭] │
│ [탭5: 저장 테이블] │
│ │
│ [저장] [취소] │
└─────────────────────────────────┘
```
#### 방안 B: 기능별 분리 모달
우클릭 컨텍스트 메뉴로 기능 선택 → 해당 기능 모달 열림
```
[화면 노드] 우클릭
┌─────────────────┐
│ 테이블 연결 설정 │
│ 조인 설정 │
│ 필터 설정 │
│ 필드-컬럼 매칭 │
│ 저장 테이블 설정 │
└─────────────────┘
```
#### 방안 C: 사이드 패널
노드 클릭 시 **오른쪽 패널**에 설정 UI 표시 (모달 없이)
### 현재 상태
| 항목 | 상태 |
|------|------|
| 노드 플로워 시각화 | ✅ 완료 (읽기 전용) |
| DB 테이블 | ✅ 있음 (`screen_field_joins`, `screen_data_flows` 등) |
| 백엔드 API | ✅ 있음 (CRUD) |
| 패널 UI | ✅ 있음 (`FieldJoinPanel`, `DataFlowPanel`) |
| **노드에서 직접 설정** | ✅ **구현 완료** (방안 A) |
---
## 노드에서 직접 설정 기능 (방안 A: 통합 설정 모달)
### 구현 완료 (2026-01-09)
노드 더블클릭 시 통합 설정 모달이 열리며, 4개 탭으로 다양한 설정을 수행할 수 있습니다.
#### 사용법
1. **화면 노드** 또는 **테이블 노드**를 **더블클릭**
2. 통합 설정 모달이 열림
3. 탭 선택하여 설정
4. 저장 후 시각화 자동 새로고침
#### 탭 구성
| 탭 | 기능 | 설명 |
|----|------|------|
| 테이블 연결 | 화면-테이블 관계 설정 | 메인/서브/조회/저장 테이블 지정, CRUD 권한 설정 |
| 조인 설정 | FK-PK 조인 관계 설정 | 저장 테이블의 FK 컬럼 ↔ 조인 테이블의 PK 컬럼 매핑, 표시 컬럼 지정 |
| 데이터 흐름 | 화면 간 데이터 이동 설정 | 소스 화면 → 타겟 화면, 단방향/양방향 흐름 설정 |
| 필드 매핑 | 테이블 컬럼 정보 조회 | 현재 테이블의 컬럼 목록, 데이터 타입, 웹 타입 확인 |
#### 구현 파일
| 파일 | 역할 |
|------|------|
| `frontend/components/screen/NodeSettingModal.tsx` | **새로 생성** - 통합 설정 모달 컴포넌트 |
| `frontend/components/screen/ScreenRelationFlow.tsx` | 노드 더블클릭 이벤트 핸들러 추가 |
#### 주요 코드 변경
**NodeSettingModal.tsx (신규)**
- 4개 탭 컴포넌트 내장 (TableRelationTab, JoinSettingTab, DataFlowTab, FieldMappingTab)
- 기존 API 활용: `getTableRelations`, `getFieldJoins`, `getDataFlows`
- CRUD 연동: `createFieldJoin`, `updateFieldJoin`, `deleteFieldJoin`
- 저장 후 부모 컴포넌트 새로고침 콜백 (`onRefresh`)
**ScreenRelationFlow.tsx (수정)**
```typescript
// 노드 더블클릭 이벤트 핸들러 추가
const handleNodeDoubleClick = useCallback((_event: React.MouseEvent, node: Node) => {
// 화면/테이블 노드 판별 후 모달 오픈
if (node.id.startsWith("screen-")) {
// 화면 노드 처리
} else if (node.id.startsWith("table-")) {
// 테이블 노드 처리
}
setIsSettingModalOpen(true);
}, [screenTableMap, screenSubTableMap]);
// ReactFlow에 이벤트 연결
<ReactFlow
onNodeDoubleClick={handleNodeDoubleClick}
...
/>
// 모달 렌더링
<NodeSettingModal
isOpen={isSettingModalOpen}
onClose={handleSettingModalClose}
onRefresh={handleRefreshVisualization}
...
/>
```
#### 시각화 새로고침 메커니즘
```typescript
// 강제 새로고침용 키
const [refreshKey, setRefreshKey] = useState(0);
// 새로고침 핸들러
const handleRefreshVisualization = useCallback(() => {
setRefreshKey(prev => prev + 1);
}, []);
// useEffect 의존성에 refreshKey 추가
useEffect(() => {
// 데이터 로드 로직
}, [screen, selectedGroup, ..., refreshKey]);
```
---
### 주요 파일 경로
```
backend-node/src/
├── controllers/screenGroupController.ts # 화면 그룹 API
├── routes/screenGroupRoutes.ts # 라우트 정의
frontend/
├── app/(main)/admin/screenMng/screenMngList/page.tsx # 메인 페이지
├── components/screen/
│ ├── ScreenGroupTreeView.tsx # 트리 뷰 (그룹/화면 표시)
│ ├── ScreenGroupModal.tsx # 그룹 추가/수정 모달
│ ├── ScreenRelationFlow.tsx # React Flow 시각화 + 더블클릭 이벤트
│ ├── ScreenNode.tsx # 노드 컴포넌트
│ ├── NodeSettingModal.tsx # **신규** - 통합 설정 모달
│ └── panels/
│ ├── FieldJoinPanel.tsx # 필드 조인 설정 UI (개별 패널)
│ └── DataFlowPanel.tsx # 데이터 흐름 설정 UI (개별 패널)
└── lib/api/screenGroup.ts # API 클라이언트
```
---
## 향후 개선 사항
### 필드 매핑 탭 고도화
현재 필드 매핑 탭은 테이블 컬럼 정보를 조회만 가능합니다. 향후 다음 기능 추가 가능:
1. **컬럼-컴포넌트 바인딩 설정**: 화면 컴포넌트와 DB 컬럼 직접 연결
2. **드래그 앤 드롭**: 시각적 매핑 UI
3. **자동 매핑 추천**: 컬럼명 기반 자동 매핑 제안
### 관계 시각화 연동
설정 저장 후 시각화에 즉시 반영되지만, 다음 개선 가능:
1. **실시간 프리뷰**: 저장 전 미리보기
2. **관계 유형별 색상 커스터마이징**
3. **관계 라벨 표시 옵션**
---
## 관련 문서
- [멀티테넌시 구현 가이드](.cursor/rules/multi-tenancy-guide.mdc)