# P&ID 재설계 - 코딩 계획

> 작성일: 2026-05-04
> 상태: 진행 중
> 목표: `No-10_Plant_PID.dxf`(28,819 엔티티) 처리 시 30분 타임아웃 해결

---

## 현황 요약

| 단계 | 내용 | 상태 |
|------|------|------|
| Step 1 | 현황 분석 (DXF 구조 파악) | ✅ 완료 |
| Step 2 | 성공 테스트 분석 (분할+병렬 성공 요인) | ✅ 완료 |
| Step 3 | 레전드 페이지 분석 (legend_parser.py 생성) | ✅ 완료 |
| Step 4 | 해결 방향 정의 | ✅ 완료 |
| Step 5~10 | 구현 (아래 상세 계획) | 🔲 미시작 |

---

## 핵심 전략

1. **도면 분할** — 한 DXF 파일 내 여러 도면을 좌표 기반으로 분리 (9개 도면 → 각각 독립 처리)
2. **계측기 유형별 병렬 LLM 호출** — Sensor/Valve/System/Gauge/Pump 동시 처리
3. **위치 정보 저장** — 태그의 DXF 상 좌표 + 근처 텍스트
4. **AREA 그룹핑** — 태그명에서 플랜트 번호 유추

---

## 변경 대상 파일

| 파일 | 변경 내용 |
|------|-----------|
| `mcp-server/pipeline/extractor.py` | 도면 분할 로직 추가 |
| `mcp-server/worker/pid_worker.py` | 도면 분할 + 병렬 LLM 호출 |
| `mcp-server/pipeline/mapper.py` | 기존 유지 (이미 배치 처리 구현됨) |
| `mcp-server/pipeline/topology.py` | 기존 유지 (이미 SpatialGrid 구현됨) |
| `mcp-server/pipeline/legend_parser.py` | 기존 유지 (이미 계측기 그룹 정의됨) |

---

## 상세 코딩 계획

### Phase 1: 도면 분할 로직 (extractor.py)

#### 1-1. 도면 분할 테스트 스크립트 작성
- **파일**: `test_drawing_split.py` (신규)
- **목표**: `No-10_Plant_PID.dxf`를 TITLE 레이어 LINE으로 분할하는 로직 프로토타입
- **작업 내용**:
  - ezdxf로 DXF 로드
  - TITLE 레이어의 LINE 엔티티 탐색
  - 수직 LINE(X 좌표가 일정)을 도면 경계로 감지
  - 각 도면별 X/Y 범위 출력
- **검증**: 9개 도면 영역이 올바르게 분리되는지 확인
- **완료 기준**: 콘솔에 9개 도면의 X/Y 범위가 출력됨

#### 1-2. PidGeometricExtractor에 도면 분할 메서드 추가
- **파일**: `mcp-server/pipeline/extractor.py`
- **목표**: `split_drawings()` 메서드 추가
- **작업 내용**:
  - `split_drawings() -> List[DrawingRegion]` 메서드 추가
  - DrawingRegion 데이터클래스 정의 (drawing_no, x_min, x_max, y_min, y_max)
  - TITLE 레이어 LINE 기반 경계 감지
  - 레전드 페이지(X < 2000) 제외
  - FFD 페이지도 제외 (최상단 텍스트 기반)
- **완료 기준**: `split_drawings()` 호출 시 9개 DrawingRegion 반환

#### 1-3. 영역별 추출 메서드 추가
- **파일**: `mcp-server/pipeline/extractor.py`
- **목표**: `extract_region()` 메서드 추가
- **작업 내용**:
  - `extract_region(region: DrawingRegion) -> List[GeometricEntity]` 메서드 추가
  - bbox가 region 범위 내에 있는 엔티티만 필터링
  - 기존 `extract_and_save()` 로직 재사용
- **완료 기준**: 각 도면별 엔티티 수 합계가 전체 엔티티 수와 일치

#### 1-4. 도면 분할 통합 테스트
- **파일**: `test_drawing_split.py`
- **목표**: 전체 파이프라인 테스트
- **작업 내용**:
  - DXF 로드 → 분할 → 영역별 추출 → 결과 검증
  - 각 도면별 엔티티 수, 태그 수 확인
  - 처리 시간 측정
