# AI Photo Organizer 얼굴 인식 + 촬영일(EXIF) 기준으로 사진을 **로컬에서** 자동 정리하는 Electron 데스크톱 앱. 클라우드 업로드 없이 내 PC 안에서만 동작한다. > 기획·설계 문서: [docs/PRD.md](docs/PRD.md) · [docs/DECISIONS.md](docs/DECISIONS.md) · [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) ## 동작 방식 1. 인물 프로필(최대 3명)과 참조 얼굴 사진을 등록한다. 2. 정리할 폴더(소스)와 결과 폴더(출력)를 고른다. 3. [정리 시작] → 각 사진을 스캔해 - 얼굴이 매칭되면 `출력/<인물>/YYYY/MM/` 로 **이동**(2·3순위 인물에게는 **복사**) - 매칭 인물이 없으면 `출력/Unsorted/YYYY/MM/` 로 이동 - **영상 파일**(`.mp4 .mov .avi .mkv .webm .m4v`)은 얼굴인식 없이 `출력/Movie/YYYY/MM/` 로 이동 - EXIF 촬영일이 없으면 파일 수정일로 대체 데이터 안전: 이동은 **복사 → 무결성 검증 → 원본 삭제** 순서로 수행하고, 파일명 충돌 시 `_1`, `_2` 로 자동 리네임한다(덮어쓰기 없음). ## 기술 스택 Electron 33 · electron-vite · React 18 + TypeScript · Zustand · Tailwind · [@vladmandic/face-api](https://github.com/vladmandic/face-api) (WebGL) · exifr · electron-builder 3개 프로세스로 분리된 구조: - **Main** (Node): 스캔 / EXIF / 파일 이동·복사 / 오케스트레이션 - **UI Renderer** (React): 화면 — 무거운 연산 없음 - **Inference Renderer** (숨김 창): face-api 얼굴 인식 전담 ## 개발 ```bash npm install npm run models:download # 최초 1회 — 모델 가중치 받기 npm run dev # 개발 실행 (HMR) ``` ## 검증 / 빌드 ```bash npm run typecheck # 타입체크 (node + web) npm test # 순수 로직 단위 테스트 (Vitest) npm run dist:all # Windows(nsis) + macOS(dmg) 인스톨러 빌드 ``` > macOS 타깃은 macOS 호스트에서 빌드해야 코드사이닝/공증이 가능하다(미서명 dmg는 어디서나 생성 가능). ## 트러블슈팅 - **`TypeError: Cannot read properties of undefined (reading 'whenReady')`** 로 부팅 즉시 크래시하면, 환경에 `ELECTRON_RUN_AS_NODE=1` 이 설정된 것이다. 이 변수가 있으면 Electron 바이너리가 일반 Node로 동작해 `electron.app` 이 `undefined` 가 된다. 실행 전 변수를 해제하라: - PowerShell: `Remove-Item Env:\ELECTRON_RUN_AS_NODE` - bash: `unset ELECTRON_RUN_AS_NODE` ## 폴더 구조 ``` src/ main/ Main 프로세스 (scanner, exif, fileOps, orchestrator, ...) preload/ contextBridge (UI용 index, 추론창용 inference) renderer/ React UI inference/ 숨김 추론 창 (faceEngine, imageLoader) shared/ 공유 타입/상수 models/ face-api 가중치 (download 스크립트로 채움) tests/ Vitest 단위 테스트 docs/ 기획·설계 문서 ```