Files
ExperionCrawler/.rooBackup/2026-05-02_pipeline_sync/Graph_Pipeline_Phase4.md

10 KiB

🎨 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)

// 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)

// 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)

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$ 시각화)이 통합되어 동작하는가?