- **완료 기준**: 9개 도면 모두 정상 추출, 총 처리 시간 < 30초

---

### Phase 2: 계측기 유형별 병렬 LLM 호출 (pid_worker.py)

#### 2-1. 계측기 유형별 프롬프트 정의
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: 각 유형별 전용 프롬프트 상수 정의
- **작업 내용**:
  - `_SENSOR_EXTRACT_SYSTEM` — FT, FIT, LT, PT, TE, PG, LG, TG 추출
  - `_VALVE_EXTRACT_SYSTEM` — FCV, TCV, LCV, PCV, XV, FV, LV, PV, TV 추출
  - `_SYSTEM_EXTRACT_SYSTEM` — LI, PI, TI, FIQ, FICQ, TICA, PICA, LICA 추출
  - `_GAUGE_EXTRACT_SYSTEM` — PG, TG, LG 추출
  - `_PUMP_EXTRACT_SYSTEM` — P-10101, VP-10117, DP-10101 등 펌프 추출
  - 각 프롬프트는 `max_tokens=65536` 적용
- **완료 기준**: 5개 프롬프트 상수 정의 완료

#### 2-2. 유형별 추출 함수 작성
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: `_extract_tags_by_type()` 함수 추가
- **작업 내용**:
  - `_extract_tags_by_type(text: str, type_name: str, system_prompt: str) -> List[dict]` 함수
  - LLM 호출 → JSON 파싱 → 태그 목록 반환
  - `max_tokens=65536` 적용
  - finish_reason=length 복구 로직 포함
- **완료 기준**: 단일 유형 추출 테스트 통과

#### 2-3. 병렬 호출 로직 구현
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: `_extract_all_types_parallel()` async 함수 추가
- **작업 내용**:
  - `asyncio.gather()`로 5개 유형 동시 호출
  - 각 유형별 결과 통합
  - 중복 태그 제거 (tagNo 기준)
- **완료 기준**: 5개 유형 병렬 호출 테스트, 총 처리 시간 < 120초

#### 2-4. `_build_pid_graph_parallel()` 리팩토링
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: 기존 함수를 도면 분할 + 병렬 LLM 호출로 변경
- **작업 내용**:
  - Phase 1: 도면 분할 (extractor.split_drawings())
  - Phase 2: 각 도면별 기하 추출 (extractor.extract_region())
  - Phase 3: 각 도면별 유형별 병렬 LLM 호출
  - Phase 4: 결과 통합 + 그래프 빌드
  - Phase 5: 저장
- **완료 기준**: 기존 API 호환 유지, 처리 시간 30분 → 5분 이내

#### 2-5. 병렬 처리 통합 테스트
- **파일**: `test_parallel_extraction.py` (신규)
- **목표**: 전체 병렬 처리 파이프라인 테스트
- **작업 내용**:
  - `No-10_Plant_PID.dxf` 전체 처리
  - 각 단계별 시간 측정
  - 추출된 태그 수, 매핑 수 확인
- **완료 기준**: 전체 처리 < 5분, 태그 추출 수 > 기존

---

### Phase 3: 위치 정보 저장

#### 3-1. 위치 정보 스키마 정의
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: 태그 추출 결과에 위치 정보 포함
- **작업 내용**:
  - 각 태그에 `bbox` (min_x, min_y, max_x, max_y) 필드 추가
  - `drawing_no` (도면 번호) 필드 추가
  - `nearby_text` (근처 텍스트) 필드 추가
- **완료 기준**: 추출 결과 JSON에 위치 정보 포함

#### 3-2. 근처 텍스트 추출 로직
- **파일**: `mcp-server/pipeline/extractor.py`
- **목표**: `get_nearby_text()` 메서드 추가
- **작업 내용**:
  - 특정 좌표 주변 threshold 이내 TEXT 엔티티 검색
  - SpatialGrid 활용 (O(1) 조회)
  - 상하좌우 위치 파악 (direction 필드)
- **완료 기준**: 태그 주변 텍스트 정상 추출

