d3ro-voice/memory/project_status.md
yunchan8804 77d514222e feat(V2-5): macOS 빌드 지원 — 플랫폼 분기 + electron-builder mac 타겟 + CI
플랫폼 분기 (paths.ts):
- EXE_SUFFIX 상수로 sox/sidecar/ffmpeg 실행파일 확장자 통합
- Windows에선 .exe 자동 부착, Mac/Linux에선 빈 문자열
- 미사용 getProjectRoot 헬퍼 제거

런타임 서비스 Mac 분기:
- SoundEffectService: darwin → /usr/bin/afplay,
  linux → aplay 분기 추가 (execFile로 안전하게)
- ScreenContextService._getActiveWindowInfo:
  win32 → PowerShell + user32.dll (기존),
  darwin → osascript (System Events frontmost process + 윈도우 타이틀)
  Linux는 미지원 (null)

electron-builder.yml:
- mac 타겟 추가 (dmg + zip, arm64 + x64 매트릭스)
- hardenedRuntime, gatekeeperAssess, entitlements 설정
- extendInfo로 NSMicrophoneUsage / NSCameraUsage / NSAppleEvents /
  NSSystemAdministration 권한 메시지
- dmg 레이아웃 (드래그 to /Applications)
- linux AppImage placeholder
- notarize: false 기본, NOTARIZE 환경변수로 활성화

build/entitlements.mac.plist:
- allow-jit, allow-unsigned-executable-memory (Electron 필수)
- audio-input, camera, network.client
- automation.apple-events (활성 윈도우 조회용)
- files.user-selected.read-write
- allow-dyld-environment-variables (sox/ffmpeg 라이브러리 로드)

scripts/build-sidecar.py:
- IS_WINDOWS / IS_MACOS / EXE_SUFFIX 도입
- Windows에서만 --noconsole 플래그
- 빌드 결과 경로 + size 출력 플랫폼 통합

scripts/install-sox.sh (신규):
- Mac/Linux용 SoX 번들 스크립트
- macOS는 otool로 dylib 의존성 식별 후 함께 복사,
  install_name_tool로 rpath를 @loader_path로 변경
- electron-builder의 extraResources 대상 디렉토리에 배치

resources/icons/ (신규):
- README.md만 커밋, 실제 아이콘 파일은 분리
- sips/iconutil/imagemagick으로 .icns/.ico/.png 생성 가이드

.github/workflows/build-mac.yml (신규):
- macos-14 runner (Apple Silicon), arm64/x64 matrix
- brew sox, npm install, @electron/rebuild,
  install-sox.sh, build-sidecar.py, electron-builder dist
- CSC/NOTARIZE 환경변수 자동 처리
- artifact 업로드 (dmg + zip, retention 7일)

docs/v2/phase-V2-5-mac-guide.md (신규):
- 사전 조건, 시스템 의존성, dev 실행, dist 빌드,
  Code signing + Notarization, CI 트리거, 트러블슈팅

검증 (Windows에서):
- typecheck 통과 (Mac 분기 추가에도 회귀 없음)
- build 통과
- dev 런타임 정상

Mac 검증은 사용자 본인 Mac에서 수행 (V2-5 사용자 액션).
2026-04-08 15:57:16 +09:00

15 KiB

D3RO-VOICE 프로젝트 현황

마지막 갱신: 2026-04-08 규칙 13: 작업 완료 즉시 이 파일 갱신 의무

현재 단계

V1 (Electron) 완료V2 (Monorepo) 진행 중

  • Phase V2-1 완료 (Monorepo 전환 — a/b/c/d)
  • Phase V2-2 🟡 로컬 작업 완료, 사용자 Supabase 배포 대기
  • Phase V2-5 🟡 로컬 작업 완료, 사용자 Mac 검증 대기
    • paths.ts 플랫폼 분기, electron-builder.yml mac 타겟, entitlements, SoundEffectService(afplay)/ScreenContextService(AppleScript) Mac 분기, build-sidecar.py 크로스 플랫폼, install-sox.sh, GitHub Actions Mac CI
    • 가이드: docs/v2/phase-V2-5-mac-guide.md
  • 다음: Phase V2-3 (Web App MVP — Next.js) 또는 V2-4 (데스크톱 동기화)
  • V2-2 사용자 액션이 끝나면 V2-3 진행 가능

