# drawNET Bug Report - 2026-03-21 🐞

이 문서는 2026년 3월 21일 발생한 버그 및 장애와 그에 따른 조치 사항을 기록합니다.

---

### [Instance #2255] - Sidebar Focus Loss & Explicit Save Refactoring
- **현상**: 사이드바에서 라벨 수정 시 포커스 유실로 인한 타이핑 불가능 현상 및 자동 저장에 의한 의도치 않은 데이터 경합 가능성 제기.
- **원인**: 실시간 `input` 및 자동 `change`(blur) 이벤트가 시각 속성 변경 리스너와 충돌하여 DOM 리렌더링 발생.
- **조치**: 
    1. **명시적 저장 모델(Explicit Apply)** 도입: 텍스트 관련 필드는 오직 **Enter** 또는 **[적용]** 버튼 클릭 시에만 저장되도록 변경하여 입력 중 데이터 무결성 보장.
    2. 사이드바 내부 요소에 포커스가 있을 경우 그래프 외부 변화에 의한 리렌더링을 차단하여 포커스 연속성 확보.
- **현상**: 라벨 위치를 "하(bottom)"로 설정해도 저장 후 불러오면 다시 "상(top)"으로 초기화됨.
- **원인**: `layers.js` 내부에 라벨 위치 기본값이 `bottom`으로 하드코딩되어 강제 적용되었으며, 일부 객체 생성 시 `label_pos` 데이터 주입 누락.
- **조치**: `layers.js` 하드코딩 제거, `system.js`에서 생성 시 기본값(장비-하, 그룹-상) 강제 주입, 유틸리티 함수 보강을 통한 정합성 확보.

### [Instance #2245] - Sidebar Display Stale During Group Rename (Recursive & Logic Fix)
- **현상**: 그룹 이름을 변경해도 해당 그룹에 속한 하위 개체의 사이드바 내 [상위] 정보가 즉시 바뀌지 않음.
- **원인**: 
    1. **저장 조건부 누락**: 부모 노드가 바뀌지 않은 단순 속성(이름 등) 변경 시 `saveUpdates` 호출이 누락되어 저장이 실행되지 않음.
    2. **포커스 가드 충돌**: 사이드바 내부에서 편집 중일 때 리렌더링을 차단하는 로직이 적용(Apply) 시점의 갱신마저 막아버림.
    3. **비동기 타이핑 불일치**: 엔진의 데이터 확정 전 UI 렌더링 시도로 인한 구형 데이터 출력.
- **조치**: 
    1. `handleNodeUpdate` 내 저장 로직을 평탄화하여 **속성 변경 시 항상 저장**되도록 수정.
    2. **재귀적 전파(Recursive Propagation)** 도입: 그룹명 변경 시 하위 모든 개체(`getDescendants`)에 동기화 타임스탬프를 주입하여 하위 개체들의 변경 이벤트를 강제 트리거함.
    3. `safeRender` 포커스 가드 최적화: `INPUT/TEXTAREA`가 활성화된 경우만 스킵하도록 정규화하고 `setTimeout(0)`으로 렌더링 시기를 튜닝함.
- **현상**: 불러온 파일의 일부 그룹 라벨이 화면 출력값과 사이드바 표시값이 서로 다름 (예: Storage vs 그룹).
- **원인**: 과거 버전의 저장 로직 오류로 인해 `attrs`와 `data` 필드 간의 불일치가 파일 내에 고착화됨.
- **조치**: `json_handler.js` 마이그레이션 필터를 추가하여, 로드 시 `data.label`을 원본 소스로 삼아 시각적 라벨을 강제 동기화함.

### [Instance #2235] - Destructive Object Disappearance (Style Corrupt)
- **현상**: 레이어 설정 변경 시 객체가 갑자기 투명해지거나 색상이 사라지는 현상.
- **원인**: `layers.js`에서 투명도 적용 시 `setAttrs`를 사용하여 기존의 모든 커스텀 스타일(fill, stroke 등)을 덮어써버림.
- **조치**: `attr()` 개별 호출 방식으로 변경하여 기존 스타일 유산을 완벽히 보존함.

### [Instance #2230] - Missing Coordinates Recovery (Pos/Size)
- **현상**: 일부 객체가 좌표값 누락으로 인해 (0,0)에 배치되거나 아예 보이지 않음.
- **원인**: 복사/붙여넣기 및 엔진 전환 과정에서 X6 표준 좌표 필드가 유실된 데이터 잔재.
- **조치**: `json_handler.js`에 `data.pos` 기반 좌표 자동 복구 로직을 주입하여 유실된 개체들을 정상 위치로 소환함.

