Commit graph

17 commits

Author SHA1 Message Date
Yun Chan
708e20f747 feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
2026-08-20 11:12:05 +09:00
Yun Chan
078304dda9 refactor(ui): deprecated accent.amber->main 91건 + 매직 리터럴 토큰화 (WS3)
- accent.amber/amberDim/amberGlow -> accent.main/dim/glow 91건 (34파일).
  theme.ts의 @deprecated 별칭 참조 제거 (본체 main 사용).
- inline fontSize/fontWeight -> d3roTypo, borderRadius -> d3roRadius 토큰 37건.
- P4: 화면 고유 수치(스탯 fontSize, 레이아웃 width)는 토큰화 제외.
정책: docs/REFACTOR_POLICY.md DP1, 이식 인사이트 P4
2026-07-22 01:54:37 +09:00
Yun Chan
32db25a74f feat(dashboard): 히어로 + 스탯 타일에 TiltCard 적용
동기 부여된 모션만 — 히어로(maxTilt 8) + 4개 스탯 타일(maxTilt 6). 나머지 데이터 밀집/드롭존/리스트 섹션은 MetalCard 유지 (틸트 = unmotivated slop 회피).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:51:30 +09:00
Yun Chan
082ed2ef02 feat(ui): Midnight Glass v2 마감 — lucide 아이콘 통일 + 몰입 패널 웨이브 + 팝업 정합
- @mui/icons-material → lucide-react 전환 (23파일, 잔여 0)
- VoiceRecordingPanel: 9바 DOM 웨이브 → GradientWave (canvas)
- Vanilla 팝업 5종 style.css v2 정합 (글래스 네이비/헤어라인/블루,
  CSS 변수 주입 구조 유지 — 테마 반응형 보존)
2026-07-21 20:20:32 +09:00
Yun Chan
a8a1d6e546 feat(ui): Midnight Glass v2 전면 리디자인 — 기반+셸+대시보드
- theme.ts 재작성: glass/gradient/glow 토큰군, 기본 dark=Midnight(블루),
  6종 테마 변형 전부 파생 토큰 유지 (테마 시스템 보존)
- DS 리스킨(API 호환): 글래스 카드/버튼, Pretendard 타이포, 소프트 LED
- 신규: GradientWave(canvas 스펙트럼 음파), StatRing(컬러 링 타일)
- 보더리스: frame:false + 커스텀 TitleBar, 네이티브 스크롤바 제거(폭 불변)
  + OverlayScrollbars 오버레이 스크롤
- AppLayout 와이드 사이드바(lucide, 그라디언트 액티브 필), 대시보드 재구축,
  StatusBar(브랜드/로컬시간), Pretendard 번들, i18n +20키(ko/en)
2026-07-21 20:14:15 +09:00
Yun Chan
8f7d300b89 feat(conversation): OpenAI gpt-realtime-2.1 라이브 음성 대화 Premium 백엔드
- realtime-token Edge Function: 티어 검증 + realtime_session 쿼터 + ephemeral key 발급
- useRealtimeConversation 훅: WebRTC 직결 (마이크 → OpenAI, 오디오 자동 재생)
- VoiceConversationPage: conversationBackend 분기 + 연결 실패 시 로컬 fallback
- AppConfig.conversationBackend + SettingsModal 음성 대화 엔진 선택
- ErrorCode 799 ConversationRealtimeTokenFailed, i18n ko/en
2026-07-21 12:10:13 +09:00
윤찬
996def683b refactor(desktop): 라이선스 UI 빅뱅 — 키 입력 제거, 구독 기반 전환
- LicenseTab/LicenseModal: LemonSqueezy 키 입력 삭제, Payple 구독 UI로 전환
- useLicenseState 훅: 라이선스+클라우드 인증 공용 상태 관리 추출
- PREMIUM_MODEL_LIMITS: 3곳 중복 → @d3ro/core/constants 단일 소스
- i18n: LemonSqueezy 전용 키 18개 삭제, 구독 관련 키 13개 추가 (12 locale)
- DashboardPage: dashboard.model* → license.model* 키 통일
2026-04-12 19:54:04 +09:00
윤찬
c9baf031c9 feat(server+web+desktop): Phase 3.2-B Payple 결제 연동 + 대시보드 Premium 상태 표시
Payple PG 연동:
- _shared/payple.ts: Payple API 래퍼 (auth/billing/cancel/deleteBillingKey)
- payple-checkout Edge Function: 빌링키 결제 + 구독 활성화
- payple-webhook Edge Function: 결제완료/취소 이벤트
- payple-manage Edge Function: 구독 취소 (빌링키 해지)
- DB migration: payment_provider + payple_payer_id + payple_pay_oid
- 웹 billing 페이지: Payple JS SDK 결제창 + 관리 버튼 (Stripe 대체)
- Electron LicenseModal: shell.openExternal → 웹 결제 페이지