V1 완료 페이즈

Phase 내용 상태
1~9 기본 음성 어시스턴트 (STT/LLM/TTS/핫키/팝업)
10 Killer features (메모, 보이스 커맨드, 스크린 컨텍스트, 체인, 캡션)
11 Monetization (라이선스, 쿼터)
12 Pro features (파일 전사, 회의 요약, 딕테이션 템플릿)
13 음성 대화, RAG, 보이스 액션
14 회의 모드
14.5 회의 고도화 (다중 문서 생성/편집/내보내기)
15 Auto Polish + AI 채팅 + 마인드맵 + 공유
15.5 화자 구분 (LLM 추정 + pyannote)

추가 개선사항 (post-15.5)

  • 히스토리/회의 목록 반응형 그리드 + 카드 UI
  • 설정 LLM 모델 드롭다운
  • 오디오 테스트 실시간 레벨 미터
  • Ollama 미실행 시 설치 경로 탐색 후 자동 스폰 (2026-04-08)

V2 진행 상황

Phase V2-1: Monorepo + Core 추출 — 진행 중

Sub-phase 범위 상태
V2-1a npm workspaces + apps/desktop으로 V1 이동 완료
V2-1b packages/core 추출 (types, errors, ipc-channels, constants, utils) 완료
V2-1c packages/ui 추출 (DS 컴포넌트 + theme + theme-vars) 완료
V2-1d packages/i18n 추출 (locale JSON + 훅) 완료

V2-1d 완료 내역

  • packages/i18n/ (@d3ro/i18n) 신규 생성:
    • src/locales/ 12개 JSON (ko/en/ja/zh/zh-TW/es/fr/de/pt/ru/vi/th)
    • src/index.tsx: TFunction, Locale, LOCALE_META, resolveTranslation, createFormatDate/Number/RelativeDate/Time, I18nContext, useI18n, I18nProvider
  • Electron 독립성 확보: I18nStorage interface 추가 (load/save 어댑터)
    • 기존 window.electronAPI.config 직접 호출 → storage prop 주입 패턴
    • 기본값은 noopStorage (메모리 한정)
  • apps/desktop/src/renderer/App.tsxelectronI18nStorage 어댑터 구현 후 <I18nProvider storage={electronI18nStorage}>로 주입
  • apps/desktop 설정:
    • @d3ro/i18n: "*" dep 추가
    • tsconfig paths, vite alias, externalize exclude에 @d3ro/i18n 추가
  • 일괄 치환: ./i18n, ../i18n, ../../i18n@d3ro/i18n (29 파일)
  • apps/desktop/src/renderer/i18n/ 디렉토리 완전 제거

V2-1d 검증

  • typecheck
  • build
  • dev 런타임 (DB/핫키/Ollama/Main window 모두 정상)
  • Electron 의존이 완전히 apps/desktop에만 남아 monorepo 원칙 준수 (packages/i18n은 React에만 의존, 웹/모바일에서 그대로 재사용 가능)

V2-1c 완료 내역

  • packages/ui/ (@d3ro/ui) 신규 생성:
    • src/theme.ts (d3roPalette/d3roTypo/d3roShadow SSOT 전체)
    • src/theme-vars.ts (팝업/main 프로세스용 CSS 변수 맵)
    • src/components/ds/{CrtDisplay, InstrumentPanel, Led, MetalCard, MetalDial, PhosphorText, PhysicalButton, ScreenPanel, ButtonGroup, index}.tsx
    • src/index.ts barrel
  • packages/ui/package.json: React/MUI/Emotion은 peerDependencies, @d3ro/core만 직접 dep
  • apps/desktop/src/shared/ 디렉토리 완전 제거 (theme-vars가 마지막이었음)
  • subpath exports: ./theme, ./theme-vars, ./components/ds
  • DS 컴포넌트 내부 ../../theme 상대 경로는 그대로 유효 (packages/ui 내부에서 해결)
  • 일괄 치환:
    • ../theme, ../../theme, ./theme@d3ro/ui/theme
    • ../components/ds, ../../components/ds, ./ds, ../ds@d3ro/ui/components/ds
    • ../ds/<Component>, ../../ds/<Component>@d3ro/ui/components/ds (세부 파일 import는 barrel로 통합)
    • @shared/theme-vars@d3ro/ui/theme-vars (WindowManager 1건)
  • apps/desktop/tsconfig.node/web.json: @shared/* paths 완전 제거, @d3ro/ui, @d3ro/ui/* paths 추가, include에서 src/shared/**/* 제거
  • electron.vite.config.ts: @shared alias 제거, @d3ro/ui alias 추가, externalize exclude에 @d3ro/ui 추가
  • vitest.config.ts: alias 교체

