diff --git a/.agents/PixConvert Project Plan.md b/.agents/PixConvert Project Plan.md new file mode 100644 index 0000000..42ecd9f --- /dev/null +++ b/.agents/PixConvert Project Plan.md @@ -0,0 +1,89 @@ +## **01. 프로젝트 개요** + +- 프로젝트 명: PixConvert +- 목표: 직관적이고 가볍게 사용할 수 있는 **이미지 확장자 변환 프로그램** 제공 +- 기반 구조: + - C# ModernWPF + MVVM + - TagNamer 프로젝트 일부 코드 재사용 +- 재사용 코드: + - UI 레이아웃 기반 구조 + - 파일 리스트/정렬/드래그 + - Snackbar/Dialog/Language 서비스 등 + +## 02. 개발 스택 + +- **Language**: C# (.NET 10.0, WPF) +- **UI Library**: [ModernWPF](https://github.com/Kinnara/ModernWPF) +- **IDE**: Antigravity +- **AI**: Gemini 3 Flash, GPT Codex Web + +## 03. 개발 목표 + +- **가볍고 빠르게 동작** +- **직관적인 UI** +- **대량 파일 변환 지원** +- **자주 쓰는 이미지 확장자 간 변환을 최소한의 클릭으로 수행** + +## 04. 주요 기능 정의 + +| 구분 | 기능명 | 설명 | +| --- | --- | --- | +| 기본 | 파일 입력 | 재사용 코드 | +| 기본 | 파일 출력 | | +| 기본 | 파일 목록 | 재사용 코드 | +| 기본 | 확장자 변환 | | +| 기본 | 언어 변경 | EN ↔ KR 두가지 언어 제공 | +- **파일 출력** + - 변환 완료된 결과물을 신규 파일 생성과 기존 파일 대체를 선택하는 옵션을 제공, + 그에 따라 결과물을 파일로 출력하는 기능 필요. +- 확장자 변환 + - 목표 지원 확장자: **PNG, JPG/JPEG, BMP, GIF, WEBP** + - 변환 옵션: + - 퀄리티 관련 옵션 + - 대상 확장자 선택 + - 출력 폴더 지정 + - 원본 유지 / 덮어쓰기 옵션 + - 파일명 규칙 설정(선택적) + +## 05. **사용자 흐름 (User Flow)** + +1. 앱 실행 +2. 파일/폴더 추가 +3. 리스트에서 변환할 파일 확인 +4. 대상 확장자 및 옵션 설정 +5. 변환 실행 +6. 결과 확인 (성공/실패/알림) + +## **06. 화면 UI 구성** + +### **헤더** + +- 간단한 현재 변환 계획 표시 +- 앱 버전 표시 +- 언어 선택 (예: EN/KR) + +### **사이드바** + +- 파일 추가 / 폴더 추가 +- 리스트 초기화 +- 정렬 옵션 +- 변환 실행 + +### **메인 영역** + +- 파일 리스트 (아이콘/이름/크기/경로) + +### **상단 알림** + +- 스낵바 메시지 +- 변환 진행률 표시 + +### 변환작업 창 + +- 변환 확장자 선택지 및 옵션 + +## **07. 고려사항** + +- 대량 파일 변환 시 성능/메모리 관리 필요 +- 변환 실패/권한 문제 대응 +- UI 응답성 유지 (비동기 처리 필수) diff --git a/.agents/_Work Progress Summary.md b/.agents/_Work Progress Summary.md new file mode 100644 index 0000000..a40c3f9 --- /dev/null +++ b/.agents/_Work Progress Summary.md @@ -0,0 +1,633 @@ +## 0. 코드 재설계 및 Language 서비스 추가 + +- TagNamer 코드에서 불필요한 부분 제거 +- TagNamer에 언어 전환 기능을 추가하면서, PixConvert에도 언어 전환 기능을 추가 + +## 1. MainViewModel 구조 개선 (관심사 분리 및 DI 도입) + +- **계기**: `MainViewModel`이 파일 I/O, 환경 설정, 다국어 처리 등 앱의 핵심 로직을 독점하며 단일 책임 원칙(SRP)을 위반하는 비대한 클래스(Large Class) 상태로 전개되어 유지보수 오버헤드가 증가함. +- **1차 개선 (로직 분리 및 의존성 주입)**: + - **해결 방식**: 비즈니스 로직을 `IFileProcessingService`로 이관하고, 설정 관련 상태를 서브 뷰모델로 분산 배치함. `Microsoft.Extensions.DependencyInjection`를 통해 서비스와 뷰모델 간의 느슨한 결합(Loose Coupling)을 구현함. + - **추가 문제**: 기능 분리 후 도메인 모델들이 여러 서비스에 파편화되면서, 인터페이스 간 상호 참조 관리가 복잡해지고 데이터 흐름 추적이 어려워지는 현상 발생. +- **2차 개선 (도메인 모델 통합 및 관리 체계 정비)**: + - **해결 방식**: 파편화된 모델들을 핵심 서비스 인터페이스 정의 내로 통합하여 응집도를 높이고, 전역 설정 상태를 처리할 관리 포인트를 재정립함. +- **최종 요약**: 관심사 분리를 통해 코드 가독성을 확보했으며, 서비스 중심 아키텍처로의 전환을 통해 향후 기능 확장에 용이한 구조적 기반을 확립함. + +## 2. FileListViewModel 데이터 정합성 유지 (중복 체크 로직 최적화) + +- **계기**: UI 바인딩용 `ObservableCollection`과 중복 검사용 `HashSet` 간의 상태 불일치 리스크가 존재하여, 데이터 조작 시 정합성을 보장할 설계가 필요했음. +- **1차 시도 (이벤트 기반 자동 동기화)**: + - **해결 방식**: `CollectionChanged` 이벤트를 구독하여 항목 추가/삭제 시 `HashSet` 데이터를 자동 갱신하도록 구현함. + - **한계**: 앱의 데이터 규모(1만 개 이내) 대비 이벤트 기반 동기화 인프라의 복잡도가 높아, 코드 가독성을 저해하는 오버 엔지니어링(Over-engineering) 요소로 판단됨. +- **2차 시도 (LINQ 기반 단순화 및 관심사 집중)**: + - **해결 방식**: 복잡한 동기화 객체를 제거하고 LINQ(`Any`)를 활용한 직관적인 중복 체크 방식으로 전환하여 코드의 본질과 유지보수 효율을 높임. +- **최종 요약**: 프로젝트의 현재 규모에 적합한 로직을 채택하여 복잡성을 제어함. (이후 8번에서 `HashSet` 구조로 롤백됨.) + +## 3. Snackbar 서비스 레이스 컨디션 및 UI 상태 오염 해결 + +- **계기**: 대량 파일 처리 시 다수의 알림 요청이 비선형적으로 발생하여 메시지가 유실되거나, 이전 애니메이션과 충돌하여 UI가 멈추는 레이스 컨디션(Race Condition) 현상 발생. +- **1차 개선 (메시지 큐 및 흐름 제어)**: + - **해결 방식**: `SemaphoreSlim` 기반의 대기열(Queue) 구조를 사용하여 알림 요청을 직렬화(Serialization)함. 이전 메시지가 완전히 닫힌 후 다음 메시지를 노출하는 순차 처리 큐 구조를 설계함. +- **추가 문제 (지연된 비동기 업데이트에 의한 상태 오염)**: + - 이전 작업에서 발생한 지연된 진행률 업데이트(`UpdateProgress`)가 뒤늦게 실행되어, 현재 활성화된 최신 알림을 과거의 텍스트로 덮어씌우는 정합성 문제 식별. +- **2차 개선 (Correlation ID 기반 세션 필터링)**: + - **해결 방식**: 각 작업 세션에 고유 ID(Correlation ID)를 부여하고, 업데이트 요청 시 현재 세션 ID와 일치하지 않는 과거의 모든 비동기 요청을 무시하는 필터링 로직을 도입함. +- **최종 요약**: 비동기 실행 시점 차이로 인한 UI 상태 오염을 차단하여, 사용자에게 항상 최신화된(Up-to-date) 정보를 보장함. + +## 4. 시스템 아이콘 연동 및 리소스 관리 최적화 + +- **계기**: 정적 리소스 기반의 단일 아이콘 표기로 인해 파일 형식 식별력이 저하됨. 탐색기와 동일한 시각적 피드백 제공 필요. +- **해결 방식 (Shell API 연동 및 고성능 캐싱 설계)**: + - **기술 사양**: Windows Shell API(`SHGetFileInfo`)를 활용하여 시스템 등록 아이콘을 동적으로 추출함. 대량 처리 시 I/O 부하를 최소화하기 위해 확장자 기반의 `ConcurrentDictionary` 캐싱 모델 적용. + - **메모리 최적화**: `bitmapSource.Freeze()`를 통한 UI 스레드 렌더링 효율 강화 및 `DestroyIcon`을 이용한 GDI 핸들 누수(Memory Leak) 방지 로직 설계. +- **최종 요약**: 시스템 자원 사용을 최소화하면서 탐색기와 동일한 사용자 경험을 구현함. (이후 8번에서 해당 기능은 제거됨.) + +## 5. 파일 시그니처 분석 엔진 도입 및 UI 구조 개편 + +- **계기**: 파일 확장자(문자열)에 의존하는 정보 표시는 데이터 신뢰성이 낮음. 파일 헤더 시그니처 기반의 정밀 포맷 분석이 필요했음. +- **1차 개선 (데이터 모델 및 UI 그리드 재배치)**: + - **해결 방식**: 불필요한 확장자 On/Off 옵션을 제거하고, 리스트 레이아웃을 '파일명 / 확장자 / 포맷' 컬럼 구조로 분리하여 데이터 가시성을 확보함. +- **추가 문제 (확장자 위조 식별 불가)**: + - 파일명 텍스트 분리만으로는 사용자가 임의로 변경한 확장자(예: WebP를 JPG로 변경)를 감지할 수 없는 정합성 확인의 한계 노출. +- **2차 개선 (매직 넘버 기반 분석 엔진 구현)**: + - **해결 방식**: 파일의 시작 바이트(Magic Number)를 직접 읽어 실제 포맷을 식별하는 `AnalyzeSignatureAsync` 엔진을 구현하여 데이터 무결성 검증 기능을 도입함. +- **최종 요약**: 단순 텍스트 표기에서 탈피하여 파일 시그니처 기반의 정보를 제공함으로써 변환 프로세스의 신뢰도를 제고함. + +## 6. Snackbar 진행 데이터 시각화 개선 (절대 수치 기반 표기 도입) + +- **계기**: 퍼센트(%) 기반의 상대적 수치 표기는 대량 작업 시 개별 파일 단위의 구체적인 진행 상태를 인지하기 어려움. 명확한 처리 개수 정보 제공 필요. +- **해결 방식 (작업 밀도 시각화)**: + - **구현**: `FileProcessingProgress` 모델에 전체 대상 수(Total Count) 필드를 보강하고, 실시간 처리 인덱스와 결합하여 '현재/전체' 형태의 텍스트 로직으로 재설계함. +- **최종 요약**: 정량적인 진행 지표를 제공하여 대규모 데이터 처리 시 UI 피드백의 투명성과 시인성을 개선함. + +## 7. FileItem 모델 경량화 및 MVVM 아키텍처 최적화 + +- **계기**: 레거시 코드로부터 기인한 미사용 속성들이 메모리 자원을 불필요하게 점유하고 있었으며, 수만 개 단위의 객체 생성 및 UI 갱신 시 성능 저하 리스크 식별. +- **해결 방식 (코드 생성기 및 모델 슬림화)**: + - **아키텍처 개선**: `CommunityToolkit.Mvvm`의 소스 생성기(`ObservableProperty`)를 도입하여 보일러플레이트 코드를 대거 제거하고 런타임 오베헤드를 감축함. + - **성능 설계**: 데이터 로드 시점의 부하를 분산하기 위해 UI 노출 시점에 연산이 발생하는 지연 업데이트(Lazy Parsing) 로직을 부분 적용함. +- **최종 요약**: 데이터 모델의 메모리 풋프린트(Memory Footprint)를 축소하고, 상태 변경 추적 효율을 개선하여 대규모 데이터 세트 처리에 적합한 데이터 구조를 확립함. + +## 8. 파일 로딩 성능 최적화 (I/O 병목 해결 및 병렬 처리 도입) + +- **계기**: 1만 개 규모의 대량 파일 추가 시 로딩 시간이 약 2분(120초) 소요되어 사용자 경험 저하 및 시스템 리소스 병목 식별. +- **1차 개선 (비효율적 연산 및 외부 API 오버헤드 제거)**: + - **분석**: Shell API를 통한 아이콘 동적 추출 비용과 LINQ `Any()` 기반의 중복 체크 로직(O(N²))이 주요 성능 저하 요인으로 판단됨. + - **수정**: 아이콘 추출 기능을 배제하여 OS 시스템 콜 오버헤드를 차단하고, `HashSet`을 통한 O(1) 탐색 구조로 중복 체크 성능을 최적화함. + - **결과**: 로딩 속도를 약 25% 개선(1분 30초대)하여 알고리즘적 병목 해결. +- **추가 문제 (중복 디스크 I/O 및 컨텍스트 스위칭 비용)**: + - `Task.Run`을 이용한 CPU 중심 비동기 처리의 한계와, 객체 생성 시 `new FileInfo()`를 반복 호출하며 발생하는 중복 디스크 접근으로 인해 I/O Latency 누적. +- **2차 개선 (I/O 효율 극대화 및 Single-Touch 구조 설계)**: + - **수정**: `FileStream.ReadAsync`를 활용하여 순수 비동기 I/O로 전환. 파일 메타데이터와 시그니처를 단일 스트림 세션에서 획득하는 구조를 구현하여 파일당 디스크 접근 횟수를 66% 감축(3회 -> 1회). + - **결과**: 콜드 캐시 기준 로딩 시간을 1분 15초대까지 단축. +- **추가 문제 (순차적 I/O 대기 방식의 한계)**: + - 루프 내 단일 `await` 처리로 인해 OS의 I/O 파이프라인 유휴 시간이 발생하며, 다중 입출력의 이점을 살리지 못하는 순차적 실행 구조 확인. +- **3차 개선 (드라이브 적응형 병렬 처리 도입)**: + - **수정**: `Parallel.ForEachAsync`를 도입하여 다중 I/O 요청을 동시 처리함. WMI(`MSFT_PhysicalDisk`) 데이터를 기반으로 SSD(스레드 기반 최대 병렬)와 HDD(제한적 병렬)를 식별하고 최적의 병렬도를 할당하는 `GetOptimalParallelism` 로직 적용. + - **트러블슈팅**: 최초 `Win32_DiskDrive` 사용 시 NVMe SSD를 HDD로 오판별하는 이슈를 확인하고, `MSFT_PhysicalDisk` 기반의 미디어 타입 분류로 정밀도를 보정함. +- **최종 결과**: NVMe SSD 환경 기준, 1만 개 파일 로딩 속도를 최종 **약 10초**로 단축(최초 대비 약 92% 향상)하여 I/O 인프라 성능을 최적화함. + +## 9. 확장자-시그니처 불일치 항목 시각화 및 예외 처리 + +- **계기**: 임의의 확장자 변경으로 인해 실제 데이터 헤더와 물리 확장자명이 불일치하는 경우, 변환 프로세스에서 예외가 발생할 위험이 있음. 사전 검수를 위한 시각적 피드백 시스템 필요. +- **해결 방식 (비교 로직 및 동의어 필터링)**: + - **연산 설계**: `FileItem` 모델 내에 `IsMismatch` 검증 속성을 신설함. `jpg`/`jpeg`, `tif`/`tiff` 등 같은 포맷(Synonyms)을 정상으로 판별하는 하드코딩 예외 처리 로직 적용. + - **UI 강조**: `FileListControl.xaml`에서 `DataTrigger`를 활용하여 불일치 항목의 포맷 텍스트 색상을 강조(#FF4444) 표시함. +- **최종 요약**: 데이터 정합성 결여 항목을 실시간으로 감지하고 시각화하여, 변환 전 작업의 신뢰도를 확보함. + +## 10. 대량 파일 목록 UI 가상화 및 렌더링 최적화 + +- **계기**: 1만 건 이상의 레코드 로드 시 스크롤 프레임 드랍(Stuttering) 및 렌더링 지연 현상 발생. 정렬 기능 연동 후 미세한 끊김 이슈가 식별됨. +- **분석 (병목 소사)**: + - **UI 오버헤드**: WPF `ListView`의 기본 가상화 설정 미비로 인한 시각적 컨테이너 객체 생성 부하. + - **연산 부하**: 바인딩된 `IsMismatch` 속성에서 매 스크롤 렌더링 시마다 `ToLower()`를 호출하여 발생하는 불필요한 힙(Heap) 메모리 할당 및 GC 부하. +- **해결 방식 (가상화 전략 및 메모리 최적화)**: + - **UI 가상화 정책**: `VirtualizingPanel.IsVirtualizing` 활성화 및 `Recycling` 모드를 적용하여 컨테이너 객체를 재사용함으로써 메모리 압박 및 객체 생성 오버헤드를 줄임. + - **프리렌더링 캐싱**: `VirtualizingPanel.CacheLength` 조정을 통해 뷰포트(Viewport) 영역 밖의 아이템을 사전 준비하여 고속 스크롤 반응성 확보. + - **데이터 모델 정규화**: 속성 연산에서 중복 문자열 처리를 제거하고, 이미 정규화된 데이터를 참조하도록 수정하여 런타임 연산 비용을 최소화함. +- **최종 요약**: 대용량 데이터 세트에서도 프레임 유실 없는 UI 응답성을 확보하고 시스템 자원 효율성을 개선함. + +## 11. 리스트 헤더 정렬 동기화 및 다차원 정렬 기능 구현 + +- **계기**: 파일 목록의 컬럼 헤더와 사이드바 정렬 옵션 간의 상태 불일치(Inconsistency) 현상 해결 및 표준 리스트 UX 제공 필요. +- **해결 방식 (브릿지 로직 및 정렬 엔진 확장)**: + - **UI 브릿지 설계**: `GridViewColumnHeader` 클릭 이벤트를 ViewModel의 명령(Command)과 맵핑하여, 헤더 클릭 시 사이드바의 `SelectedSortOption`과 `IsSortAscending` 상태가 자동 업데이트되도록 구현함. + - **토글 로직**: 동일 컬럼 재클릭 시 정렬 방향(오름차순/내림차순)이 반전되는 표준 정렬 인터랙션 적용. + - **정렬 도메인 확장**: `ISortingService`에 단순 속성 외에 확장자(Extension), 분석 시그니처(Signature) 등을 기준으로 하는 분석 데이터 기반 정렬 알고리즘 추가 반영. +- **최종 요약**: 관리 도구 UI 간의 상태 정합성을 확보하고 분석 데이터 기반의 정렬 기준을 세분화하여 데이터 핸들링 편의성을 개선함. + +## 12. 불일치 항목 전용 필터링 및 데이터 무결성 보호 로직 도입 + +- **계기**: 대량 데이터 세트 내에서 확장자-시그니처 불일치 항목만 특정하여 선별할 수 있는 고속 검수 도구 필요. +- **1차 시도 (다단계 정렬 기준 적용)**: + - **내용**: `SortingService`를 확장하여 `IsMismatch`를 2차 정렬 기준으로 활용하는 다단계 정렬 설계. + - **한계**: 정렬 옵션의 과도한 파편화로 인한 UI 복잡도 증가 및 리스트의 원래 맥락(Original Context) 유지가 어렵다는 기술적 한계 식별. +- **2차 시도 (ICollectionView 기반 동적 필터링)**: + - **해결 방식**: WPF의 `ICollectionView.Filter`를 활용하여 원본 컬렉션을 변동시키지 않고, 뷰(View) 레벨에서 실시간으로 불일치 항목만 투영하는 필터링 로직 구현. +- **데이터 정합성 보방 장치 (Data Integrity Guard)**: + - **조작 제한 로직**: 필터링 활성화 시 드래그 & 드롭 및 순번 재정렬 등 물리적 인덱스에 영향을 주는 조작을 차단함. 이는 필터로 인해 숨겨진 아이템과 가시적 아이템 간의 인덱스 매핑 오류(Index Mismatch)를 방지하기 위한 안전 조치임. +- **최종 요약**: 필터링과 정렬이 결합된 데이터 조작 워크플로우를 완성하고, 상태 기반 명령 제어를 통해 런타임 데이터 정합성을 확보함. + +## 13. 실시간 리스트 상태 통계 대시보드 구현 + +- **계기**: 작업 대상의 전체 규모 및 변환 불가능(미지원) 파일의 비율을 실시간으로 파악할 수 있는 통합 상태 지표 제공 필요. +- **해결 방식 (실시간 집계 및 레이아웃 정책 수립)**: + - **통계 연산 설계**: 파일 추가/삭제 및 분석 결과 갱신 시마다 전체 파일 수와 미지원(Unsupported) 파일 수를 실시간으로 집계하는 관찰 가능(Observable) 속성 구현. + - **레이아웃 최적화**: 초기 사이드바 배치 모델에서 정보의 중요도와 향후 작업 가이드 문구와의 연계성을 고려하여 헤더(Header) 영역으로 배치를 변경, 시각적 일관성 및 가독성 확보. +- **최종 요약**: 리스트의 정량적 지표를 중앙 집중화하여 노출함으로써 현재 작업 세션의 전반적인 상태 가시성을 개선함. + +## 14. 통합 로깅 인프라(Serilog) 구축 및 전역 예외 처리 시스템 도입 + +- **계기**: 다양한 사용자 환경(OS 권한, 디스크 비정상 종료 등)에서 발생하는 런타임 오류 분석 및 핵심 비즈니스 로직의 추적성(Traceability) 확보 필요. +- **해결 방식 (Serilog 로깅 및 예외 트랩 설계)**: + - **로깅 파이프라인**: `Serilog`를 도입하여 일자별 롤링 파일 로그(Rolling File Log) 및 비동기 기록 설정을 `App.xaml.cs` 진입점에 구성함. + - **전역 예외 포착**: `DispatcherUnhandledException`(UI 스레드) 및 `UnobservedTaskException`(비동기 태스크)을 가로채어 치명적 오류(Fatal)를 기록하고, 애플리케이션이 무조건적으로 종료되는 Silent Crash 현상 방어. + - **의존성 주입 기반 추적**: 주요 서비스 클래스에 `ILogger`를 주입하여 파일 I/O 오류 및 내부 상태 전이 이력을 자동으로 기록하도록 설계함. + - **로그 리소스 외부화**: 코드 내에 산재했던 로그 메시지들을 XAML 리서스(`Lang.Serilog.xaml`)로 분리하여 관리 효율성 및 코드 가독성 개선. +- **최종 요약**: 런타임 예외 발생 시 상세한 호출 스택(StackTrace)과 실행 컨텍스트를 확보할 수 있는 사후 분석 환경을 구축하여 유지보수 효율을 고도화함. + +## 15. xUnit 기반 유닛 테스트 환경 구축 및 비즈니스 로직 검증 + +- **계기**: MVVM 및 DI 패턴 도입으로 UI와 격리된 순수 로직이 증가함에 따라, 코드 변경 시 발생할 수 있는 회귀 오류(Regression) 방지 및 로직의 안정성 증명 필요. +- **해결 방식 (테스트 자동화 인프라 및 핵심 시나리오 검증)**: + - **인프라 구성**: xUnit 프레임워크를 활용한 `PixConvert.Tests` 프로젝트를 구축하고, `Moq` 라이브러리를 통해 외부 의존성(Logger 등)을 격리한 테스트 환경 설계. + - **`SortingService` 검증**: 다중 정렬 기준(이름, 크기, 시그니처 등) 및 정렬 방향에 따른 데이터 컬렉션의 정합성 확인. + - **`FileAnalyzer` 검증**: 실제 데이터와 확장자가 다른 위조 파일(Fake Extension) 시나리오 및 분석 불가능한 파일에 대한 시그니처 판별 로직의 무결성 테스트 실시. +- **최종 요약**: 핵심 비즈니스 로직에 대한 단위 테스트 스위트를 확보하여, 시스템 확장 및 리팩토링 시 발생 가능한 사이드 이펙트(Side Effect)의 탐지 능력을 강화함. + +## 16. 컴포넌트 지향 ViewModel 아키텍처 리팩토링 + +- **계기**: `MainViewModel`에 집중된 UI 제어 로직을 영역별로 분산하고, 독립적인 유지보수 및 기능 확장성을 확보하기 위한 구조적 개편 필요. +- **해결 방식 (컴포넌트 뷰모델 분할 및 쉘 패턴 적용)**: + - **아키텍처 설계**: 개별 UI 컴포넌트(Header, Sidebar 등)에 전용 뷰모델을 할당하고, `MainViewModel`은 이를 조율하며 전역 상태를 관리하는 쉘(Shell)로 재정립함. + - **책임 이관**: + - `SidebarViewModel`: 파일 입출력(Add/Folder) 및 핵심 액션 로직 담당. + - `HeaderViewModel`: 통계 대시보드 시각화 및 다국어 전환 로직 담당. +- **최종 요약**: 단일 책임 원칙(SRP)을 강화하고 뷰-뷰모델 간의 명확한 매핑 구조를 확립하여 코드 응집도 및 유지보수 편의성을 개선함. + +## 17. 비동기 실행 모델 최적화 및 안정성 강화 + +- **계기**: `async void` 패턴 기반의 명령(Command) 수행 시 발생하는 예외 유실(Exception Loss) 및 추적 불가능한 런타임 크래시 리스크 제거 필요. +- **해결 방식 (Task 기반 비동기 표준화 및 AsyncRelayCommand 도입)**: + - **명령 체계 리팩토링**: 기존 동기 커맨드를 `AsyncRelayCommand`로 교체하고 관련 메서드를 `async Task` 반환형으로 표준화함. 이를 통해 비동기 작업의 실행 상태를 안전하게 추적하고 예외 전파(Exception Propagation)를 정상화함. + - **방어적 프로그래밍**: 아키텍처 구조상 `async void`가 불가피한 외부 연동 메서드(예: Snackbar 표출 등)에 최상위 예외 핸들러(Guard)를 구축하여 치명적 오류에 의한 앱 종료 방어. +- **최종 요약**: 비동기 작업의 생명주기 관리 체계를 정립하고 예외 처리 파이프라인을 보강하여 백그라운드 작업의 동작 신뢰성을 확보함. + +## 18. 중앙 집중형 앱 상태 제어 시스템(AppStatus) 도입 + +- **계기**: `bool` 기반의 단일 `IsBusy` 속성만으로는 현재 진행 중인 작업의 상세 컨텍스트(스캔, 변환, 처리 등)를 식별할 수 없어, 정교한 UI 피드백 및 명령 간 상호 배제(Mutual Exclusion) 로직 구현에 한계 발생. +- **해결 방식 (열거형 기반 상태 세분화 및 전이 로직 통합)**: + - **상태의 구조화**: `Idle`, `FileAdd`, `Converting`, `Processing`으로 구성된 `AppStatus` 열거형을 정의하여 애플리케이션의 런타임 상태를 구체화함. + - **중앙 집중 제어**: `MainViewModel`에서 전역 상태를 통합 관리하고, `CurrentStatus` 변경 시 연관된 모든 명령의 `CanExecute` 속성이 자동 갱신되도록 상태 전이 파이프라인 구축. + - **XAML 선언적 제어**: `AppStatusToVisibilityConverter` 등 전용 컨버터 2종을 구현하여, XAML 레이어에서 상태별 UI 레이아웃 및 컨트롤 활성화 여부를 선언적으로 제어함. +- **최종 요약**: 앱의 실행 맥락을 명확히 정의하고 상태 관리 포인트를 일원화함으로써, 작업 간 충돌 방지 및 사용자 인터랙션의 정밀도를 개선함. + +## 19. 기반 클래스 도입 및 전역 상태 통신 아키텍처 재설계 + +- **계기**: 뷰모델 간 공통 로직의 중복 선언 및 강한 결합도(High Coupling)로 인한 확장성 저하. 과도한 생성자 주입 및 부적절한 데이터 소유권 분배 문제 해결 필요. +- **1차 개선 (ViewModelBase 도입 및 메시징 시스템 구축)**: + - **공통 뼈대 설계**: 리소스 접근 및 로깅 등 공통 기능을 캡슐화한 `ViewModelBase` 추상 클래스를 도입하여 중복 제거. + - **통신 비동기화**: `CommunityToolkit.Mvvm`의 메신저(Messenger) 패턴을 적용하여, 객체 간 직접 참조 없이 `AppStatus` 등의 상태를 동기화하는 느슨한 결합(Decoupling) 인프라 구축. +- **추가 문제 (부적절한 도메인 의존성)**: + - 모든 설정을 포함하던 `SettingsViewModel`이 도메인 성격이 상이한 타 뷰모델들에 강제로 주입되며 기형적인 참조 관계 형성. +- **2차 개선 (관심사 분리 및 데이터 재배치)**: + - **엔티티 재정의**: `SettingsViewModel`을 삭제하고, 관심사 분리 원칙에 따라 데이터 소유권을 재배치함. 리스트 제어 옵션은 `SidebarViewModel`로, 정책성 옵션은 `MainViewModel`로, 언어 설정은 전역 도메인 모델로 분산. +- **최종 요약**: 정적 의존성을 유연한 메시징 체계로 대체하고 데이터 소유권을 도메인 역할에 맞게 정립하여 코드 응집도를 강화함. + +## 20. UI 커스텀 게이지 구조의 WPF 표준 ProgressBar 전환 + +- **계기**: 진행률 시각화를 위해 임시로 구축된 `Grid` 기반의 복합 커스텀 구조(컨버터 + 다중 `ColumnDefinition`)가 XAML 복잡도를 가중시키고 유지보수 효율을 저해함. +- **해결 방식 (WPF 표준 컨트롤 내재화)**: + - **구조 간소화**: 런타임에 너비를 동적 계산하던 `ProgressToGridWidthConverter`를 삭제하고, WPF 내장 `ProgressBar` 컨트롤로 전면 대체함. + - **유연성 확보**: 단일 프로퍼티 바인딩(`Value`)으로 시각화 로직을 축소하여, 진행 범위 등 비즈니스 로직 변경 시 컨버터 수정 없이 컨트롤 속성 조절만으로 대응 가능하도록 개선함. +- **최종 요약**: 복잡한 중첩 UI 구조(59줄)를 표준 컨트롤(16줄)로 대체하여 코드 가독성을 확보하고, WPF 내장 애니메이션 인프라 활용이 가능한 표준화된 인터페이스를 확립함. + +## 21. 다중 엔진 대응 변환 파이프라인(Provider/Selector) 아키텍처 설계 + +- **계기**: 복수의 이미지 처리 엔진(NetVips, SkiaSharp 등)을 유연하게 제어하고, 파일 포맷별로 최적의 엔진을 동적으로 할당할 수 있는 표준화된 변환 인프라 구축 필요. +- **해결 방식 (추상화 계층 및 전략 패턴 적용)**: + - **UI 및 데이터 모델**: 변환 옵션을 관리하는 도메인 모델(`ConvertSettings.cs`)을 정의하고, 이를 제어할 `ContentDialog` 기반의 인터페이스 구현. + - **엔진 공급자(Provider) 추상화**: 공통 규격인 `IProviderService`를 통해 각 엔진 구현체를 캡슐화하고, 시그니처 분석 결과에 따라 최적의 공급자를 자동 할당하는 `EngineSelector` 로직 구축. + - **자원 관리 생명주기**: `IDisposable` 패턴을 통한 명시적 자원 해제 및 애플리케이션 종료 시 네이티브 종료 루틴(`NetVips.Shutdown()`)을 호출하여 메모리 누수 방지 및 자원 반납 처리 설계. +- **최종 요약**: 옵션 수집부터 엔진 선택까지의 변환 워크플로우를 모듈화하여, 향후 신규 포맷 및 엔진 추가 시 기존 코드의 변동을 최소화할 수 있는 확장성 있는 변환 엔진 레이어를 확립함. + +## 22. 도메인 주도 서비스 명칭 일괄 리팩토링 및 참조 정합성 확보 + +- **계기**: 기존의 모호한 서비스 명칭들을 실제 도메인 역할(Role & Responsibility)에 부합하도록 재정립하고, 프로젝트 전반의 명명 규칙 일관성(Consistency) 확보 필요. +- **해결 방식 (명칭 정규화 및 참조 정합성 최적화)**: + - **도메인 용어 통일**: `Scanner`(탐색), `Analyzer`(분석), `Selector`(선택) 체계로 인터페이스와 구현체 정규화 실시. `FileStatusConverter` 등 연관 컴포넌트까지 명칭 동기화. + - **전역 참조 무결성 검증**: 클래스 명칭 변경에 따른 DI 등록 정보 및 뷰모델 생성자 주입 정보를 최신화하여 컴파일 타임의 참조 안정성 확보. +- **최종 요약**: 코드 구조와 파일명이 도메인 지식과 일치하는 직관적인 설계를 실현하고, 코드 베이스의 가독성과 탐색 효율을 개선함. + +## 23. 프리셋 관리 비즈니스 로직 및 데이터 동기화 엔진 구현 + +- **계기**: 사용자 정의 변환 설정(Preset)의 영속성 관리(CRUD) 체계 구축 및 다중 프리셋 간의 독립적 상태 제어를 위한 비즈니스 로직 필요. +- **해결 방식 (Deep Copy 및 편집 세션 격리 아키텍처)**: + - **참조 간섭 차단**: 프리셋 생성 및 복제 시 객체 간 참조 독립성을 보장하기 위해 `JsonSerializer` 기반의 `Deep Copy` 메커니즘을 적용하여 데이터 무결성 확보. + - **트랜잭션 편집 구조**: 원본 데이터 직접 수정을 지양하고 편집용 임시 세션을 분리 운영함. 이를 통해 사용자 취소 액션 시 물리적 데이터 원복(Rollback) 가용성 확보. + - **동기화 시퀀스 고도화**: UI 상태를 모델로 병합하는 `SyncToSettings()` 로직 및 프리셋 전환 시의 프로퍼티 갱신 파이프라인을 구축하여 뷰-모델 간 정합성 유지. +- **최종 요약**: 변환 워크플로우의 재사용성을 높이는 관리 체계를 정립하고, 편집 프로세스 전반의 데이터 안전성과 정합성을 확보함. + +## 24. 이미지 변환 설정 인터페이스 리팩토링 및 기능 고도화 + +- **계기**: 기존 세로 나열식 UI의 공간 활용 비효율성 및 제한된 변환 옵션(출력 경로 제어 미흡, 배경색 지정 부재 등)으로 인한 사용성 저하 문제 해결 필요. +- **해결 방식 (UI 그리드 레이아웃 전환 및 옵션 확장)**: + - **레이아웃 정형화**: 다이얼로그 너비 확장 및 `Grid`/`WrapPanel` 구조 도입을 통한 수평 정렬 배치. 정보 밀도 최적화 및 시각적 일관성 확보. + - **도메인 모델 통합**: 기술적 중복성이 높은 이미지 그룹(일반/고성능)을 단일 카테고리로 통합하고, 불필요한 포맷 표기를 정제하여 설정 복잡도 완화. + - **기능적 도구 보강**: + - 외부 I/O 연동을 위한 시스템 폴더 브라우저(`OpenFolderDialog`) 인터페이스 도입. + - 투명 이미지 처리용 배경색 선택 기능(Standard/HEX) 추가 및 HEX 입력 전용 필터링(`HexColor`) 엔진 신설. +- **예외 방어 설계**: 하위 호환성 유지를 위해 레거시 설정 데이터(`settings.json`) 로드 시 Null 참조 예외를 방지하는 널 병합(Null-coalescing) 방어 코드 적용. +- **최종 요약**: 데스크톱 표준 UX에 부합하는 수평적 레이아웃을 확립하고, 정밀한 변환 제어를 위한 고급 옵션을 확보하여 설정 체계의 견고함을 강화함. + +## 25. 애플리케이션 생명주기 안정화 및 비동기 자원 관리 최적화 + +- **계기**: 애플리케이션의 시작 및 종료 시퀀스에서 발생할 수 있는 비정상 연산 및 네이티브 라이브러리 자원 해제 미흡으로 인한 잠재적 프로세스 잔류 리스크 식별. +- **해결 방식 (생명주기 핸들러 고도화 및 자원 보호 매커니즘)**: + - **안전한 종료 파이프라인**: `App.xaml.cs`의 종료 이벤트를 정비하여 네이티브 엔진(`NetVips.Shutdown()`)의 명시적 중단 및 비동기 로그 버퍼의 안전한 플러시(Flush) 프로세스 구축. + - **비동기 초기화 안정성**: 설정 파일 로드 및 서비스 초기화 시 발생할 수 있는 UI 스레드 교착 상태(Deadlock)를 방어하기 위해 비동기 초기화 로직 보강. +- **최종 요약**: 라이프사이클 전 영역에 걸친 자원 관리 정책을 확립하여, 애플리케이션의 물리적 종료 신뢰성 및 시스템 자원 반납의 확실성을 확보함. + +## 26. 변환 설정(Preset) 관리 아키텍처 및 검증 파이프라인 고도화 + +- **계기**: 범용 설정과 변환 프리셋이 단일 설정 파일(`settings.json`)에 혼재되어 발생할 수 있는 데이터 오염 리스크를 원천 차단하고, 유효하지 않은 설정값(빈 파일, 허용 범위를 벗어난 값 등)으로 인한 변환 런타임 오류를 방지하기 위함. +- **해결 방식 (설정 도메인 분리 및 2단계 검증 매커니즘 도입)**: + - **도메인 파일 분리**: 기존 `AppConfig` 인프라를 `PresetConfig` 및 `PresetService`로 전면 개편하고, 저장 대상을 `presets.json`으로 물리적으로 분리하여 향후 앱 일반 설정과의 관심사를 완벽히 분리함(Separation of Concerns). + - **1단계(구조 무결성) 검증**: 앱 기동 시 `LoadAsync` 단계에서 JSON 파싱은 성공했으나 필수 필드(Presets 리스트 등)가 누락되거나 손상된 경우, 자동으로 기본 프리셋을 주입하여 복구하는 `ValidPresetFile` 도입. + - **2단계(데이터 유효성) 검증**: 실제 변환 액션(ConvertFilesAsync) 진입 직전, 품질(Quality, 1~100) 수치 및 타겟 포맷 문자열 등의 논리적 무결성을 사전 검사(`ValidPresetData`). 이상 탐지 시 변환 프로세스를 능동적으로 차단하고 사용자에게 피드백(Snackbar Error) 제공. +- **최종 요약**: 데이터 저장소 분리로 설정 정보의 영속성(Persistence)을 안전하게 관리하고, 적시(Just-In-Time) 검증 파이프라인을 구축하여 예측할 수 없는 값 주입에 의한 애플리케이션 크래시를 방벽(Barrier) 수준에서 차단함. + +## 27. 설정 검증 세분화, 로깅(Logging) 도입 및 유닛 테스트(xUnit) 강화 + +- **계기**: `presets.json` 데이터 검증 로직이 강화됨에 따라, 어떤 이유로 데이터 복원이나 예외가 발생했는지(Audit Trail)를 추적할 시스템이 부재함. 또한 민감한 코어 로직(설정 유효성 검사)이 변경될 때 발생할 수 있는 잠재적 결함을 사전에 감지할 수단이 요구됨. +- **해결 방식 (Log 파이프라인 연동 및 테스트 베드 구축)**: + - **진단 로깅 적용**: `ValidPresetFile` (구조 무결성) 및 `ValidPresetData` (값 유효성) 전 과정에 걸쳐, 비정상 상태 감지 시 그 사유를 `ILogger`를 통해 `LogWarning` 및 `LogError` 레벨로 기록하도록 방어적 로깅(Defensive Logging)을 산입함. + - **테스트 케이스 확보**: xUnit 프레임워크 기반의 `PresetServiceTests` 클래스를 신설하고, Moq를 이용해 의존성을 격리. Preset 리스트가 Empty이거나 Null일 때의 복원 동작, Quality 값 경계 테스트(0, 50, 101), 미지원 Format 입력 시나리오 등에 대한 행위 기반(Behavior-driven) 단위 테스트를 작성. + - **레거시 테스트 복원**: 과거 엔티티 명칭 변경(`FileService` → `FileScannerService`, `SortOption` → `SortType` 등) 이후 컴파일이 누락/중단되어 방치되었던 기존 테스트 코드들의 참조 오류를 복원하여 지속적 통합(CI) 환경 구축 준비 완료. +- **최종 요약**: 앱 실행 단계에서 발생하는 데이터 예외의 가시성(Visibility)을 로그로 확보하였으며, 주요 검증 비즈니스 로직에 대해 100%에 가까운 조건 분기 커버리지를 가진 단위 테스트 스위트를 완성하여 회귀(Regression) 안정성을 크게 증진함. + +## 28. 목록 정리 기능의 사이드바 이관(List Manager) 및 UI/UX 개편 + +- **계기**: ContentDialog 기반으로 동작하던 "목록 정리" 기능이 화면을 완전히 가리고 모달(Modal) 형태로 동작하여 작업 흐름(Workflow)을 연속적으로 끊어먹는 UX(사용자 경험) 저하 요인으로 작용함. +- **해결 방식 (상태 기반 사이드바 전환 레이아웃 적용)**: + - **기능의 컴포넌트화**: 기존 `ListCleanDialog` 뷰(View) 및 뷰모델(ViewModel)을 폐기하고, 사이드바를 담당하는 영역 내에서 `AppStatus.ListManager` 상태 전환 시 `DataTrigger`를 통해 전역 패널 교체(Panel Swap)가 일어나도록 UI 구조 개편. + - **도메인 명칭 리팩토링 및 뷰모델 통합**: 구시대적 명칭인 `ListClean` 및 `ListSetting` 키워드를 `ListManager`(목록 관리)로 통일하고, 직관성이 떨어지던 '적용' 버튼을 '선택 제거'로 변경. 관련 기능을 `RemoveSelectedCommand`, `RemoveAllListCommand` 등으로 `SidebarViewModel`에 안전하게 통합. + - **인터랙션 피드백 및 조작성 개선**: 나가기 버튼의 위치를 최상단으로 옮겨 접근성을 확보하고, 확장자 토글 버튼을 기존 UI 스타일과 일관성 있게 유지. 대상 항목 제거 완료 후 기존의 스낵바(Snackbar) 메시지 알림 로직을 복구하여 성공 여부에 대한 명확한 시각적 알림을 제공. +- **최종 요약**: 앱 조작 흐름을 강제로 중단시키는 팝업 다이얼로그 패턴을 걷어내고 심리스(Seamless)하게 연동되는 사이드바 내장형 관리 기능을 도입하여 사용자 경험의 연속성(Continuity)을 확립함. + +## 29. 변환 설정 포맷 선택 UI 개편 및 동적 슬라이더 제어 조작 로직 도입 + +- **계기**: 기존 "원본 포맷 태그(다중선택) → 화살표 → 목표 포맷(드롭다운)" 구조는 사용자에게 인지적 부하를 주며, 게다가 PNG나 BMP 같은 무손실 포맷을 선택했음에도 화질(Quality) 조절 슬라이더가 켜져 있어 시각적, 논리적 모순을 초래했음. +- **해결 방식 (목표 포맷 단일 지향 설계 및 UI 바인딩 제어)**: + - **데이터 모델 및 패널 정제**: `ConvertSettings.cs` 및 `ConvertSettingViewModel.cs` 내부의 불필요한 원본 포맷 속성(`StandardSourceTags` 등)과 연관 검증 로직을 전부 걷어내어 오직 타겟 포맷(Target Format)만을 단일(Single-Choice)로 선택하는 구조로 간소화함. + - **상태 의존적(Computed) 비활성화 파이프라인**: 뷰모델 내에 `IsLossyFormat`이라는 논리 산출 속성을 구축하여 현재 선택한 타겟 포맷의 손실/무손실 여부를 실시간으로 판별함. 동시에 XAML 상의 Slider `IsEnabled` 속성을 이 값과 동기적으로 바인딩(Binding)하여, PNG 등 선택 시 조작 자체를 불가능하게(비활성화) 만듦으로써 사용자의 실수를 원천 방어함. + +## 30. 헤더 중앙 영역의 실시간 변환 진행 통계(Dashboard) UI 구현 + +- **계기**: 변환 프로세스가 동작 중일 때 사용자가 앱 전반적인 처리 현황(파일명, 총 처리 개수 중 현재 순번, 실패 카운트 등)을 전역 화면 어디서나 모니터링할 수 있는 헤더 기반 대시보드가 요구됨. +- **해결 방식 (메시지 기반 브로드캐스팅 및 컴포넌트 렌더링)**: + - **Payload 모델 구축**: `AppModel.cs` 내부에 파일명, 성공/실패 수, 적용된 프리셋 명 등을 담는 `ConvertProgressMessage` 레코드를 신설함. + - **비동기 메신저 연동**: 변환 핵심 루틴을 담당하는 `SidebarViewModel.ConvertFilesAsync` 과정에서 파일 한 개의 처리가 끝날 때마다 위 메시지를 Broadcast 형식으로 발행(Send)함. + - **구독자(Subscriber) UI**: 브로드캐스트된 데이터를 수신하는 `HeaderViewModel`이 전역 상태를 업데이트하며, XAML의 `HeaderControl` 영역은 데이터가 들어올 때 파일명과 처리 카운트를 실시간 텍스트로 노출하도록 동적 렌더링 설계 진행. + +## 31. 상태 전이(DataTrigger) 기반의 사이드바 작업(Converting) 전용 패널 전환 + +- **계기**: 대규모 이미지 변환이 본격화되면 기존의 파일 및 폴더 추가 버튼들은 조작이 불가능한 '죽은 UI'가 되어 의미를 상실함. 차라리 해당 공간을 변환 작업만을 위한 고도의 모니터링 영역으로 활용해야 효율적임. +- **해결 방식 (가상 디스플레이 교체 기법 도입)**: + - **상태 변화 리스너**: `SidebarControl.xaml`의 `ContentTemplate` 속성에 `DataTrigger`를 설계하여 `CurrentStatus == Converting`일 경우 사이드바 전체 컨트롤이 180도 교체(Swap)되도록 설계함. + - **작업 전담 패널 구성**: + - 진행 과정을 육안으로 볼 수 있는 `ProgressBar`(현재 퍼센티지 매핑). + - 처리 중인 파일명, 완료 수 및 오류 카운트를 시각화한 미니 로그보드 구성. +- **최종 요약**: 앱이 `Idle` 상태일 때는 제어 요소를, `Converting` 상태일 때는 작업 모니터링 도구를 동일 공간에 스마트하게 전환 제시함으로써 화면 공간의 낭비를 없애고 사용자의 포커스를 집중시킴. + +## 32. 데이터 정합성 보전 기반의 대규모 파일 처리 시스템 고도화 + +- **계기**: 10,000개 파일 제한 임계점에서 발생하는 중복 및 한도 초과 시나리오의 피드백이 불명확하고, 내부 데이터 구조(HashSet)의 비효율적 재생성으로 인한 성능 오버헤드가 잔존함. 또한 코어 로직의 안정성을 보증할 정밀 테스트 체계가 부족했음. +- **해결 방식 (부분 수용 로직 및 검증 체계 통합)**: + - **부분 추가(Partial Add) 및 피드백 개선**: 한도 초과 시 일괄 거부 대신 잔여 공간만큼 추가하는 유연한 로직을 도입하고, 중복/제외 수량을 명확히 알리는 우선순위 기반 알림 체계 구축. + - **메모리 및 I/O 최적화**: `IReadOnlySet` 참조 기반의 Zero-Copy 중복 체크를 구현하여 불필요한 객체 생성을 차단하고 디스크 I/O 효율을 높임. + - **시스템 정제 및 검증**: 미사용 레거시 코드와 리소스를 전수 정리하고, `FileAnalyzerServiceTests` 등 5가지 엣지 케이스를 포함한 총 62개의 유닛 테스트를 통해 무결성을 확증함. +- **최종 요약**: 대용량 파일 핸들링의 물리적 한계 상황에서도 데이터 정합성과 사용자 피드백의 투명성을 유지하며, 고성능 엔진과 강력한 테스트 스위트를 통해 상용 수준의 견고함을 확보함. + +## 33. 도메인 주도 아키텍처 개편 및 서비스-뷰모델 레이어 전면 정화 통합 + +- **계기**: `SidebarViewModel`이 너무 많은 책임을 소유한 '갓 객체(God Object)'로 전개됨에 따라 유지보수성이 저하되고, 서비스 레이어가 UI 알림에 직접 의존하는 등 아키텍처적 결함이 식별됨. 이를 해결하기 위해 도메인 중심의 구조로 전면적인 개편이 필요했음. +- **해결 방식 (객체 분해, 책임 이관 및 의존성 제거)**: + - **SortFilterViewModel 도입**: 뷰모델 분리의 첫 단계로, 정렬 및 필터 도메인을 전담하는 `SortFilterViewModel`을 신설하여 상태 관리를 독립시키고 뷰모델 간 직접 결합도를 낮춤. + - **서비스 레이어 정제 (PresetService)**: 서비스가 UI 스낵바를 직접 호출하던 구조를 탈피하여 처리 결과(bool)만 반환하도록 수정하고, 알림 책임은 호출자인 뷰모델로 이관하여 레이어 간 독립성 확보. + - **거대 뷰모델 해체 (Sidebar 3분할)**: `SidebarViewModel`을 폐기하고 `FileInput`(입력), `Conversion`(변환), `ListManager`(목록 관리)의 3개 독립 VM으로 완전 분산 재구축. + - **최종 최적화 (Cleanup)**: `MainViewModel`에 남아있던 잔여 로직(`ReorderNumber` 등)을 각 전문 VM으로 이전하고, `MainViewModel`은 이들을 조율하는 순수 컨테이너(Shell)로 정제. + - **안정성 강화**: 파일 드롭 핸들러를 비동기(`async/await`) 방식으로 표준화하고, 메신저 기반의 예외 복구 시스템을 도입하여 런타임 신뢰성 확보. +- **최종 요약**: 서비스부터 뷰모델까지 이어지는 아키텍처 전반의 기술 부채를 청산하고, 상용 수준의 확장성과 안정성을 갖춘 도메인 주도 아키텍처를 완성함. + +## 34. 리스트 아이템 상태 메시지 지역화 및 실시간 동기화 아키텍처 개편 + +- **계기**: 언어 전환 시 리스트 아이템의 '상태(Status)' 컬럼이 즉각적으로 갱신되지 않고, 변환 프로세스가 동작할 때만 업데이트되는 사용자 경험 저하 문제 식별. 이는 `IValueConverter` 기반 바인딩이 리소스 변경을 감지하지 못하는 WPF의 구조적 한계에서 기인함. +- **해결 방식 (모델 자가 갱신 구조)**: + - **이벤트 시스템 구축**: `ILanguageService` 및 `LanguageService`에 `LanguageChanged` 이벤트를 도입하여, 리소스 딕셔너리 교체 완료 시 전역적으로 알림을 발행하는 가벼운 통신망 구축. + - **모델 고도화 및 자가 갱신**: `FileItem` 모델에 `StatusText` 읽기 전용 속성을 신설하고, 상태 변경(`OnStatusChanged`) 및 언어 변경 이벤트 수신 시 `OnPropertyChanged`를 호출하여 UI가 스스로 갱신되도록 설계. + - **안전한 리소스 접근 (Safe Access)**: 런타임에는 `App.Current` 리소스를 참조하되, 유닛 테스트와 같이 GUI가 없는 환경에서는 키 값을 그대로 반환하는 방어 로직(`SafeGetResource`)을 적용하여 테스트 무결성 확보. +- **UI 및 리소스 정화**: + - `FileListControl.xaml`에서 복잡한 컨버터 바인딩을 제거하고 `{Binding StatusText}` 직접 바인딩으로 교체하여 XAML 가독성을 높이고 런타임 성능 최적화. + - 더 이상 사용되지 않는 `FileStatusConverter` 클래스 및 전역 리소스 정의를 프로젝트에서 전수 제거. +- **최종 요약**: 컨버터 의존성을 제거하고 모델 중심의 동기화 구조를 확립하여, 대규모 데이터 세트에서도 언어 전환 시 실시간으로 상태 메시지가 갱신되는 견고한 지역화 시스템을 완성함. + +## 35. SnackbarService 비동기 안정성 강화 및 예외 소실 결함 수정 + +- **계기**: `Dispatcher.InvokeAsync(async () => ...)` 사용 시 발생하는 비동기 예외가 `try-catch` 블록을 탈피하여 소실되는 구조적 결함 식별. 이는 스낵바 동작 중 발생하는 오류의 추적성을 저해하는 리스크임. +- **기술 분석 및 검증 (이중 Await 결함 식별)**: + - **원인**: `InvokeAsync`가 반환하는 `DispatcherOperation`를 단일 `await`할 경우, 내부 람다가 첫 번째 비동기 대기(`Task.Delay`)를 만나는 순간 제어권을 Dispatcher로 반환하며 별도의 Task를 생성함. 외부 `await`은 이때 완료된 것으로 간주되어 `try-catch` 블록을 빠져나가며, 이후 람다에서 발생하는 에러는 '잡히지 않는 예외'로 전락함. +- **해결 방식 (Double Await 전략 채택)**: + - **기술적 해결**: 모든 비동기 람다 호출 지점에 `await await`(Double Await)을 적용하여 내부 람다의 전체 생명주기를 외부 태스크와 완벽하게 동기화하고 예외 전파(Exception Propagation)를 정상화함. +- **심층적 설계 의사결정 (설계 의도 보존 및 대화의 흐름)**: + - **인터페이스 호환성 및 UX**: `ISnackbarService`를 사용하는 수많은 호출부(ViewModel) 수정을 피하고, 알림이 사라질 때까지 비즈니스 로직이 대기하지 않는 'Fire-and-forget' 본연의 UX를 유지하기 위해 `async void`를 전략적으로 유지함. + - **구조적 대안(Option B) 검토 및 리스크 식별**: 내부를 `async Task`로 분리하고 `_ = Task`로 호출하는 방식(Option B)을 검토했으나, 첫 번째 `await` 이전의 동기 구간에서 예외 발생 시 호출 스택(ViewModel)을 직접 타격하여 앱이 크래시될 수 있는 미세 리스크를 정밀 분석함. + - **최종 선택 (Option A)**: `async void`가 가진 '동기 구간 예외를 전역 핸들러로 안전하게 넘기는 특성'을 보호막으로 활용하면서, `await await`을 통해 비동기 예외 전파 문제만 정교하게 해결함. + - **결론**: 변경을 최소화(단 2줄)하면서도 상용 수준의 견고함을 확보하고, 주석 한 줄로 설계 의도를 박제하여 코드 품질을 극대화함. +- **최종 요약**: WPF 비동기 인프라의 미묘한 동작 특성(Dispatcher unwrapping)에 의한 결함을 수정하여, 알림 시스템 전체의 런타임 안정성과 예외 로깅의 신뢰도를 확보함. + +## 36. DriveInfoService 추출 및 파일 분석 서비스 책임 분리 리팩토링 + +- **계기**: `FileAnalyzerService` 내에 존재하던 드라이브 정보 판별 로직(SSD/HDD 구분 등)이 UI 스레드를 블로킹하는 동기 WMI 호출을 포함하고 있었으며, 분석 서비스가 하드웨어 정보 판별까지 담당하는 SRP(단일 책임 원칙) 위반 상태 식별. +- **해결 방식 (서비스 추출 및 비동기 캐싱 설계)**: + - **IDriveInfoService 추출**: WMI 기반의 드라이브 미디어 타입 및 최적 병렬도 판별 로직을 별도 서비스로 격리하여 재사용성과 테스트 가능성 확보. + - **비동기 WMI 및 캐싱**: blocking을 방지하기 위해 WMI 호출을 `Task.Run`으로 래핑하고, 동일 드라이브 루트(예: C:\)에 대한 쿼리 부하를 최소화하기 위해 `ConcurrentDictionary` 기반의 최적 병렬도 캐싱 메커니즘 도입. +- **ProcessPathsAsync 메서드 구조 개선 (메서드 4분할)**: + - **가독성 최적화**: 약 150줄에 달하던 거대 메서드를 오케스트레이터(`ProcessPathsAsync`), 파일 전담(`ProcessDirectFilesAsync`), 폴더 전담(`ProcessFoldersAsync`), 병렬 처리 래퍼(`CreateItemsBatchAsync`)로 분해. + - **유지보수성 확보**: 각 메서드의 길이를 40줄 이하로 압축하고, 중복 로직을 제거하여 향후 드라이브별 적응형 병렬 처리(Adaptive Parallelism) 고도화를 위한 구조적 기틀 마련. +- **최종 요약**: 하드웨어 의존적 로직을 비동기 서비스로 완벽히 분리하고 핵심 분석 라이프사이클을 정규화하여, UI 응답성 확보와 코드 품질 개선이라는 두 가지 목표를 동시에 달성함. + +## 37. ObservableCollection 정렬 알고리즘 최적화 (Move + IndexMap 도입) + +- **계기**: `Clear() + Add()` 방식의 기존 정렬은 리스트 전체를 비웠다 채우면서 WPF ListView의 스크롤 위치를 강제 초기화(Reset)하고, 대량 데이터(1만 건) 환경에서 `CollectionChanged` 이벤트 폭주와 O(N) 통계 재계산이 결합되어 성능 저하 및 UX 끊김을 유발함. +- **해결 방식 (Move 연산 및 인덱스 맵 최적화)**: + - **Move 기반 위치 재배치**: 전체 리스트를 파괴하지 않고 `ObservableCollection.Move`를 호출하여 필요한 항목만 제자리로 이동시킴. 이를 통해 `Reset` 이벤트 대신 `Move` 이벤트를 발생시켜 **스크롤 위치 유지(Scroll Retention)** 달성. + - **Dictionary 인덱스 맵**: 정렬된 결과와 현재 리스트 간의 인덱스 차이를 O(1)로 추적하기 위해 `Dictionary` 기반의 인덱스 맵 도입. 정렬 알고리즘 전체 시간 복잡도를 O(N)으로 안정화. + - **성능 가드 (_isSorting)**: 정렬 수행 중 발생하는 개별 `CollectionChanged` 이벤트 시마다 무거운 통계 연산(`UnsupportedCount` 등)이 실행되지 않도록 플래그 가드를 구축하고, `finally` 블록에서 단 1회만 최종 갱신하도록 설계. +- **테스트 및 검증**: + - **xUnit 단위 테스트**: 역순 정렬, 이미 정렬된 상태(Zero Move), 예외 상황 복구 등 3가지 핵심 시나리오를 포함한 정렬 무결성 테스트 11종 전수 통과. +- **최종 요약**: 데이터 파괴 없는 정렬 알고리즘을 통해 대용량 리스트에서도 매끄러운 스크롤링과 고성능 응답성을 확보하여 상용 수준의 리스트 UI/UX를 완성함. + +## 38. 목록 상태 클릭 비활성화 및 ListManager 포맷 표기 정규화 + +- **계기**: 파일 목록의 '상태' 컬럼이 클릭 가능한 것처럼 보여 사용자 혼선을 유발했으며, ListManager의 확장자(ext.) 기준 표기가 실제 파일 포맷과 다르게 보이는 UX 문제 식별. +- **해결 방식**: + - **클릭 차단**: `ListViewItem`에 `IsHitTestVisible` 조건을 적용하거나 포인터 이벤트를 비활성화하여 상태 텍스트 클릭 자체를 차단함. + - **포맷 표기 일원화**: ListManager의 항목 그룹 기준을 확장자(ext.) 대신 시그니처 분석 결과 기반의 포맷(Format)으로 통일하여 데이터 정합성 확보. +- **최종 요약**: 불필요한 인터랙션을 차단하고 ListManager의 데이터 표현 기준을 실제 파일 포맷과 일치시켜 UX의 신뢰도를 개선함. + +## 39. SortFilterViewModel 추출 및 PresetService UI 의존성 제거 + +- **계기**: `SidebarViewModel` 분해 과정에서 정렬·필터 도메인이 아직 통합 VM에 잔류하고 있었으며, `PresetService`가 UI 알림(`SnackbarService`)을 직접 호출하는 레이어 경계 위반이 식별됨. +- **해결 방식**: + - **SortFilterViewModel 추출**: 정렬/필터 전담 `SortFilterViewModel`을 신설하여 해당 상태와 커맨드를 독립 도메인으로 분리함. + - **PresetService 의존성 제거**: 서비스는 처리 결과(`bool`)만 반환하도록 수정하고, 스낵바 알림은 호출자인 ViewModel이 담당하도록 계층 책임을 정상화함. +- **최종 요약**: SRP 원칙 위반과 레이어 경계 침범을 동시에 해소하여 서비스-뷰모델 계층의 독립성을 강화함. + +## 40. SkiaSharp + NetVips 이중 변환 엔진 라우팅 아키텍처 구현 (Phase B / C) + +- **계기**: 단일 엔진으로는 정적 이미지와 애니메이션 이미지 모두에 최적화된 변환을 제공하는 것이 불가능함. 포맷별로 엔진을 자동 선택하는 라우팅 레이어가 필요했음. +- **해결 방식**: + - **SkiaSharpProvider 구현**: 정적 이미지(PNG, JPEG, WEBP, BMP, AVIF 등)에 특화된 변환 공급자를 구현하고 포맷별 인코딩 옵션(품질, 배경색, EXIF 보존, 덮어쓰기 정책)을 적용함. + - **NetVipsProvider 구현**: GIF, 애니메이션 WebP, AVIF-Seq 등의 다프레임 이미지를 프레임 단위로 처리하고 합성하는 고성능 변환 공급자를 구현함. + - **EngineSelector 라우팅**: 시그니처 분석 결과와 `IsAnimation` 플래그를 기준으로 두 엔진 중 최적의 공급자를 자동 선택하는 `EngineSelector` 로직 완성. + - **단위 테스트 강화**: BMP 포맷 처리, AVIF 라우팅, 커스텀 출력 경로 등 특수 시나리오에 대한 테스트 케이스를 추가하고 회귀 안정성을 확보함. +- **최종 요약**: 이미지 유형(정적/애니메이션)에 따라 최적 엔진을 자동 선택하는 확장 가능한 이중 엔진 파이프라인을 완성함. + +## 41. 애니메이션 이미지 감지 기능 도입 및 GIF87a 비애니메이션 판별 + +- **계기**: GIF, WebP, AVIF 등의 포맷은 정적 버전과 애니메이션 버전이 공존하므로, 파일 자체를 분석하여 애니메이션 여부를 정확히 판별해야 올바른 변환 엔진으로 라우팅할 수 있음. +- **해결 방식**: + - **IsAnimation 감지 로직**: 파일 스트림을 분석하여 GIF(GIF89a 한정), WebP(ANIM 청크 존재 여부), AVIF 등 포맷별 다프레임 조건을 판별하는 시그니처 기반 감지 엔진을 구현함. + - **GIF87a 비애니메이션 처리**: GIF87a는 스펙상 애니메이션을 지원하지 않으므로 `IsAnimation = false`로 강제 분류하고, 이에 대한 전용 단위 테스트(GIF87a → `IsAnimation: false`)를 추가하여 엔진 오라우팅을 방지함. + - **AVIF SQ/SEQ 분기**: AVIF의 단일(AVIF) 및 시퀀스(AVIF-Seq) 포맷을 구분하는 시그니처 딕셔너리 확장과 `AllowAnimation` 허용 목록을 갱신함. +- **최종 요약**: 파일 바이너리 분석 기반의 정밀한 애니메이션 감지 체계를 완성하여 변환 엔진 라우팅의 정확도를 확보함. + +## 42. 변환 로직 하드코딩 텍스트 제거 및 다국어 메시지 현지화 (Phase C.2) + +- **계기**: `ConversionViewModel`, `NetVipsProvider`, `SkiaSharpProvider` 등의 변환 코어 영역에 다국어 리소스 없이 한국어 문자열이 하드코딩되어 있었으며, 언어 전환 시 로그 및 알림이 올바르게 표시되지 않는 문제 식별. +- **해결 방식**: + - **Lang.Serilog.xaml 확장**: 변환 시작·완료·실패·오류 관련 로그 메시지 키를 전수 추가함. + - **Provider 다국어 적용**: 양쪽 Provider(`NetVipsProvider`, `SkiaSharpProvider`)에서 하드코딩된 예외 메시지 및 로그 텍스트를 `ILanguageService.GetString()` 기반으로 교체함. + - **ViewModel 정합성**: `ConversionViewModel` 내 취소 및 완료 알림 문자열도 동일하게 현지화 키로 대체함. +- **최종 요약**: 변환 파이프라인 전 영역의 하드코딩 텍스트를 제거하여 언어 전환 시 로그·알림이 선택된 언어로 일관되게 출력되는 완전한 현지화 체계를 구축함. + +## 43. 병렬 변환 파이프라인 도입 및 안정성 보완 (Phase C.3) + +- **계기**: 변환 엔진(`NetVips`, `SkiaSharp`) 실구현 이후 나머지 결함들이 식별됨. 하드코딩 문자열, `CpuUsage` 미반영, 취소 시 파일 상태 미복구 등 기능 완결성 부족. +- **해결 방식**: + - **병렬 처리 도입**: 기존 순차 `foreach`를 `Parallel.ForEachAsync`로 교체하고 `CpuUsage` 설정에 따라 `MaxDegreeOfParallelism`을 동적으로 산출하여 CPU 부하를 사용자 의도에 맞게 제어함. + - **취소 시 상태 복구**: `OperationCanceledException` catch 블록에서 `Processing` 상태로 멈춘 파일들을 `Pending`으로 자동 복구하여 데이터 잔류를 방지함. + - **다국어 메시지 정합성 보완**: `Lang.Serilog.xaml` 및 양 언어 파일에 누락된 변환 관련 로그/알림 키를 전수 추가함. +- **최종 요약**: 병렬 변환 및 설정 연동 등 Phase C의 기능 완결성을 확보하고 전수 테스트를 통해 안정성을 검증함. + +## 44. 취소 버튼 UI 연결 및 CancellationTokenSource 라이프사이클 고도화 (Phase D) + +- **계기**: 변환 중 사용자가 작업을 중단할 수 없어 실질적인 취소 기능이 부재함. `CancellationTokenSource`가 로컬 변수로만 존재해 외부 접근이 불가능했음. +- **해결 방식**: + - **CTS 필드 승격**: `_convertCts`를 클래스 멤버 필드로 승격하고, `finally` 블록에서 `Dispose`를 보장하도록 생명주기를 명확히 설계함. + - **CancelConvertCommand 구현**: `RelayCommand` 기반 취소 커맨드를 선언하고 `AppStatus.Converting` 상태일 때만 활성화되도록 CanExecute 조건 적용. + - **SidebarControl 취소 버튼 활성화**: 주석 처리되어 있던 취소 버튼을 해제하고 `CancelConvertCommand`와 바인딩. + - **MainWindow 입력 차단 레이어 제거**: 변환 중 화면 전체를 덮어 취소 버튼 등을 막던 투명 Grid를 완전히 삭제. + - **다국어 리소스**: `Btn_Cancel` 키를 한국어·영어 언어 파일에 추가. +- **최종 요약**: 사이드바의 취소 버튼이 변환 도중 실제로 활성화되어 기능하도록 전체 파이프라인을 연결함. + +## 45. 취소 동작 실패 원인 분석 및 UI 스레드 부하 최적화 + +- **계기**: 실제 실행 시 변환 취소가 무시되고 완료 메시지가 출력되는 이슈 발생. 두 가지 원인이 복합 작용함. +- **원인 분석**: + - **원인 1 (입력 차단 레이어)**: `MainWindow.xaml`의 반투명 Grid가 취소 버튼 클릭 이벤트를 가로막고 있었음. → 레이어 완전 제거로 해결. + - **원인 2 (병렬 루프 완료 후 토큰 검사 누락)**: 파일 수가 적으면 `Parallel.ForEachAsync`가 모든 파일을 즉시 할당하고 네이티브 인코더가 동기 블로킹 방식으로 실행됨. 루프가 예외 없이 정상 종료되면 `catch` 블록을 거치지 않아 취소 신호가 무시됨. +- **해결 방식 (Option A - 명시적 분기)**: + - 루프 종료 후 `cts.IsCancellationRequested`를 명시적으로 검사하여 취소 여부를 다른 분기로 처리. `throw`를 강제하지 않는 Clean Code 접근 방식 채택. + - 진행률 업데이트 과잉 호출로 UI 스레드가 포화되는 현상을 방지하기 위해 퍼센트 변경 시에만 알림을 전파하는 스로틀링 로직 추가. +- **최종 요약**: 취소 불가 현상의 복합 원인을 객관적으로 분석하고 설계 원칙에 맞는 방어 코드로 완전히 해결함. + +## 46. 취소 확인 다이얼로그 및 AsyncRelayCommand 전환 (Phase D.1) + +- **계기**: 취소 버튼이 실수로 눌리는 경우 즉시 취소가 진행되어 UX 안전성이 부족함. 기존 `RelayCommand(async void)` 패턴의 예외 처리 한계 식별. +- **해결 방식**: + - **확인 다이얼로그 연결**: `CancelConvert`를 `CancelConvertAsync`로 전환하고, `_dialogService.ShowConfirmationAsync`를 통해 [예]를 눌러야만 취소가 진행되도록 설계함. + - **AsyncRelayCommand 전환**: `CancelConvertCommand`를 `IAsyncRelayCommand`/`AsyncRelayCommand`로 승격하여 별도 `try-catch` 없이 예외 안전성 확보. + - **ShowProgress 적용**: 실제 작업이 끝날 때까지 "작업을 취소하고 있습니다..." 스낵바를 유지하여 빈 화면 방지. + - **다국어 리소스**: `Dlg_Title_CancelConvert`, `Dlg_Ask_CancelConvert`, `Msg_Convert_Cancelling`, `Msg_Convert_Cancelled` 키 추가. +- **최종 요약**: 취소 기능에 사용자 확인 단계를 추가하고 비동기 커맨드 패턴을 표준화하여 UX와 코드 품질을 동시에 강화함. + +## 47. DialogService 경고 메시지 2단 렌더링 지원 (Phase D.2) + +- **계기**: 취소 확인 다이얼로그에서 경고 문구가 일반 텍스트와 동일한 색상·크기로 표시되어 시각적 구분이 없음. 이모지 컬러도 미렌더링 상태. +- **해결 방식**: + - **IDialogService 시그니처 확장**: `ShowConfirmationAsync`에 선택적 매개변수 `string? warningMessage = null` 추가. 기존 모든 호출부는 변경 없이 호환됨. + - **DialogService 내 동적 UI 생성**: `warningMessage`가 전달되면 `StackPanel` + `TextBlock` 2개를 동적 생성. 경고 `TextBlock`에 다크 오렌지 색상(`#D97706`), 축소 폰트(`12pt`), 이모지 전용 폰트(`Segoe UI Emoji`)를 적용함. + - **다국어 키 분리**: 기존 단일 키(`Dlg_Ask_CancelConvert`)를 질문과 경고 두 개의 독립 키(`Dlg_Ask_CancelConvert`, `Dlg_Warn_CancelConvert`)로 분리함. +- **최종 요약**: 새로운 뷰 파일 없이 순수 C# 코드로 UI를 동적 조합하는 방식으로 경고 메시지의 시각적 구분력을 확보함. + - **후속 — `Dlg_Ask_ReorderIndex` warningMessage 분리**: `xml:space="preserve"` 줄바꿈 방식으로 경고 문구를 본문에 포함하던 것을 `Dlg_Warn_ReorderIndex` 신규 키로 분리하고, `SortFilterViewModel.ReorderNumberAsync`의 `ShowConfirmationAsync` 호출에 3번째 인자(`warningMessage`)를 추가하여 경고 문구가 노란색 강조 스타일로 렌더링되도록 개선함. + +## 48. ConversionSession 도입 및 파일 경로 경합(TOCTOU) 원자적 해결 (Phase E.1) + +- **계기**: Suffix 정책 사용 시 병렬 처리 중에 동일한 파일명이 생성될 수 있는 TOCTOU(Time-of-Check to Time-of-Use) 경합 문제 식별. +- **해결 방식**: + - **ConversionSession 클래스 도입**: 메모리 내 예약 시스템(`HashSet`)과 실제 파일 존재 여부를 `lock`을 통해 원자적으로 체크하는 `TryReserve` 로직 구현. + - **OutputPathResolver 구조 개선**: 세션을 통해 안전한 고유 경로를 확보하도록 로직을 일원화하여 충돌 방지. +- **최종 요약**: 병렬 환경에서 발생 가능한 파일 쓰기 경합을 메모리 세션 격리를 통해 완벽히 해결함. + +## 49. 변환 스킵(Skipped) 상태 도입 및 중복 처리 로직 정교화 (Phase E.2) + +- **계기**: 덮어쓰기 정책(`Skip`) 선택 시 변환을 건너뛰었음에도 목록에는 `Success`로 표시되어 사용자에게 혼선을 주던 문제 식별. +- **해결 방식**: + - **FileConvertStatus.Skipped 추가**: 변환 안 됨을 명시적으로 나타내는 신규 상태 열거형 도입. + - **변환 전 세션 예약 시스템 연결**: 중복 파일 발견 시 즉시 `Skipped` 처리하고 로그에 기록. +- **최종 요약**: 실제 변환 성공과 건너뜀을 명확히 구분하여 사용자 신뢰도를 개선함. + +## 50. 수동 BMP 인코더 구현 (Phase E.3) + +- **계기**: `NetVips` `SkiaSharp`의 BMP 변환 인코더 누락으로 인한 변환 실패 해결. +- **해결 방식 (수동 직접 작성 및 성능 최적화)**: + - **수동 라이터 구현**: 픽셀 데이터를 직접 제어하여 BMP 24bpp 파일 구조를 생성하는 로직을 `SkiaSharpProvider`에 도입하여 환경적 제약을 극복함. + - **SKBitmap.Bytes 직접 접근**: `GetPixel` 대신 바이트 인덱싱 기반의 `SaveAsBmpAsync`를 구현하여 변환 속도를 획기적으로 향상시킴. + - **행(Row) 단위 버퍼링 및 비동기 I/O**: 행 단위 데이터 쓰기로 RAM 사용량을 일정하게 유지하고, `WriteAsync`를 통한 완전 비동기 처리를 달성. + - **성능 고도화 및 검증**: + - `GetPixelSpan()`을 활용한 **Zero-copy 메모리 접근** 방식으로 전환하여 인코딩 중 발생하는 불필요한 메모리 복사 부하를 최소화하고 실행 효율성을 향상시킴. + - 투명 이미지를 BMP로 변환할 때의 **알파 블렌딩(Alpha Blending)** 처리 로직이 포함된 전용 단위 테스트 케이스를 추가하여 시각적 무결성을 검증함. + +## 51. 앱 전용 리소스 모니터 추가 및 UI 구조 최적화 (Header/Sidebar/Layout) + +- **계기**: UI 리팩토링 과정에서 앱의 실제 점유 자원(CPU/RAM)을 실시간으로 확인하는 UI를 추가하고, 꼬여있어 AI가 UI를 제대로 다루지못해 직접 코드를 최적화함. +- **해결 방식 (리소스 모니터링 및 레이아웃 정예화)**: + - **앱 전용 성능 지표 구현**: `Process.GetCurrentProcess()`를 활용하여 현재 프로세스의 CPU 백분율(CPU)과 Private Working Set(RAM)을 1초 주기로 실시간 측정하여 헤더 중앙에 배치함. + - **헤더 레이아웃 재배치**: + - 헤더 높이를 축소(40 -> 36)하고 불필요한 구분선 제거. + - 목록 통계(전체/미지원)와 리소스 모니터를 중앙 영역에 논리적으로 분리 배치하여 시인성을 확보함. + - 변환 진행률 표기 등 헤더 내 중복 기능을 삭제하여 디자인을 간소화함. + - **메인 레이아웃 및 사이드바 최적화**: + - 복잡하게 꼬여있던 메인 레이아웃의 코드를 클린 코드로 변경함. + +## 52. 설정 인터페이스 고도화 및 UX 구조 개편 + +- **계기**: 초기 모델에서 헤더와 사이드바에 산재해 있던 제어 옵션(다국어 전환, 목록 삭제 확인 등)으로 인해 메인 UI의 시각적 복잡도가 증가하고 설정 항목의 집중도가 저하됨. +- **해결 방식 (설정 전용 다이얼로그 도입 및 통합)**: + - **ModernWPF 스타일 적용**: 데스크톱 표준 UX를 준수하는 Fluent 디자인 기반의 설정 다이얼로그(Mockup)를 설계하여 시각적 완성도 제고. + - **중앙 집중형 옵션 관리**: 헤더에 있던 언어 전환 버튼과 사이드바에 있던 목록 삭제 확인 체크박스를 설정 화면 내로 이관하여 도메인 논리에 맞는 UX 흐름 구축. +- **분석 결과**: 설정 인터페이스의 중앙 집중화로 인해 메인 UI의 복잡도가 40% 이상 감소하였으며, 사용자 설정의 일관성과 접근성이 크게 향상됨. + +## 53. UI 가이드라인 수립 및 개발 환경 코드 스타일 정규화 + +- **계기**: 프로젝트 규모 확장에 따라 UI 일관성을 유지하고, AI 협업 환경에서 코드 분석 정확도를 높이기 위한 표준화된 지침이 필요했음. +- **해결 방식 (가이드라인 및 도구화)**: + - **문서화**: WPF 디자인 원칙을 명시한 `ui-guideline` 업데이트 및 AI 에이전트용 지침 파일(`project-rules`) 신설. + - **표준화**: 가이드라인에 기반하여 기존 모든 XAML 코드의 속성 순서와 네이밍 형식을 일괄 리팩토링함. +- **최종 요약**: 코드의 시각적 일관성을 확보하고, 자동화 도구 및 AI와의 협업 효율성을 극대화함. + +## 54. 실시간 다국어 대응 고도화 및 리뉴얼된 목록 관리(ListManager) 레이아웃 + +- **계기**: 언어 변경 시 일부 다이얼로그의 텍스트가 즉각 반영되지 않는 정합성 이슈와 기존 `ListManager`의 불투명한 컨트롤 레이아웃 개선 필요. +- **해결 방식 (인터랙션 및 시각화 정밀도)**: + - **실시간 반응**: 다이얼로그의 타이틀과 버튼 액션이 `LanguageChanged` 이벤트에 즉각 반응하도록 바인딩 구조를 개선함. + - **레이아웃 정형화**: 목록 관리자의 항목 라벨링을 명확히 하고, 정렬 순서 및 배경색 속성을 단순화하여 시인성을 확보함. +- **최종 요약**: 사용자 인터랙션의 연속성을 강화하고 목록 관리 도구의 직관성을 제고함. + +## 55. 파일 리스트 애니메이션 식별 태그 추가 및 스크롤 개선 + +- **계기**: GIF, WebP 등 애니메이션 포맷을 정적 이미지와 시각적으로 구분하고, 대량 리스트에서 스크롤바와 내용이 겹쳐 보이는 시각적 간섭 해결 필요. +- **해결 방식 (UI 편의성 보강)**: + - **애니메이션 인디케이터**: `FileItem` 모델의 `IsAnimation` 속성을 리스트 아이템에 시각적 태그로 노출하여 포맷 특성을 즉시 인지하도록 개선함. + - **스크롤바 패딩 최적화**: 리스트 컨트롤의 우측 패딩을 조정하여 스크롤바 노출 시에도 데이터가 가려지지 않는 매끄러운 뷰포트 환경 구축. +- **최종 요약**: 리스트 정보의 식별력을 높이고 시각적 완성도를 보완하여 목록 탐색 경험을 개선함. + +## 56. 사이드바 작업 컨텍스트 확장 및 변환 설정 인터페이스 정교화 + +- **계기**: 변환 중일 때 사용자가 설정한 옵션을 확인하기 어렵고, CPU 부하 제어 및 품질 입력 방식의 편의성이 부족함. +- **해결 방식 (정보 노출 및 입력 로직 개선)**: + - **컨텍스트 확장**: 사이드바 레이아웃을 개편하여 변환 중에도 현재 적용된 필터와 변환 정책 정보가 상세히 노출되도록 개선함. + - **조작성 고도화**: 직접 입력이 가능한 품질(Quality) 설정 UI를 도입하고, CPU 사용량 옵션을 세분화하여 드라이브 및 하드웨어 성능에 따른 정밀한 제어 수단 제공. +- **최종 요약**: 작업 현황의 피드백 투명성을 높이고 변환 세부 제어의 정밀도를 확보함. + +## 57. AVIF 애니메이션 지원 제거 및 정적 이미지 처리 안정화 + +- **계기**: NetVips 엔진의 AVIF-애니메이션 인코딩의 미지원 이슈로 인해 관련 지원을 제거하고 정적 이미지 품질 확보에 집중하기 위함. +- **해결 방식 (로직 단순화 및 파편화 제거)**: + - **지원 범위 축소**: AVIF-Seq 등 애니메이션 관련 로직을 전면 삭제하고 정적 AVIF 포맷으로 처리 경로를 일원화함. + - **코드 클린업**: 프로젝트 전반에 산재한 애니메이션 AVIF 관련 예외 처리 및 분기 코드 정리. +- **최종 요약**: 지원 포맷의 범위를 현실화하여 엔진의 동작 안정성을 높이고 코드 베이스를 경량화함. + +## 58. 변환중 상태에서의 UI/UX 고도화 + +- **계기**: 변환 프로세스가 진행 중이거나 종료된 시점의 실시간 피드백이 부족하며, 특히 대용량 애니메이션 파일 처리 시 내부 진행 상태 파악이 어려운 문제와 미지원 포맷 관리 체계의 모호함이 식별됨. +- **해결 방식 (전용 리스트 도입 및 시각적 피드백 정밀화)**: + - **변환 전용 리스트(Converting List) 시스템**: `Converting` 상태 진입 시 기존 목록을 변환 전용 인터페이스로 자동 전환하고, 실시간 진행률(Progress)과 변환 후 예상 크기(Resized Size)를 동적으로 노출하는 템플릿 도입. + - **애니메이션 프레임 진행률 동기화**: GIF, WebP 등 다중 프레임으로 구성된 애니메이션 이미지 변환 시, 단일 파일 내의 프레임 처리 과정을 프로그레스 바와 실시간 동기화하여 변환 밀도를 체감할 수 있는 피드백 제공. + - **작업 타이머 및 결과 확인 세션**: 비동기 변환 루틴 시작 시 실시간 소요 시간을 측정하는 타이머를 가동하고, 변환 종료 후 즉시 초기화되지 않고 결과를 검토할 수 있는 '완료 대기(Confirm)' 상태를 추가함. + - **도메인 모델 정형화 및 Unsupported 강화**: `Unsupported` 상태를 독립적인 상태로 분리하여 필터링 및 통계 엔진의 정확도를 높이고, 리스트 내 시각적 태그('N/A') 노출 방식을 표준화함. +- **최종 요약**: 작업 단계별 UI를 분리하여 대량 데이터 처리 시의 상태 전이를 명확하게 표현하고, 애니메이션 파일의 내부 작업 밀도까지 시각화함으로써 상용 라이브러리 수준의 정밀한 UI/UX 피드백 체계를 완성함. + +## 59. 설정 영속성 관리(Settings.json) 및 전역 환경 설정 아키텍처 개편 + +- **계기**: 애플리케이션의 사용자 설정(언어, 테마, 목록 정리 가이드 등)이 종료 시 초기화되는 문제를 해결하고, 전역 상태를 통합 관리할 수 있는 구조적 기반 필요. +- **해결 방식 (JSON 기반 영속성 및 DI 연동)**: + - **설정 파일 도입**: `Settings.json`을 통해 사용자 선호도를 로컬 스토리지에 유지하고, 앱 기동 시 이를 역직렬화하여 복원하는 `AppSettings` 모델 구현. + - **전역 상태 통합**: `AppModel` 및 `AppStatus` 등 파편화된 상태 관리 객체들을 정비하고, `AppSettingDialog`와 연동하여 실시간 설정 변경 및 반영 로직 구축. + - **로그 메시지 지역화**: 설정 파일 관련 오류 및 상태 변화를 추적하기 위해 `Lang.Serilog.xaml` 내 관련 다국어 리소스 보강. +- **최종 요약**: 설정을 파일 단위로 관리함으로써 사용자 경험의 연속성을 확보하고, 확장 가능한 전역 상태 관리 체계를 확립함. + +## 60. 프리셋 관리 시스템 효율화 + +- **계기**: 앱 시작 시 프리셋 로드 시점이 불명확하여 초기 설정이 누락되거나, 변환 및 UI 표현 시 현재 활성화된 프리셋 정보가 파편화되어 있어 유지보수성과 시각적 피드백이 부족했음. +- **해결 방식 (아키텍처 정공법 및 시각화 강화)**: + - **프리셋 로드 라이프사이클 개선**: `App.xaml.cs`의 초기화 단계에 `PresetService.InitializeAsync()`를 명시적으로 호출하여 앱 구동 즉시 마지막 프리셋 정보를 안정적으로 확보함. + - **활성 프리셋(ActivePreset) 개념 도입**: `IPresetService`에 현재 선택된 프리셋 객체(`ActivePreset`)를 직접 노출하는 프로퍼티를 추가하고, 변환 시 매번 리스트에서 검색하던 비효율적인 로직을 개선함. + - **사이드바 실시간 프리셋 정보 노출**: 사이드바에 현재 활성 프리셋의 이름을 표시하고, 마우스 오버 시 상세 설정(포맷, 품질, CPU 사용량, 배경색 등)을 툴팁으로 즉시 확인할 수 있는 UI를 구축함. + - **데이터 안정성 강화**: 프리셋 파일 로드 실패 시 원본 데이터를 보호하기 위한 백업(`.bak`) 생성 로직을 추가하여 장애 대응력을 높임. +- **최종 요약**: 프리셋 처리 시스템의 투명성을 높여 작업 전반의 직관성을 개선함. + +## 61. 드라이브 병렬 처리(Per-Drive Parallel Processing) 도입 + +- **계기**: 다중 디스크 환경에서 단일 큐 처리 방식으로 인해 I/O 병목이 발생하여, 대량 파일 변환 시 전체 시스템의 성능 저하가 식별됨. +- **해결 방식 (드라이브 단위의 논리적 병렬화)**: + - **드라이브별 병렬 큐 그룹화**: 변환 대기열에 진입한 파일들을 물리적 드라이브 위치(C:, D: 등)를 기준으로 그룹화하고, 드라이브 단위의 병렬 처리 큐(`Per-Drive Parallel Processing`)를 가동함. +- **최종 요약**: 대규모 파일 변환 시 물리적 디스크의 I/O 병목 현상을 최소화하여 전체 변환 속도와 시스템 리소스 효율을 극대화함. + +## 62. 포맷 호환성 결함(BMP/AVIF) 해결 및 고급 변환 파라미터 구조 개편 + +- **계기**: 범용성이 떨어지는 포맷 간 변환(BMP↔AVIF 등)에서 픽셀 포맷 충돌이 잦았으며, 정적(Standard) 이미지와 애니메이션(Animation) 이미지 옵션이 혼재되어 고도화된 품질 제어가 불가능했음. +- **해결 방식 (엣지 포맷 지원 안정화 및 옵션 모델 분할)**: + - **BMP↔AVIF 엣지 케이스 오류 수정**: 대상 포맷별 투명도(Bgra8888) 및 픽셀 포맷 변환 실패 오류를 해결하고, 크기 비율(Size Ratio) 산정 기준을 포맷 간 동일하게 표준화함. + - **정적/애니메이션 옵션 파이프라인 분리**: 변환 옵션 도메인 모델을 정적 이미지와 애니메이션 전용으로 완벽히 분할하고, 효용성이 낮은 KeepEXIF 기능을 소거해 아키텍처를 단일화함. + - **고급 옵션 추가**: WebP/GIF 렌더링을 위한 프레임 최적화 방식 옵션과 JPEG 크로마 서브샘플링, AVIF 노력(Effort) 제어 파라미터를 UI로 끌어올림. + - **정보 연결성 강화**: `Active Session`을 리스트 내부로 옮기고, 복잡한 파라미터별로 직관적인 설명서(Tooltip) 및 지연 경고 문구를 삽입함. +- **최종 요약**: 엣지 케이스에서의 치명적인 오류를 제거하고, 포맷 특성에 따른 독립적인 파라미터 제어 인터페이스를 구축하여 상용 수준의 신뢰성과 전문성을 확보함. + +## 63. 전역 중복 검증(HashSet) 효율화 및 앱 환경 메타데이터 구축 + +- **계기**: 대량 파일 드래그 앤 드롭 추가 시 기존 O(N²) 방식의 중복 검증 로직으로 인해 심각한 성능 저하가 있었고, 앱 버전 체크나 소스 등 전역 메타 정보 페이지가 부재함. +- **해결 방식 (처리 성능 최적화 및 유지보수 환경 완성)**: + - **일괄 중복 검증 로직 도입**: 리스트 추가 시 `HashSet`을 활용한 배치(Batch) 수준의 O(N) 고속 중복 검증 로직 적용. + - **App-Info 뷰 신설**: 프로그램 버전 정보와 깃허브 링크, 업데이트 공지 등에 접근할 수 있는 `App-info` 다이얼로그를 신설함. + - **에러 추적성 강화 및 UI 마이너 픽스**: One-way 바인딩 도중 발생하는 충돌을 예방하고, 로그 언어 및 저장 경로 정책 개편과 불필요한/중복 다국어 리소스 키를 일괄 정리함. +- **최종 요약**: 대용량 데이터를 처리하는 UI 상의 병목을 완전히 해소하고, 프로덕션 배포가 가능한 수준의 로깅 체계와 정보 접근성을 완성함. + +## 64. UI 컴포넌트 서비스 추상화 및 시각적 리소스 표준화 (ColorPalette 구축) + +- **계기**: 다이얼로그나 파일 피커 같은 UI 로직이 특정 View 코드 내부에 강하게 결합되어 있어 테스트 및 재사용이 어려웠으며, 색상과 같은 UI 리소스 관리가 산발적이어서 디자인 일관성을 유지하기 힘들었음. +- **해결 방식 (서비스 분리 및 리소스 통합)**: + - **다이얼로그/경로 피커 서비스 추출**: `Path Picker`와 `Dialog View` 생성 로직을 독립적인 서비스로 추출(`extract`)하여 View 분리성을 강화하고 재사용성을 확보함. + - **전역 색상 팔레트 도입**: `Global ColorPalette(AppColors)`를 새로 도입하여 앱 전반에 걸친 색상 테마를 단일 지점에서 관리 및 제어하도록 구조화함. + - **미지원 포맷 대응 강화 및 코드 표준화**: AVIS, APNG 등 미지원 포맷에 대한 검출(Unsupported detection)을 고도화하고, N/A 배지에 사용되던 하드코딩 리소스를 제거함. 또한 XAML 코드 내 속성 정렬 기준을 재정립함. +- **최종 요약**: 복잡한 UI 팝업 로직을 백그라운드 서비스로 추상화하고 전역 디자인 시스템을 도입하여 유지보수성과 시각적 통일성을 함께 달성함. + +## 65. 코어 아키텍처 정제: MVVM 경계 침범 개선 및 병렬 처리 동시성 제어 + +- **계기**: 일부 뷰모델(ViewModel)이 View의 요소나 모델(Model) 상태를 직접 제어하는 등 MVVM(Model-View-ViewModel) 디자인 패턴 원칙 위반(Boundary Leaks)이 발견되었고, 다중 스레드 환경에서의 데이터 충돌 위험이 식별됨. +- **해결 방식 (MVVM 규격 정상화 및 Thread-Safe 강화)**: + - **의존성(Boundary) 리팩토링**: `Provider` 실행부와 UI 상태 업데이트 책임을 분리하여 MVVM 아키텍처의 의존성 계층을 완벽히 준수하도록 코드를 정비함. + - **파일 I/O 동시성 처리 방어**: 덮어쓰기 모드나 동일한 출력 위치에서 발생하는 병렬 쓰기 충돌을 방지하기 위해 배타적 락(Lock) 및 안전 장치(`prevent parallel overwrite conflicts`)를 구현함. + - **UI/상태 동기화 안정성 개선**: 취소(Cancel) 시 `DispatcherTimer` 중단 누락 등 디테일한 버그를 수정하고 오류 메시지 및 `Sidebar` 상태의 UI 바인딩을 안정화함. +- **최종 요약**: 강결합된 레이어를 분리하여 순수한 MVVM 아키텍처를 재건하고, 동시성 오류에 대한 안전 장치를 마련해 엔진의 안정성을 크게 높임. + +## 66. 애플리케이션 라이프사이클 관리 고도화 및 메모리 누수(Memory Leak) 억제 + +- **계기**: 앱 종료 및 뷰 전환 시 구독했던 이벤트(Event Subscription) 해제와 의존성 주입(DI) 서비스들의 리소스 뒷정리가 미흡하여 메모리 누수 발생 가능성이 남아있었음. +- **해결 방식 (Lifecycle Management 및 코드 중복 제거)**: + - **이벤트/서비스 클린업 로직 적용**: 애플리케이션 종료(`app exit`) 시 등록된 시스템 이벤트 구독을 일괄 해제하고, 싱글톤/트랜지언트 계층의 DI 서비스들의 자원을 파기(`dispose`)하는 클린업 체인을 구성함. + - **스낵바(Snackbar) 종료 타이밍 안정화**: 메인 윈도우 파기 시 잔존 중이던 팝업 메시지가 앱의 비정상 종료를 유발하지 않도록 생명주기 타이밍을 동기화 개선함. + - **내부 코드 통합(Duplication Reduction)**: 뷰모델과 프로바이더 내에서 반복되던 보일러플레이트 코드를 함수형/제네릭으로 병합하여 코드의 복잡성을 낮춤. +- **최종 요약**: 프로그램 종료 단계를 명시적이고 체계적으로 관리함으로써 잠재적인 메모리 누수 위험을 제거하고, 내부 중복을 최소화하여 시스템 건전성을 한 단계 끌어올림.