대시보드 Premium 상태:
- CrtDisplay services에 PREMIUM LLM LED 추가
- 백엔드 인디케이터 카드 (Local/Premium) + 티어 카드
- 사용량 섹션: 전 티어 표시 + 모델별 Premium 쿼터
- 12개 locale × 14개 i18n 키
2026-04-12 19:18:40 +09:00
윤찬
a744551442 fix(desktop): Bug 13 전면 해소 — Conversation 에러 배너 + Dictation 빈 STT 가드 + recording tip 타이머 leak
- VoiceConversationPage: Snackbar + Alert(severity=warning filled) 하단 중앙
  배너 추가, onError 콜백에서 setErrorBanner. formatErrorMessage 헬퍼 —
  phase=stt + 'no speech' → i18n conversation.error.noSpeech, 그 외 →
  phaseLabel: rawMessage.
- VoiceModeService._transcribe: minBytes 가드(0.5s @ 16kHz 16bit mono =
  16000B) + 빈 result.text 가드. 양쪽 모두 _handleError(STTAudioTooShort /
  STTNoAudioData, 'No speech detected...')로 recording-tip popup error
  상태 3초 표시 재사용. 기존에는 빈 전사가 조용히 session completed +
  빈 history entry 생성되던 경로 차단.
- VoiceModeService._errorHideTimer 필드: _handleError의 setTimeout(hide, 3000)
  핸들 보관, _startSession 초기화 블록과 dispose()에서 clearTimeout. 다음
  세션 시작 후에도 이전 에러 타이머가 살아 진행 중인 recording tip을 ~2초
  지점에 숨기던 잠재 버그 수정 (실측 재현 및 해소 확인).
- i18n ko/en: conversation.error.phase.{stt,llm,tts} + conversation.error.noSpeech
  4개 키 추가.
2026-04-12 09:46:22 +09:00
윤찬
412a2e71f9 feat(desktop): Voice Conversation 몰입 UX 패널 + 사운드 피드백 + Bug 13 빈 STT (빅뱅 Phase 5 Part 6)
listening 상태에서 풀 몰입 계측기 모드로 전환되는 VoiceRecordingPanel 추가.
recording-tip 팝업의 9바 cos-분포 waveform(BAR_COUNT=9, SMOOTHING=0.5,
RANDOM_FACTOR=0.35, 100ms)을 React로 포팅해 REC LED + elapsed 타이머 +
"SPEAK NOW" 힌트까지 구성. thinking/speaking 상태에서는 메시지 리스트로
복귀해 대화 맥락 유지 + 점 3개 typing indicator 버블 추가.

VoiceConversationService에 AudioCaptureService audio-level forwarding과
사운드 훅 4개(recording-start / recording-stop / chime / error)를 삽입.
chime은 recording-stop.wav 재사용(SoundEffectService SoundName 확장).
VOICE_CONVERSATION.AUDIO_LEVEL 채널 신설 + preload onAudioLevel API.

U8 Bug 13 동반 해소: finishListening에서 minBytes 미달 또는 VAD 무음 판정으로
빈 텍스트가 나오는 경우 조용히 listening으로 복귀하던 것을 _emitError('stt')로
사용자 피드백(에러 사운드 + 에러 이벤트)을 노출하도록 수정. 사용자가 "⏹ 눌러도
반응 없음"으로 오해하던 증상 해소.
2026-04-11 23:16:34 +09:00
윤찬
3b77be01bc refactor(desktop): IME composition 가드 helper 추출 + 8곳 Enter 핸들러 통합 (빅뱅 Phase 5 Part 5)
Bug 10 fix(MeetingModePage 인라인 가드)를 isImeComposingEvent helper로 추출하고,
한글 위험도 있는 나머지 7개 Enter 핸들러에 일괄 적용. 총 8곳이 이제 동일 helper 경유.

