d3ro-voice/docs/phases/phase-7.md
Yun Chan e24bb8378c 초기 프로젝트 설정: 하네스 시스템 + 설계서 + RE 노하우
- CLAUDE.md: 프로젝트 규칙, 기술 스택, 코딩 규칙, 페이즈 로드맵
- .claude/settings.json: 권한, 강제 훅 (매 프롬프트 설계서 규칙 주입)
- .claude/skills/: implement-phase, review-phase, scaffold, test-commit, debug
- .claude/agents/: electron-architect, voice-pipeline-expert, ui-specialist
- docs/design/00-09: 마스터 아키텍처, 서비스 명세(16개), IPC(113채널),
  DB스키마, UI컴포넌트, 검증리포트, 외부엔진연동, 갭분석,
  VoiceMode패턴, 디자인시스템, 히스토리팝업
- docs/phases/1-7+3.5: 전체 구현 페이즈 문서
- docs/re-findings/: Speakly RE 노하우 5개 문서
2026-04-05 01:03:03 +09:00

7.3 KiB

Phase 7: 테스트 + 빌드 + 배포

목표

테스트 커버리지를 확보하고, 프로덕션 빌드/패키징 파이프라인을 구축하여 Windows 설치 파일을 생성한다. CI/CD를 설정하여 자동 빌드 및 배포를 가능하게 한다.

태스크

7.1 테스트 전략 수립

  • 3계층 테스트 피라미드:
    • 단위 테스트 (vitest): 서비스 로직, 유틸리티, 상태 머신
    • 통합 테스트 (vitest): IPC 핸들러, DB 쿼리, 서비스 간 상호작용
    • E2E 테스트 (Playwright + electron): 전체 사용자 시나리오
  • 커버리지 목표: 단위 70%+, 통합 50%+, E2E 핵심 플로우

7.2 단위 테스트 — 최우선 대상

  • VoiceModeService 상태 머신:
    • 모든 RecognitionState 전이 경로 테스트
    • 모든 AudioState 전이 경로 테스트
    • 잘못된 전이 시도 시 에러 처리
    • 이중 조건 플러시 (sttReady + audioBuffer) 시나리오
    • 타이밍 상수 검증 (minAudioDurationMs, doublePressMs)
    • 세션 취소/타임아웃 시나리오
  • LocalSTTService:
    • sidecar 프로토콜 파싱 (JSON stdout)
    • 이중 조건 플러시 로직
    • 모델 로딩 상태 전이
    • 에러 전파 (sidecar crash, transcription fail)
  • LocalLLMService:
    • Ollama API 응답 파싱
    • NDJSON 스트리밍 파싱 (불완전 라인 처리 포함)
    • 가용성 폴링 로직
    • 에러 코드별 처리 (연결 실패, 모델 미설치)
  • HotkeyService:
    • 키코드 매칭 + 수정자 키 조합
    • 더블프레스 감지 (300ms 윈도우)
    • holdMode vs toggleMode 동작
  • TextInsertService:
    • 클립보드 백업/복원 흐름
    • 삽입 실패 시 클립보드 복원 보장
  • HistoryService / DictionaryService:
    • CRUD 메서드 (in-memory SQLite 사용)
    • 검색/필터 쿼리
    • 보존 정책 (cleanup)
    • 통계 집계 정확성
  • CustomInstructionService:
    • CRUD + 프리셋 보호 (삭제 불가)
    • 순서 변경
    • 프롬프트 템플릿 변수 치환

7.3 통합 테스트

  • IPC 핸들러 테스트:
    • 각 IPC 채널이 올바른 서비스 메서드를 호출하는지 검증
    • 인자 검증 + 에러 응답 형식
    • preload bridge ↔ main handler 매핑 정합성
  • DB 쿼리 통합 테스트:
    • drizzle-orm 쿼리가 실제 SQLite에서 올바르게 실행되는지 검증
    • 마이그레이션 적용 후 스키마 일관성
    • 동시 접근 시나리오 (WAL 모드)
  • 서비스 간 상호작용:
    • VoiceModeService → AudioCaptureService → LocalSTTService → LocalLLMService → TextInsertService 파이프라인
    • ConfigService 변경 → 서비스 반영 (설정 핫리로드)

7.4 E2E 테스트 (Playwright)

  • @playwright/test + electron fixture 사용
  • 핵심 시나리오:
    1. 앱 실행 → 메인 윈도우 표시
    2. Dashboard 통계 로드
    3. Settings 열기 → 설정 변경 → 저장
    4. History 목록 표시 → 검색 → 삭제
    5. Dictionary 추가 → 편집 → 삭제
    6. 온보딩 플로우 완주 (첫 실행 시뮬레이션)
  • 외부 의존성 모킹:
    • Ollama API: MSW(Mock Service Worker) 또는 로컬 HTTP 서버
    • faster-whisper sidecar: 모킹된 stdout 응답
    • piper-tts sidecar: 모킹된 WAV 출력

