# 🎨 Graph Pipeline Phase 4: 활용 및 시각화 (Application & Visualization)

이 문서는 P&ID Graph Pipeline의 최종 단계인 **활용 및 시각화**의 상세 구현 계획을 다룹니다. 앞선 단계에서 구축한 [기하학적 데이터 $\rightarrow$ 위상 그래프 $\rightarrow$ 시스템 태그 매핑] 결과물을 결합하여, 운영자가 도면 상에서 실시간 공정 상태를 파악하고 장애 영향도를 분석할 수 있는 인터페이스를 구현하는 것이 목표입니다.

---

## 🔍 [Supervisor Diagnosis] 프로그램 진단 및 개선 권고

**진단 일자:** 2026-05-02
**진단자:** Roo (Software Engineer / Supervisor)

### 1. 종합 진단 결과
현재 계획은 기본적인 데이터 흐름(C# $\rightarrow$ Python $\rightarrow$ Frontend)을 잘 정의하고 있으나, **실제 산업 현장의 대규모 P&ID 도면 적용 시 발생할 수 있는 성능 및 안정성 문제**에 대한 고려가 부족합니다. 특히 실시간 데이터 오버레이의 부하 관리와 분석 결과의 신뢰성 검증 단계가 누락되어 있습니다.

### 2. 주요 진단 항목 및 수정 이유

| 항목 | 진단 결과 | 위험도 | 수정 이유 및 개선 방향 |
|---|---|---|---|
| **데이터 전송 효율** | WebSocket/API 폴링 방식의 단순 나열 | MED | 수천 개의 태그가 포함된 도면에서 개별 폴링/전송 시 네트워크 부하 급증 $\rightarrow$ **태그 그룹화 및 변경분 기반(Delta) 전송** 도입 필요 |
| **프론트엔드 렌더링** | SVG/Canvas 단순 오버레이 | HIGH | 노드 수가 많아질 경우 DOM 요소 증가로 인한 브라우저 랙 발생 $\rightarrow$ **Canvas 기반 렌더링 최적화 및 Viewport 기반 가시 영역 렌더링** 전략 필요 |
| **분석 엔진 신뢰성** | `nx.descendants` 단순 활용 | MED | 단순 위상 전파는 실제 공정의 '흐름 방향(Flow Direction)'과 '밸브 개폐 상태'를 무시함 $\rightarrow$ **엣지 속성(방향성, 상태)을 반영한 가중치 경로 분석**으로 고도화 |
| **에러 핸들링** | Python 브릿지 통신 시 예외 처리 미흡 | LOW | 분석 엔진 다운 시 C# 서버의 블로킹 가능성 $\rightarrow$ **Circuit Breaker 패턴 및 타임아웃 설정** 명시 필요 |
| **사용자 경험(UX)** | 단순 하이라이트 표시 | LOW | 영향도 결과가 많을 경우 도면이 빨간색으로 도배됨 $\rightarrow$ **단계별 영향도(1차, 2차...) 색상 구분 및 필터링** 기능 추가 |

---

## 📦 1. 필수 패키지 및 기술 스택

### 1.1 프론트엔드 (Visualization)
| 기술/라이브러리 | 용도 | 비고 |
|---|---|---|
| `SVG / Canvas API` | P&ID 도면 렌더링 및 데이터 오버레이 | **Canvas API 우선 권장 (대규모 노드 성능 최적화)** |
| `Cytoscape.js` / `D3.js` | 위상 그래프 시각화 및 인터랙티브 탐색 | 그래프 분석 뷰어 |
| `Vue.js` / `React` | 전체 UI 프레임워크 및 상태 관리 | `src/Web` 구조와 통합 |
| `Axios` / `WebSocket` | 실시간 OPC UA 데이터 수신 및 API 통신 | **SignalR (ASP.NET Core) 도입 권장 (실시간 양방향 통신 최적화)** |

### 1.2 백엔드 (API & Analysis)
| 기술/라이브러리 | 용도 | 비고 |
|---|---|---|
| `ASP.NET Core` | Graph API 및 분석 엔드포인트 제공 | `ExperionCrawler` 메인 서버 |
| `NetworkX` (Python) | 영향도 분석 및 경로 추적 알고리즘 실행 | 분석 엔진 (Phase 2 활용) |
| `FastAPI` / `Flask` | Python 분석 엔진과 C# 서버 간의 브릿지 | 분석 마이크로서비스 |

---

## 📐 2. 상세 설계 구조

### 2.1 실시간 데이터 오버레이 (Real-time Overlay)
도면의 좌표 정보와 매핑된 시스템 태그를 연결하여 실시간 값을 표시합니다.
1.  **매핑 데이터 로드:** `(도면노드ID, 시스템태그, 좌표)` 리스트를 프론트엔드로 전달.
2.  **실시간 스트리밍:** `OPC UA` $\rightarrow$ `C# Server` $\rightarrow$ `SignalR Hub` $\rightarrow$ `Frontend`. (**개선: 변경된 값만 전송하는 Delta Update 방식 적용**)
3.  **동적 렌더링:** 태그 값이 변경되면 해당 좌표의 Canvas 요소를 업데이트하거나 툴팁에 현재 값을 표시. (**개선: Viewport 내 요소만 업데이트하여 CPU 부하 감소**)

### 2.2 영향도 분석 엔진 (Impact Analysis Engine)
특정 설비의 이상 발생 시 하류(Downstream) 영향을 계산합니다.
1.  **분석 요청:** 사용자가 도면에서 특정 노드(예: 펌프 P-101)를 클릭.
2.  **그래프 탐색:** Python 분석 엔진에서 `nx.descendants(G, 'P-101')` 실행. (**개선: 엣지의 `flow_direction` 속성을 확인하여 실제 유체 흐름 방향으로만 전파 계산**)
3.  **결과 반환:** 영향받는 모든 노드 ID 리스트, 경로(Path), 그리고 **영향 단계(Depth)**를 반환.
4.  **시각적 강조:** 도면 상에서 영향 경로를 단계별 색상(예: 1차-진한 빨강, 2차-연한 빨강)으로 하이라이트 처리.

---

## 💻 3. 실제 구현 코딩 가이드 (Example)

### 3.1 [Backend] 영향도 분석 API (C# $\rightarrow$ Python Bridge)
```csharp
// src/Web/Controllers/PidGraphController.cs

// 1. 분석 상태 추적을 위한 DTO
public record AnalysisStatus(string taskId, double progress, string status, string message);

// 2. 실시간 진행 상태 조회 API (Phase 5 병렬 처리 반영)
[HttpGet("status/{taskId}")]
public async Task<IActionResult> GetAnalysisStatus(string taskId)
{
    // Orchestrator가 관리하는 작업 상태 저장소(Redis/MemoryCache)에서 조회
    var status = await _statusService.GetStatusAsync(taskId);
    if (status == null) return NotFound();
    
    return Ok(new {
        taskId = status.TaskId,
        progress = status.Progress, // 0.0 ~ 1.0
        status = status.Status,     // "Processing", "Completed", "Failed"
        message = status.Message
    });
}

[HttpGet("impact/{nodeId}")]
public async Task<IActionResult> GetImpactAnalysis(string nodeId)
{
    try 
    {
        // Python 분석 마이크로서비스에 요청 (Timeout 및 Circuit Breaker 적용 권장)
        var response = await _httpClient.GetAsync($"http://python-analysis-api/impact/{nodeId}");
        response.EnsureSuccessStatusCode();
        var result = await response.Content.ReadFromJsonAsync<ImpactResult>();
        
        return Ok(result);
    }
    catch (HttpRequestException ex)
    {
        // 분석 엔진 연결 실패 시 적절한 에러 메시지 반환
        return StatusCode(503, new { error = "Analysis Engine is currently unavailable", details = ex.Message });
    }
}
```

### 3.2 [Frontend] Canvas 기반 데이터 오버레이 및 진행률 표시 (JavaScript)
```javascript
// src/Web/wwwroot/js/pid-viewer.js

// 1. 실시간 값 업데이트 (Canvas 최적화 버전)
async function updateRealtimeValues(tagData) {
    // tagData: { "TAG_01": { value: 10.5, status: "OK" }, ... }
    
    const ctx = canvas.getContext('2d');
    
    for (const [tag, data] of Object.entries(tagData)) {
        const node = nodeMap.get(tag); // 좌표 정보 맵
        if (node && isInViewport(node)) {
            // 뷰포트 내에 있을 때만 렌더링
            ctx.fillStyle = data.value > threshold ? 'red' : 'green';
            ctx.beginPath();
            ctx.arc(node.x, node.y, 5, 0, Math.PI * 2);
            ctx.fill();
            
            // 툴팁 데이터 업데이트
            updateTooltipData(tag, data.value);
        }
    }
}

// 2. 분석 진행 상태 표시 (Phase 5 병렬 처리 반영)
async function trackAnalysisProgress(taskId) {
    const progressBar = document.getElementById('analysis-progress-bar');
    const statusText = document.getElementById('analysis-status-text');

    const pollStatus = async () => {
        try {
            const response = await fetch(`/api/pid/status/${taskId}`);
            const data = await response.json();

            // 프로그레스 바 업데이트
            progressBar.style.width = `${data.progress * 100}%`;
            statusText.innerText = `분석 중... ${Math.round(data.progress * 100)}% (${data.message})`;

            if (data.status !== 'Completed' && data.status !== 'Failed') {
                setTimeout(pollStatus, 1000); // 1초 간격 폴링
            } else {
                statusText.innerText = data.status === 'Completed' ? '분석 완료!' : '분석 실패';
            }
        } catch (e) {
            statusText.innerText = '상태 조회 중 오류 발생';
        }
    };

    pollStatus();
}
```

### 3.3 [Analysis] 흐름 방향 반영 경로 추적 (Python)
```python
import networkx as nx

def get_propagation_path_with_flow(graph, start_node):
    """
    단순 descendants가 아닌, 엣지의 방향성(flow_direction)과 
    상태(valve_open)를 고려한 실제 영향 전파 경로 추출
    """
    # 1. 유효한 엣지만 필터링 (방향이 맞고 밸브가 열려있는 경로)
    valid_edges = [
        (u, v, d) for u, v, d in graph.edges(data=True) 
        if d.get('flow_direction') == 'forward' and d.get('valve_status') == 'open'
    ]
    filtered_graph = nx.DiGraph()
    filtered_graph.add_edges_from(valid_edges)
    
    # 2. 전파 단계별 노드 추출 (BFS)
    propagation_levels = nx.single_source_shortest_path_length(filtered_graph, start_node)
    
    # { node_id: distance } 형태로 반환하여 프론트엔드에서 색상 구분 가능하게 함
    return propagation_levels

# 예: P-101에서 시작되는 실제 유체 흐름 기반 영향도 분석
impact_map = get_propagation_path_with_flow(topology_graph, "P-101")
```

---

## 🚀 4. Phase 4 완료 기준 (Definition of Done)

- [ ] P&ID 도면(Canvas) 위에 **실시간 OPC UA 값**이 정확한 좌표에 표시되며, 뷰포트 최적화가 적용되었는가?
- [ ] **SignalR 또는 Delta Update**를 통해 네트워크 부하를 최소화하며 실시간 데이터를 수신하는가?
- [ ] 병렬 처리 중인 분석 작업의 **진행 상태(Progress Bar)**가 UI에 실시간으로 반영되는가?
- [ ] 특정 노드 클릭 시 **유체 흐름 방향이 반영된 영향도 분석** 결과가 단계별 색상으로 하이라이트 되는가?
- [ ] C# 서버와 Python 엔진 간 통신에 **타임아웃 및 예외 처리**가 적용되어 시스템 안정성이 확보되었는가?
- [ ] 전체 파이프라인(`추출 $\rightarrow$ 모델링 $\rightarrow$ 매핑 $\rightarrow$ 시각화`)이 통합되어 동작하는가?