신규:
- apps/desktop/src/renderer/utils/keyboard.ts — isImeComposingEvent(e)
  JSDoc에 Bug 10 원리(Chromium이 IME 조합 중 Enter를 2번 발화) + 권장 사용 패턴 포함

적용 8곳:
- pages/MeetingModePage.tsx:164 회의 메모 (기존 인라인 가드 4줄 교체)
- pages/KnowledgeBasePage.tsx:84 RAG 쿼리
- pages/VoiceConversationPage.tsx:113 텍스트 채팅
- pages/CommandsPage.tsx:336 키워드 추가 (Enter+Esc)
- components/meeting/MeetingChatPanel.tsx:111 미팅 챗
- components/meeting/EditableSegment.tsx:70 전사 세그먼트 편집 (Enter+Esc)
- components/meeting/MeetingDetailTabs.tsx:242 미팅 타이틀 (인라인 arrow → 블록)
- components/shared/HistoryEntryCard.tsx:64 태그 추가 (Enter+Esc)

/simplify 패스 품질 리뷰:
- Phase 3.3 CloudSyncService.pushOne 훅 8곳은 이미 fire-and-forget 1줄로 일관.
  내부 try-catch가 에러 삼켜 로컬 write 차단 금지 철학 준수 → 수정 없음, 현 상태가 최적.

검증:
- desktop tsc --noEmit EXIT=0
- Vite HMR로 dev 프로세스 자동 반영 (재기동 없음)
- 한글 Enter 시연은 사용자 실측 대기 (VoiceConversationPage / MeetingDetailTabs 대표 2곳)
2026-04-11 22:06:16 +09:00
윤찬
96e23f57bc fix(desktop): 한글 IME Enter 중복 addMemo 가드 + Meeting pre-push 직접 실증 (빅뱅 Phase 5 Part 4)
Phase 5 Part 3에서 남겨둔 U2(Fix 1 직접 시연 미수행)를 해소하고,
실증 중 발견한 한글 IME Enter 중복 addMemo 버그(Bug 10)를 같이 픽스.

## Bug 10 — 한글 IME Enter 중복 addMemo
- 증상: 실증 녹음 중 한글 메모 "메모 기능이 잘 작동하는지 봅니다"가
  2ms 간격으로 2번 저장 (로그 21:47:57.410/.412, UUID c7f0db45 + a6e442cc).
  5개 메모 중 이 하나만 중복 — 조합이 아직 확정 안 된 상태에서 Enter를
  친 메모에서만 발생.
- 원인: 한글 IME 조합 중 Enter → Chromium이 keydown 2번 발화
  ((1) IME 조합 확정 isComposing=true/keyCode=229,
   (2) 실제 Enter 액션). MeetingModePage.tsx:164-174의 handleMemoKeyDown이
  e.key === 'Enter' && !e.shiftKey만 검사하고 isComposing을 무시해
  두 이벤트에서 모두 handleAddMemo() 발화 → IPC 2회 → addMemo() 2회.
- 수정: MeetingModePage.tsx:168에 이중 가드 추가.
  isComposing은 모던 표준, keyCode === 229는 조합 확정 시점에
  isComposing이 false로 내려가면서 keyCode만 229로 주는 Chromium
  엣지 케이스 호환.
- 검증: Vite HMR로 즉시 반영 후 재시연 녹음(78421e75)에서 한글 메모
  5건 연속 → 전원 1:1 매핑, 중복 0.

## Fix 1 (Phase 3.3 startRecording pre-push) 직접 실증
재시연 녹음 78421e75 (21:51:24~21:51:50, 약 26초) 로그 타임라인:

  21:51:24.937  pushOne meetings/78421e75 ok      <- Fix 1 pre-push (676ms)
  21:51:30.499  pushOne meeting_memos/4ed7e59a ok <- addMemo #1 (113ms)
  21:51:32.202  pushOne meeting_memos/de011c15 ok <- addMemo #2 (78ms)
  21:51:35.893  pushOne meeting_memos/3184fe5e ok <- addMemo #3 (66ms)
  21:51:38.263  pushOne meeting_memos/00f041ef ok <- addMemo #4 (82ms)
  21:51:40.740  pushOne meeting_memos/0808c4d2 ok <- addMemo #5 (64ms)
  21:51:50.681  pushOne meetings/78421e75 ok      <- _runPostProcessing (108ms)
  21:51:50.709  pushOne history/70388090 ok       <- CaptionService→History