7.5 테스트 유틸리티

  • tests/helpers/:
    • createTestDb() — in-memory SQLite + 스키마 적용
    • mockElectronStore() — electron-store 모킹
    • mockSidecar() — sidecar stdout/stdin 모킹
    • createMockAudioBuffer() — 테스트용 PCM16 버퍼 생성
    • waitForState() — 상태 머신 전이 대기 유틸
  • vitest 설정:
    • vitest.config.ts: 경로 별칭, 환경변수, 타임아웃
    • vitest.workspace.ts: unit / integration / e2e 워크스페이스 분리

7.6 electron-vite 빌드 설정

  • electron.vite.config.ts:
    • main: TypeScript → CJS, externals (better-sqlite3, uiohook-napi, @nut-tree/nut-js)
    • preload: TypeScript → CJS, contextIsolation 호환
    • renderer: React + MUI → 번들 (코드 스플리팅, 트리 셰이킹)
  • 환경 분리: MAIN_VITE_*, RENDERER_VITE_*
  • native 모듈 빌드: electron-rebuild 또는 prebuild-install
  • 팝업 HTML 복사: recording-tip.html, result-popup.html → output

7.7 electron-builder 패키징

  • electron-builder.yml 설정:
    appId: com.d3ro.voice
    productName: D3RO Voice
    directories:
      output: release
    win:
      target:
        - target: nsis
          arch: [x64]
      icon: resources/icon.ico
    nsis:
      oneClick: false
      allowToChangeInstallationDirectory: true
      createDesktopShortcut: true
      createStartMenuShortcut: true
    extraResources:
      - from: sidecar/
        to: sidecar/
        filter: ["**/*"]
    
  • sidecar 번들링:
    • faster-whisper Python 환경 (embedded Python 또는 PyInstaller 빌드)
    • piper-tts 바이너리 + 음성 모델
    • Whisper 모델 파일 (선택: 초기 번들 또는 첫 실행 시 다운로드)
  • native 모듈 리빌드: better-sqlite3, uiohook-napi, @nut-tree/nut-js
  • asar 설정: native 모듈은 asar 외부 (asarUnpack)

7.8 자동 업데이트 (electron-updater, 선택)

  • electron-updater 라이브러리 통합
  • GitHub Releases를 업데이트 서버로 사용
  • 업데이트 체크: 앱 시작 시 + 24시간 주기
  • 업데이트 플로우:
    1. autoUpdater.checkForUpdates()
    2. 업데이트 발견 시 알림 (강제 아님)
    3. 사용자 승인 시 백그라운드 다운로드
    4. 다운로드 완료 → 재시작 안내
  • 버전 관리: semver, package.json version 필드

7.9 CI/CD (GitHub Actions)

  • .github/workflows/ci.yml:
    on: [push, pull_request]
    jobs:
      lint-and-typecheck:
        - npm run lint
        - npm run typecheck
      unit-test:
        - npm run test:unit
      integration-test:
        - npm run test:integration
      build:
        - npm run build
        - 빌드 산출물 아티팩트 업로드
    
  • .github/workflows/release.yml:
    on:
      push:
        tags: ['v*']
    jobs:
      build-and-release:
        - npm run build
        - electron-builder --win --x64
        - GitHub Release 생성 + 설치파일 업로드
    
  • Windows 러너 사용 (runs-on: windows-latest)
  • 캐시: node_modules, electron 바이너리

7.10 코드 서명 (선택)

  • Windows: Authenticode 서명 (EV 코드 서명 인증서)
  • electron-builder 설정:
    win:
      sign: ./scripts/sign.js
      signingHashAlgorithms: [sha256]
    
  • CI에서 서명: GitHub Secrets에 인증서 저장
  • 서명 없이도 실행 가능 (SmartScreen 경고 표시)

Speakly RE 참조

  • Speakly 패키징: electron-builder, NSIS 인스톨러, Squirrel.Windows 기반 업데이트
  • Speakly 빌드: NativeHelper.dll → extraResources, asar 외부 배치
  • Speakly CI: 자동 빌드/배포 파이프라인 (D3RO는 GitHub Actions로 대체)

완료 조건

  • npm run test:unit — VoiceModeService, HistoryService 등 핵심 서비스 테스트 통과
  • npm run test:integration — IPC 핸들러, DB 쿼리 테스트 통과
  • npm run test:e2e — 핵심 사용자 시나리오 테스트 통과
  • npm run build — 프로덕션 빌드 성공
  • electron-builder로 Windows NSIS 인스톨러 생성
  • 인스톨러로 설치 → 실행 → 기본 기능 작동 확인
  • GitHub Actions CI 파이프라인 작동 (lint, typecheck, test, build)
  • (선택) 자동 업데이트 체크 작동