#### 3-3. 위치 정보 통합 테스트
- **파일**: `test_location_info.py` (신규)
- **목표**: 위치 정보 정확도 검증
- **작업 내용**:
  - 알려진 태그 위치와 추출된 위치 비교
  - 근처 텍스트 정확도 확인
- **완료 기준**: 위치 정보 정확도 > 90%

---

### Phase 4: AREA 그룹핑

#### 4-1. AREA 추출 로직 개선
- **파일**: `mcp-server/pipeline/legend_parser.py`
- **목표**: `extract_area_from_tag()` 정확도 향상
- **작업 내용**:
  - FICQ-6113 → "6" (6호 플랜트)
  - FICQ-10113 → "10" (10호 플랜트)
  - 패턴 매칭 개선 (정규식 튜닝)
- **완료 기준**: 테스트 케이스 10개 모두 정확

#### 4-2. AREA별 그룹핑 함수
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: `_group_by_area()` 함수 추가
- **작업 내용**:
  - 추출된 태그 목록을 AREA별로 그룹핑
  - AREA 번호가 없는 태그는 "unknown" 그룹
  - 그룹별 통계 출력
- **완료 기준**: AREA별 그룹핑 결과 정상 출력

---

### Phase 5: Experion 태그 매핑

#### 5-1. 기존 매핑 로직 확인
- **파일**: `mcp-server/pipeline/mapper.py`
- **목표**: 기존 IntelligentMapper 동작 확인
- **작업 내용**:
  - `_batch_gather()` 배치 처리 확인 (이미 구현됨)
  - RapidFuzz 기반 후보 추출 확인
  - LLM 기반 최종 매핑 확인
- **완료 기준**: 기존 매핑 정확도 확인

#### 5-2. 매핑 결과 통합
- **파일**: `mcp-server/worker/pid_worker.py`
- **목표**: `_build_pid_graph_parallel()`에 매핑 결과 통합
- **작업 내용**:
  - Phase 3 결과 (추출된 태그)를 IntelligentMapper에 전달
  - 매핑 결과를 그래프에 추가
  - 매핑 통계 출력
- **완료 기준**: 매핑 결과 그래프에 정상 반영

---

### Phase 6: UI 연동

#### 6-1. API 엔드포인트 확인
- **파일**: `src/Web/Controllers/PidController.cs`
- **목표**: 기존 API 엔드포인트 확인
- **작업 내용**:
  - 태그 검색 API 확인
  - 위치 정보 반환 여부 확인
- **완료 기준**: API 스펙 파악

#### 6-2. 위치 정보 API 추가
- **파일**: `src/Web/Controllers/PidController.cs`
- **목표**: 태그 위치 조회 API 추가
- **작업 내용**:
  - `GET /api/pid/tags/{tagName}/location` 엔드포인트 추가
  - DXF 좌표, 도면 번호, 근처 텍스트 반환
  - 현재 실시간 값 연동
- **완료 기준**: API 테스트 통과

#### 6-3. 프론트엔드 UI 수정
- **파일**: `src/Web/wwwroot/js/app.js`
- **목표**: 태그 검색 시 위치 표시
- **작업 내용**:
  - 태그 검색 결과에 위치 정보 표시
  - "6호 정제탑, 밑에서 3번째 온도 센서입니다. 현재 온도 105도" 형식
  - DXF 도면 상 위치 시각화 (선택사항)
- **완료 기준**: UI에서 위치 정보 확인 가능

---

## 실행 순서 및 의존성

```
Phase 1 (도면 분할)
  ├── 1-1 → 1-2 → 1-3 → 1-4  (순차)
  │
Phase 2 (병렬 LLM)
  ├── 2-1 → 2-2 → 2-3 → 2-4 → 2-5  (순차, Phase 1 완료 후)
  │
Phase 3 (위치 정보)
  ├── 3-1 → 3-2 → 3-3  (순차, Phase 2 완료 후)
  │
Phase 4 (AREA 그룹핑)
  ├── 4-1 → 4-2  (순차, 독립 실행 가능)
  │
Phase 5 (매핑 통합)
  ├── 5-1 → 5-2  (순차, Phase 2+3 완료 후)
  │
Phase 6 (UI 연동)
  ├── 6-1 → 6-2 → 6-3  (순차, Phase 5 완료 후)
```