meetings/78421e75가 녹음 시작 + 종료 두 번 push된 것이
Fix 1의 직접 증거 — 부모 row가 메모 push 시점에 이미 Supabase에
존재했기 때문에 메모 5건이 RLS/FK 차단 없이 통과. Bug 7 재현 방지 확인.

## 잠재 IME 버그 7곳
동일 패턴의 Enter 핸들러 7곳에 가드 없음 (KnowledgeBasePage:85,
VoiceConversationPage:114, MeetingChatPanel:113, EditableSegment:72,
MeetingDetailTabs:242, HistoryEntryCard:65, CommandsPage:337).
다음 세션 /simplify 패스에서 일괄 처리 예정.

## 검증
- desktop tsc --noEmit EXIT=0
- Meeting 녹음 2회차 실증 통과

memory/project_status.md SaaS [11] 섹션 추가.
2026-04-11 21:58:20 +09:00
윤찬
0d17b71866 fix(desktop): macOS 단축키 표기 (Win/Ctrl/Alt → ⌘/⌃/⌥/⇧)
기존: HotkeyRecordModal에서 키 녹화 시 'Win+Shift+1' 같은 정적 displayLabel 저장
- KEY_DISPLAY_MAP이 Windows 전용 (91/92 → 'Win')
- SettingsModal HotkeyDisplay가 binding.displayLabel.split(' + ')로 chip 분리
  - 그런데 displayLabel은 join('+') (space 없음) — split이 작동 안 해서 단일 chip 'Win+Shift+1'
- macOS에서도 'Win'으로 표시되어 사용자 혼동

수정:
- preload/index.ts: process.platform 노출 (electronAPI.platform)
- renderer/utils/format-hotkey.ts 신규
  - formatHotkeySegments(binding) → 플랫폼별 segment 배열
    - macOS: ['⌘', '⇧', '1'] (⌃ ⌥ ⇧ ⌘ 순, Apple HIG)
    - Win/Linux: ['Ctrl', 'Win', 'Alt', 'Shift', '1']
  - formatHotkeyLabel(binding) → 단일 문자열
    - macOS: '⌘⇧1' (구분자 없음, Apple 표준)
    - Win/Linux: 'Ctrl + Shift + 1'
- 사용 위치 일괄 교체 (binding.displayLabel → format 헬퍼):
  - SettingsModal HotkeyDisplay (chip 표시)
  - SettingsModal Agent 모드 설명 ({{key}} 치환)
  - OnboardingModal 단축키 chip + 완료 화면
  - DashboardPage CrtDisplay 'PRESS X TO RECORD'
  - HotkeyRecordModal currentBinding 표시

displayLabel 필드는 ConfigService 호환을 위해 유지 (저장된 값은 그대로)
2026-04-11 09:04:51 +09:00
yunchan8804
3524e958ba feat(V2-1d): packages/i18n 추출 — Electron 독립 i18n 엔진
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 독립성 확보 (monorepo 원칙 준수):
- I18nStorage interface 신설 (load/save 어댑터 추상화)
- window.electronAPI.config 직접 호출 제거
- I18nProvider는 storage prop으로 영속화 어댑터 주입
- 기본값 noopStorage (메모리 한정, 세션 범위)
- 결과: packages/i18n은 React에만 의존, web/mobile에서 재사용 가능

apps/desktop 어댑터:
- App.tsx에 electronI18nStorage 구현 (config.get/set 래핑)
- <I18nProvider storage={electronI18nStorage}>로 주입

apps/desktop 설정:
- package.json: @d3ro/i18n '*' dep 추가
- tsconfig.node/web.json paths에 @d3ro/i18n 추가
- electron.vite.config.ts alias + externalize exclude 추가
- vitest.config.ts alias 추가

일괄 치환 (29 파일):
- ./i18n, ../i18n, ../../i18n → @d3ro/i18n

apps/desktop/src/renderer/i18n/ 디렉토리 완전 제거.