### [Instance #2225] - Edge Clipping & Selection Difficulty (Z-Index)
- **현상**: 그룹 위에 선을 그으면 그룹 뒤로 숨어서 클릭이 안 됨. 단축키 연결 시에도 동일 현상 반복.
- **원인**: 엣지 기본 Z-Index가 5로 설정되어, 레이어 오프셋이 적용된 그룹보다 하단에 배치됨.
- **조치**: 전체 계층 구조 재설계 `Group(1~19) < Edge(30) < Node(50)` 및 마우스/단축키 생성 경로 동기화.

### [Instance #2220] - Accidental Reset of Edge Vertices
- **현상**: 새로운 장비를 연결하면 기존에 예쁘게 꺾어 놓았던 선들이 모두 일직선으로 초기화됨.
- **원인**: `applyLayerFilters` 함수 내에 모든 엣지의 버텍스를 강제로 비우는 과도한 '자동 복구' 로직이 포함되어 있었음.
- **조치**: 해당 파괴적인 초기화 로직(`setVertices([])`)을 삭제하여 사용자 커스텀 경로 보존. (Instance #1480 정정 사항)

---

### [Instance #2202] - Label Reverts when Changing Label Position (Select Sync)
- **현상**: 라벨 이름을 수정한 직후(아직 저장되기 전) 라벨 위치(`select`)를 변경하면 이름이 이전 상태로 되돌아감.
- **원인**: 모든 입력 요소에 동일한 `debounce`(300ms)가 적용되어 있어, 상호작용 간 데이터 경합 발생 및 `renderProperties`에 의한 DOM 덮어쓰기 현상.
- **조치**: `select`, `checkbox`, `color` 등 상태 선택형 요소는 `change` 이벤트 발생 시 즉시 저장(`applyChanges`)되도록 변경하여 데이터 동기화 보장.

### [Instance #2108] - Inconsistent Line Thickness (Style vs Selection)
- **현상**: 구성도 작성 시 선 두께가 일정하지 않게 보임.
- **원인**: 
    1. 선택 시 강조 효과(3px)와 일반 상태(2px)의 차이.
    2. '굵은 선' 스타일이 UI에는 있으나 실제 두께(4px) 반영 로직이 누락됨.
- **조치**: 
    1. '굵은 선(double)' 선택 시 실제 4px가 적용되도록 매핑 로직 업데이트.
    2. 속성창에 '선 두께(Width)' 수치 입력 필드를 추가하여 개별 커스터마이징 지원.

### [Instance #2010] - ID & Label Confusion (Initial Data Setup)
- **현상**: 그룹이나 노드 생성 시 이름이 `group_xxxx`와 같은 ID 형식으로 표시되며, 수정 후 특정 상황에서 다시 ID 값으로 되돌아가는 것처럼 보임.
- **원인**: `drop.js`에서 노드 생성 시 ID와 Label을 동일한 랜덤 문자열로 초기화했기 때문에 발생한 혼동.
- **조치**: 초기 라벨을 '그룹', '사각형' 등 친숙한 한글 명칭(다국어 대응)으로 설정하도록 변경하고, 사이드바에서 ID를 읽기 전용 필드로 명시적으로 분리 노출함.

### [Instance #1968] - Data Reverted During Move after Rename (Blur vs Drag)
- **현상**: 그룹 이름을 수정한 직후 다른 곳을 클릭하지 않고 바로 드래그하여 이동하면 이름이 이전 값으로 되돌아감.
- **원인**: 사이드바가 `change`(포커스 해제) 시점에 저장하는데, 드래그 시 발생하는 리렌더링 이벤트가 `change`보다 먼저 발생하여 이전 데이터를 불러옴.
- **조치**: 사이드바 텍스트 입력 이벤트를 `input`으로 변경하고 300ms 디바운싱을 적용하여 실시간 동기화 구현.

### [Instance #1940] - JSON Syntax Error in Locale File (Stray Backticks)
- **현상**: 앱 구동 시 `[drawNET:CRITICAL] Failed to load locales` 에러 발생하며 모든 텍스트가 키값으로 표시됨.
- **원인**: `ko.json` 수정 과정에서 AI 도구가 파일 끝에 마크다운 기호(```)를 잘못 삽입하여 유효하지 않은 JSON 형식이 됨.
- **조치**: `ko.json` 파일 끝의 불필요한 문자를 제거하고 구조 정상화.

### [Instance #1931] - Property Handler Syntax Error (Accidental Deletion)
- **현상**: 노드 속성 수정 시 변경사항이 반영되지 않거나 콘솔에 `SyntaxError` 발생.
- **원인**: '에셋 경로' 필드를 제거하는 과정에서 `handlers/node.js` 속성 추출 객체의 괄호 및 인접 필드(color, fill 등)를 실수로 대량 삭제함.
- **조치**: 삭제된 모든 필드 로직을 원래대로 복구하고 의도했던 `assetPath` 추출부만 정교하게 제거.

### [Instance #1860] - Rich Card Sidebar UI Inconsistency
- **현상**: 리치 텍스트 카드의 속성창 디자인이 기존 '컴팩트 UI' 표준(토글 스위치, 정렬된 입력창 등)과 다르게 투박하게 표시되고 정보 밀도가 낮음.
- **원인**: 신규 객체 전용 템플릿 작성 시 표준 CSS 클래스(`prop-input`, `toggle-switch`) 적용 누락 및 일부 스타일(`input-with-color`) 미정의.
- **조치**: `rich_card.js` 템플릿을 표준 컴포넌트 구조로 전면 재작성하고, `properties_sidebar.css`에 부족한 레이아웃 스타일 보강.

### [Instance #1840] - Rich Card Syntax Error (Duplicate Identifier)
- **현상**: 리치 카드 선택 시 콘솔에 `Uncaught SyntaxError: Identifier 'renderRichContent' has already been declared` 발생 및 사이드바 작동 중단.
- **원인**: `styles/utils.js`에서 함수를 임포트했음에도 불구하고, 로컬 핸들러 파일에도 동일한 가명 함수가 남아있어 충돌 발생.
- **조치**: `handlers/rich_card.js` 하단의 중복된 `renderRichContent` 함수를 제거하고 공용 유틸리티 함수만 사용하도록 수정.

### [Instance #1692] - 다중 선택 해제 시 시각적 잔상(Focus) 유지
- **현상**: `Ctrl+Click`으로 다중 선택 객체 중 일부를 해제해도 캔버스상에 점선 테두리(Focus)가 남아 있음.
- **원인**: X6의 `Selection` 또는 `Transform` 플러그인이 추가한 `boundary` 도구가 `unselected` 이벤트 시 자동으로 제거되지 않거나 커스텀 도구 관리에 밀려 잔류함.
- **조치**: `selection.js`의 `unselected` 이벤트 핸들러에서 노드/엣지 해제 시 `removeTools()`를 명시적으로 호출하도록 강화.

### [Instance #1684] - `removeLabel` 런타임 에러
- **현상**: 엣지 선택 해제 시 `cell.removeLabel is not a function` 에러 발생.
- **원인**: 일부 X6 환경에서 엣지 객체의 단축 함수가 유실되거나 차단되는 문제.
- **조치**: `setLabels`와 `filter`를 사용하여 명시적으로 해당 ID의 라벨을 제외한 리스트를 재설정함.

### [Instance #1640] - 하이라이트 플러그인 의존성 에러
- **현상**: 시작/대상 앵커 호버 시 `createExecutionContext` 및 `unhighlight` 함수를 찾을 수 없다는 TypeError 발생.
- **원인**: AntV X6의 Highlight 플러그인 의존성 문제.
- **조치**: 외부 플러그인 의존성을 제거하고, 노드의 본체(`body`) 속성(`attr`)을 직접 제어하여 강조 효과를 주는 방식으로 로직 선회.

### [Instance #1628] - `addLabel` 런타임 에러
- **현상**: 엣지에 라벨 추가 시 `cell.addLabel is not a function` 에러 발생.
- **원인**: X6 특정 버전에서 엣지 객체의 믹스인(Mixin) 상태에 따라 단축 함수가 인식되지 않는 문제.
- **조치**: `getLabels()` / `setLabels()` 패턴으로 변경하여 호환성 확보.

### [Instance #1505] - 직선 라우팅 강제 꺾임 현상
- **현상**: 라우터를 제거했음에도 선이 90도로 꺾여 연결됨.
- **원인**: X6의 방향성 앵커(`top`, `left` 등)가 경로에 영향을 미침.
- **조치**: '직선' 모드일 경우 앵커를 방향성이 없는 `center`로 강제 전환.

### [Instance #1480] - 레이어 필터링 시 라우팅 설정 유실 (정정됨)
- **현상**: 레이어나 줌 변경 시 다시 꺾인 상태로 회귀함.
- **원인**: 레이어 'Auto-Repair' 로직이 Vertices를 초기화하지 않음.
- **조치**: (구) `setVertices([])` 추가 -> (현) 해당 로직이 사용자 데이터 파괴를 유발하여 최종 삭제 완료 (Instance #2220 참조).

### [Instance #1466] - Logger 참조 에러
- **현상**: `logger is not defined` 발생.
- **원인**: `edge.js` 내 모듈 임포트 누락.
- **조치**: `logger` 모듈 임포트 추가.

---
*아카이브 관리자: drawNET AI Assistant*