---

## 각 단계 완료 기준

| 단계 | 완료 기준 | 예상 시간 |
|------|-----------|-----------|
| 1-1 | 9개 도면 영역 콘솔 출력 | 30분 |
| 1-2 | `split_drawings()` 9개 Region 반환 | 1시간 |
| 1-3 | `extract_region()` 정상 동작 | 30분 |
| 1-4 | 전체 분할 테스트 통과 | 30분 |
| 2-1 | 5개 프롬프트 상수 정의 | 30분 |
| 2-2 | 단일 유형 추출 테스트 통과 | 1시간 |
| 2-3 | 5개 유형 병렬 호출 테스트 | 1시간 |
| 2-4 | `_build_pid_graph_parallel()` 리팩토링 완료 | 2시간 |
| 2-5 | 전체 병렬 처리 테스트 통과 | 1시간 |
| 3-1 | 위치 정보 JSON 필드 추가 | 30분 |
| 3-2 | `get_nearby_text()` 구현 | 1시간 |
| 3-3 | 위치 정보 정확도 검증 | 30분 |
| 4-1 | AREA 추출 테스트 10개 통과 | 30분 |
| 4-2 | AREA별 그룹핑 결과 출력 | 30분 |
| 5-1 | 기존 매핑 정확도 확인 | 30분 |
| 5-2 | 매핑 결과 그래프 반영 | 1시간 |
| 6-1 | API 스펙 파악 | 30분 |
| 6-2 | 위치 조회 API 추가 | 1시간 |
| 6-3 | UI 수정 완료 | 1시간 |

**총 예상 시간: 약 18시간**

---

## 체크리스트

### Phase 1: 도면 분할
- [ ] 1-1. 도면 분할 테스트 스크립트 작성
- [ ] 1-2. PidGeometricExtractor에 도면 분할 메서드 추가
- [ ] 1-3. 영역별 추출 메서드 추가
- [ ] 1-4. 도면 분할 통합 테스트

### Phase 2: 계측기 유형별 병렬 LLM 호출
- [ ] 2-1. 계측기 유형별 프롬프트 정의
- [ ] 2-2. 유형별 추출 함수 작성
- [ ] 2-3. 병렬 호출 로직 구현
- [ ] 2-4. `_build_pid_graph_parallel()` 리팩토링
- [ ] 2-5. 병렬 처리 통합 테스트

### Phase 3: 위치 정보 저장
- [ ] 3-1. 위치 정보 스키마 정의
- [ ] 3-2. 근처 텍스트 추출 로직
- [ ] 3-3. 위치 정보 통합 테스트

### Phase 4: AREA 그룹핑
- [ ] 4-1. AREA 추출 로직 개선
- [ ] 4-2. AREA별 그룹핑 함수

### Phase 5: Experion 태그 매핑
- [ ] 5-1. 기존 매핑 로직 확인
- [ ] 5-2. 매핑 결과 통합

### Phase 6: UI 연동
- [ ] 6-1. API 엔드포인트 확인
- [ ] 6-2. 위치 정보 API 추가
- [ ] 6-3. 프론트엔드 UI 수정

---

## 주의 사항

1. **백업 필수**: 각 파일 수정 전 `.rooBackup/`에 백업
2. **diff 제시**: 변경 내용 diff 형식으로 제시 후 확인
3. **작은 단계**: 각 단계를 독립적으로 완료하고 검증
4. **테스트 우선**: 테스트 스크립트 먼저 작성 후 구현
5. **기존 코드 유지**: topology.py, mapper.py는 기존 유지 (이미 잘 구현됨)

---

## 다음 시작 시

1. 이 파일의 체크리스트에서 첫 번째 미완료 항목부터 시작
2. 각 단계 완료 시 체크리스트 업데이트
3. 문제가 발생하면 해당 단계에서 중단하고 원인 분석
4. 완료 기준을 충족해야 다음 단계로 진행