검증: typecheck + build + dev 런타임 모두 통과.
Phase V2-1 전체 완료 (a/b/c/d).
2026-04-08 14:57:27 +09:00
yunchan8804
a041f1b6a9 feat(V2-1c): packages/ui 추출 — DS 컴포넌트 + theme + theme-vars 분리
packages/ui (@d3ro/ui) 신규:
- src/theme.ts (d3roPalette/d3roTypo/d3roShadow/d3roRadius SSOT)
- src/theme-vars.ts (팝업/main 프로세스용 CSS 변수 맵)
- src/components/ds/ (CrtDisplay, InstrumentPanel, Led, MetalCard,
  MetalDial, PhosphorText, PhysicalButton, ScreenPanel, ButtonGroup)
- src/index.ts barrel
- subpath exports: ./theme, ./theme-vars, ./components/ds
- React/MUI/Emotion은 peerDependencies로 선언
- @d3ro/core만 직접 의존성

apps/desktop/src/shared/ 디렉토리 완전 제거:
- theme-vars가 마지막 남은 파일이었음
- tsconfig include에서 src/shared/**/* 제거

일괄 치환 (renderer 전역):
- ../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)

apps/desktop 설정:
- package.json: @d3ro/ui: '*' dep 추가
- tsconfig.node/web.json: @shared/* paths 완전 제거, @d3ro/ui,
  @d3ro/ui/* paths 추가
- electron.vite.config.ts: @shared alias 제거, @d3ro/ui alias 추가,
  externalize exclude에 @d3ro/ui 추가
- vitest.config.ts: alias 교체

DS 컴포넌트 내부의 '../../theme' 상대 경로는 packages/ui 구조에서
동일하게 해결되어 그대로 유효.

검증: typecheck + build + dev 런타임 모두 통과.
2026-04-08 14:50:33 +09:00
yunchan8804
3b0eb3393b feat(V2-1b): packages/core 추출 — 공유 타입/에러/채널/유틸 분리
packages/core (@d3ro/core) 신규 생성:
- types.ts, errors.ts, ipc-channels.ts, constants.ts (shared에서 이동)
- utils/meeting-markdown.ts, utils/markdown-to-docx.ts (main/utils에서 이동)
- subpath exports 정의 (./types, ./errors, ./ipc-channels, ./constants,
  ./utils/meeting-markdown, ./utils/markdown-to-docx)
- src/index.ts barrel export 추가
- docx를 core 자체 dependency로 선언

apps/desktop 연결:
- package.json에 @d3ro/core: '*' dep 추가
- tsconfig.node/web.json paths에 @d3ro/core/* 추가
- electron.vite.config.ts 3개 섹션 alias 추가 (main/preload/renderer)
- externalizeDepsPlugin exclude에 @d3ro/core (workspace 소스 번들 대상)
- vitest.config.ts alias 추가

일괄 치환 (79 파일, 167건):
- @shared/{types,errors,ipc-channels,constants} → @d3ro/core/*
- static/dynamic import + type expression import 모두 포함
- MeetingModeService.ts의 ../utils/* 상대 경로 → @d3ro/core/utils/*
- @shared/theme-vars는 V2-1c 범위로 남김 (WindowManager만 사용)

M1 수정 포함:
- electron.vite.config.ts의 resolve('src/shared') → resolve(__dirname, ...)
  CWD 독립적으로 동작하도록 견고화

검증:
- typecheck 통과
- build 통과 (main+preload+renderer)
- dev 런타임 → DB/핫키/Ollama 모두 정상, 기존 데이터 연속성 유지
2026-04-08 14:39:46 +09:00
yunchan8804
45a580878a feat(V2-1a): Monorepo 구조 전환 — apps/desktop으로 V1 이동
- npm workspaces 루트 (apps/*, packages/*) 세팅
- 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)
- apps/desktop/package.json 신규 (name=@d3ro/desktop)
- productName: 'd3ro-voice' 명시 — app.getName()을 고정하여 userData 경로
  %APPDATA%\d3ro-voice\ 그대로 유지 (기존 DB/설정 연속성 보장)
- 루트 package.json을 workspace 루트로 재구성, 공통 devDep만 유지
  (typescript, eslint, prettier)
- turbo.json, tsconfig.base.json 추가 (Turborepo 자체 설치는 별도 sub-phase)
- memory/project_status.md 생성 (규칙 13)

검증:
- npm run typecheck 통과
- npm run build 통과 (electron-vite main+preload+renderer)
- npm run dev 실제 실행 → DB/핫키/Ollama 자동 실행 모두 정상
2026-04-08 14:04:41 +09:00