V2-1c 검증

  • typecheck
  • build
  • dev 런타임 (DB/핫키/Ollama/Main window 정상)
  • apps/desktop/src/shared/ 디렉토리 자체가 사라져 @shared/*는 이제 프로젝트에 존재하지 않음

V2-1b 완료 내역

  • packages/core/ 패키지 신규: @d3ro/core, subpath exports (types/errors/ipc-channels/constants/utils/*), docx dep 포함
  • 6개 파일 git mvpackages/core/src/로 이동:
    • apps/desktop/src/shared/{types,errors,ipc-channels,constants}.ts
    • apps/desktop/src/main/utils/{meeting-markdown,markdown-to-docx}.ts
  • packages/core/src/index.ts barrel export 추가
  • apps/desktop/package.json"@d3ro/core": "*" dep 추가
  • apps/desktop/tsconfig.node.json, tsconfig.web.jsonpaths@d3ro/core/* 추가, @shared/*는 theme-vars용으로 유지
  • apps/desktop/electron.vite.config.ts alias 3개 섹션에 @d3ro/core 추가 + M1 수정: resolve('src/shared')resolve(__dirname, 'src/shared')
  • externalizeDepsPlugin exclude에 @d3ro/core 추가 (main/preload 둘 다)
  • apps/desktop/vitest.config.ts@d3ro/core alias 추가
  • 일괄 치환: @shared/{types,errors,ipc-channels,constants}@d3ro/core/* (사용자 79개 파일, 167건)
    • static import (from '@shared/...')
    • dynamic import (import('@shared/...'))
    • type expression import (keyof import('@shared/...').AppConfig)
  • MeetingModeService.ts의 상대 경로 utils import (../utils/meeting-markdown, ../utils/markdown-to-docx)를 @d3ro/core/utils/*로 교체
  • packages/core 내부 자기 참조: meeting-markdown.ts@shared/types../types 상대 경로

V2-1b 검증

  • npm run typecheck
  • npm run build (main+preload+renderer)
  • npm run dev 런타임 실행 (DB/핫키/Ollama 모두 정상)
  • apps/desktop/src/shared/에는 theme-vars.ts 1개만 남음 (V2-1c에서 이동 예정)

V2-1a 완료 내역

  • 루트 package.json을 npm workspaces 루트로 재구성 (workspaces: apps/, packages/)
  • turbo.json, tsconfig.base.json 추가 (Turborepo 자체 설치는 뒤로 미룸)
  • V1 파일 전체를 apps/desktop/으로 git mv:
    • src/, resources/, tests/, sidecar/, scripts/
    • electron.vite.config.ts, electron-builder.yml, vitest.config.ts
    • tsconfig.node.json, tsconfig.web.json (+ 새 tsconfig.json)
  • apps/desktop/package.json 신규 (name: "@d3ro/desktop", 기존 deps 그대로)
  • @electron/rebuild --version=33.4.11로 native 모듈 재빌드 (better-sqlite3, uiohook-napi)
  • 루트 tsconfig.json → apps/desktop references 형태

V2-1a 결정사항

  • 패키지 매니저: npm workspaces 유지 (pnpm 전환은 별도 sub-phase)
    • 이유: Turborepo는 npm workspaces와 호환, 구조 이동과 PM 전환을 동시에 하면 롤백 불가
  • site/: 루트 유지 (랜딩 페이지, V2 무관)
  • docs/, memory/, CLAUDE.md: 루트 유지
  • productName: "d3ro-voice" 필수 — package name을 @d3ro/desktop으로 바꾸면 Electron의 app.getName()이 바뀌어 userData 경로가 %APPDATA%\@d3ro\desktop\으로 이동(기존 DB/설정 유실). productName을 명시하면 app.getName()이 이를 우선 반환하여 %APPDATA%\d3ro-voice\ 그대로 유지됨.

검증 결과

  • npm run typecheck
  • npm run build (electron-vite main+preload+renderer)
  • npm run dev 실제 실행 → DB 경로 d3ro-voice/로 복원, 기존 핫키(Alt keyCode=2) 로드, Ollama 자동 실행 감지 모두 정상
  • npm run dist (electron-builder installer)은 V2-1 완료 후 별도 검증

Phase V2-2: Supabase 인프라 — 로컬 작업 완료

작성된 파일 (server/supabase/)

  • config.toml — Supabase CLI 설정 (로컬 + OAuth providers)
  • migrations/20260409000001_initial_schema.sql — 12개 테이블 (profiles, teams, team_members, meetings, meeting_memos, meeting_documents, transcripts, history, dictionary, memo_tags, daily_usage, subscriptions) + 인덱스 + FK CASCADE
  • migrations/20260409000002_rls_policies.sql — 개인/팀 이중 RLS 패턴
  • migrations/20260409000003_auth_triggers.sqlhandle_new_user (profiles + subscriptions 자동 생성), moddatetime (8개 테이블 updated_at 트리거), increment_daily_usage (service_role 전용 쿼터 RPC)
  • migrations/20260409000004_storage_buckets.sql — audio/exports/avatars 버킷 + 경로 기반 정책
  • functions/_shared/ — cors.ts, auth.ts (requireUser), quota.ts (티어별 쿼터)
  • functions/stt-proxy/index.ts — Google Cloud STT 래퍼 스캐폴딩 (placeholder 응답)
  • functions/llm-proxy/index.ts — Anthropic Messages API 래퍼 스캐폴딩 (티어별 모델 정책)
  • seed.sql — 개발 시드 (빈 상태)
  • .gitignore — .branches/, .temp/, .env

설계 문서

  • docs/v2/phase-V2-2.md — 상세 설계 (스키마/RLS/Edge Functions/실시간/Storage)
  • docs/v2/phase-V2-2-setup.md — 사용자 액션 가이드 (Supabase 계정/OAuth/CLI/배포)

사용자 액션 대기 중 (로컬 외 작업)

  1. Supabase 프로젝트 생성 (https://supabase.com)
  2. supabase login && supabase link --project-ref <REF>
  3. supabase db push (4개 마이그레이션 적용)
  4. Google/GitHub OAuth 앱 등록 + Supabase Auth Providers 설정
  5. Google Cloud STT 키 + Anthropic API 키 발급
  6. supabase secrets set + supabase functions deploy

설계 결정사항

  • UUID PK: V1은 nanoid(text), V2는 PostgreSQL gen_random_uuid(). V2-4 (동기화)에서 기존 SQLite 데이터는 nanoid 유지, 새 데이터는 UUID.
  • timestamptz: V1은 epoch ms(integer), V2는 timestamptz. V2-4 동기화 시 타입 변환 필요.
  • 멀티테넌시: 모든 테이블에 user_id. 회의 관련 테이블은 team_id nullable 추가.
  • RLS 이중 패턴: 개인 전용(history/dictionary)은 단순 user_id = auth.uid(). 팀 공유(meetings)는 본인 OR team_members 조회 subquery.
  • 쿼터 집계: increment_daily_usage RPC는 SECURITY DEFINER + service_role only. 일반 유저는 읽기만.
  • Realtime: transcripts 테이블만 supabase_realtime publication에 추가 (회의 중 세그먼트 동기화 용).
  • Edge Functions placeholder: 인증/쿼터 파이프라인은 완성, 실제 AI API 호출은 주석 처리된 실제 구현 코드 포함. V2-3 (Web MVP) 진행 전까지 유지.

Phase V2-5: Mac 빌드 — 로컬 작업 완료

작성/수정된 파일

  • apps/desktop/src/main/utils/paths.tsEXE_SUFFIX 상수 도입, sox/sidecar/ffmpeg 경로 플랫폼별 분기
  • apps/desktop/src/main/services/SoundEffectService.ts — Mac afplay, Linux aplay 분기 추가 (execFile로 안전하게)
  • apps/desktop/src/main/services/ScreenContextService.ts_getActiveWindowInfo를 win32/darwin로 분기. macOS는 osascript로 frontmost process + 윈도우 타이틀 조회 (Accessibility 권한 필요)
  • apps/desktop/scripts/build-sidecar.pyIS_WINDOWS/IS_MACOS 분기, EXE_SUFFIX, --noconsole은 Windows에서만, 출력 경로 플랫폼 통합
  • apps/desktop/scripts/install-sox.sh — Mac/Linux에서 시스템 sox를 resources/sox/로 복사. macOS는 otool로 dylib 의존성 함께 복사 + install_name_tool로 rpath 변경
  • apps/desktop/electron-builder.ymlmac: 타겟 추가 (dmg+zip, arm64+x64), hardenedRuntime, entitlements, extendInfo(권한 메시지), Linux AppImage placeholder
  • apps/desktop/build/entitlements.mac.plist — 마이크/카메라/네트워크/Apple Events/JIT/dylib 권한
  • apps/desktop/resources/icons/README.md — 플랫폼별 아이콘 생성 가이드 (sips/iconutil/imagemagick)
  • .github/workflows/build-mac.yml — macos-14 runner, brew sox, sidecar 빌드, electron-builder dist (arm64/x64 매트릭스), CSC/notarize 환경변수, artifact 업로드
  • docs/v2/phase-V2-5-mac-guide.md — Mac 사전 조건/dev 실행/dist 빌드/서명/공증/CI/트러블슈팅

검증 결과 (Windows에서)

  • typecheck — Mac 분기 추가에도 회귀 없음
  • build — Windows 번들 정상
  • dev 런타임 — Ollama 자동 실행 + 모든 서비스 정상

Mac에서 검증 대기 (사용자 액션)

  • brew install sox node@22 python@3.11
  • npm install && npx @electron/rebuild@3 --version=33.4.11
  • npm run dev → Accessibility/마이크/Apple Events 권한 허용
  • 핫키, 녹음, STT, LLM, 화면 컨텍스트 동작 확인
  • 결과 리포트 받아 미세 조정 필요할 수 있음

감사 결과 vs 처리

  • C1 sox.exe/sidecar.exe/ffmpeg.exe 하드코딩 → 수정
  • C2 아이콘 부재 → placeholder 디렉토리 + README
  • C3 mac 타겟 부재 → 추가
  • C4 SoX 바이너리 부재 → install-sox.sh + 가이드
  • C5 ScreenContextService 미지원 → AppleScript 분기
  • C6 SoundEffectService 미지원 → afplay 분기
  • C7 build-sidecar.py Windows 전제 → 크로스 플랫폼
  • M6/M7/M8/M9 (이미 분기 완료) → 변경 없음

Phase V2-3/V2-4/V2-6/V2-7/V2-8: 미착수

Web App MVP, 데스크톱 동기화, Mobile App, 팀 기능, 결제/출시

알려진 차단/이슈

  • @nut-tree-fork/nut-js 포크 사용 (V1 잔여 이슈)
  • Ollama 의존성: 없으면 LLM 기능 사용 불가 (2026-04-08 자동 실행 기능 추가로 UX 개선)

디렉토리 구조 (V2-1a 목표)

d3ro-voice/                   # 루트 (monorepo)
├── apps/
│   └── desktop/              # 기존 V1 전체
│       ├── src/
│       ├── resources/
│       ├── build/
│       ├── package.json      # name: @d3ro/desktop
│       ├── electron.vite.config.ts
│       ├── electron-builder.yml
│       ├── tsconfig*.json
│       └── drizzle.config.ts
├── packages/                 # V2-1b/c/d에서 채움
├── site/                     # 랜딩 페이지 (루트 유지)
├── docs/                     # 설계서/페이즈 문서
├── memory/                   # 이 파일
├── pnpm-workspace.yaml       # 또는 package.json "workspaces"
├── turbo.json
├── package.json              # 루트 workspace
├── tsconfig.base.json
└── CLAUDE.md