d3ro-voice/apps/desktop/package.json
윤찬 e55687d298 fix(desktop+supabase): 로컬 ID UUID 통일 + Realtime publication (빅뱅 Phase 5 Part 2)
SaaS [9] — 실증 A/B/C/D 전부 통과, 로컬→클라우드 push 최초 성공(pushed=1).

## Bug 4: 로컬 nanoid PK vs Supabase UUID PK 불일치
- 증상: Push history failed: invalid input syntax for type uuid: "fvy6bIzr..."
- 원인: 로컬 drizzle schema는 text PK + nanoid() 생성, Supabase는 uuid PK.
  빅뱅 사이클 내내 push가 한 번도 성공한 적 없었음 (지난 pushed=0은 데이터 0건이라서).
- 픽스: 로컬을 UUID로 통일 (근본 해결, 땜질 금지).
  14개 서비스 20곳 nanoid() → crypto.randomUUID() 일괄 교체.
  nanoid 의존성 + electron.vite.config exclude 제거.
  drizzle schema는 text PK 그대로 유지 (SQLite는 UUID 문자열 저장 가능).

## Bug 5: supabase_realtime publication 누락
- 증상: 로그인 직후 Realtime 채널 상태: TIMED_OUT
- 원인: initial_schema.sql이 transcripts 테이블만 publication에 추가.
  데스크톱이 구독하는 meetings/history/dictionary는 누락 → postgres_changes 흐르지 않음.
- 픽스: 20260411000002_realtime_publication.sql 신규.
  pg_publication_tables 카탈로그 체크 + 조건부 ADD TABLE (meetings/meeting_memos/
  meeting_documents/history/dictionary 5개). supabase db push 적용.

## Bug 6: persistSession:false에서 realtime.setAuth 자동 전파 안 됨 (부분 픽스)
- 픽스: CloudSyncService.startRealtime()에 client.realtime.setAuth(access_token)
  명시 호출 (채널 구성 이전).
- ⚠️ Bug 5+6 적용 후에도 Realtime 여전히 TIMED_OUT. 후속 조사 필요.
  블로커 아님 — 주기 pull + Phase 3.3 auto push로 최종 일관성 유지.

## 실증 결과
- A 세션 자동 복원: Restored session for yunchan8804@gmail.com → DB 재오픈
- B push 경로: HistoryService created 56a767ac-... → Sync complete pushed=1 errors=0
- C 로그아웃 복귀: Realtime 종료 → users/_local/d3ro.db 복귀 → local mode
- D 재로그인 복원: 실증 A의 restore 경로와 동일, 같은 uuid DB 파일 보존
- E 웹 크로스 디바이스: Phase 3.3 이후로 지연 (Realtime 이슈 별건)

검증: desktop tsc --noEmit , dev 재기동 , push 최초 성공 
2026-04-11 18:46:22 +09:00

72 lines
2.3 KiB
JSON

{
"name": "@d3ro/desktop",
"version": "1.0.0",
"productName": "d3ro-voice",
"description": "로컬 AI 음성 어시스턴트 (Electron)",
"main": "./out/main/index.js",
"scripts": {
"dev": "electron-vite dev",
"build": "electron-vite build",
"preview": "electron-vite preview",
"typecheck": "tsc --noEmit",
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
"test": "vitest run --config vitest.config.ts",
"test:unit": "vitest run --config vitest.config.ts",
"test:watch": "vitest --config vitest.config.ts",
"pack": "electron-vite build && electron-builder --dir",
"dist": "electron-vite build && electron-builder",
"build:sidecar": "python scripts/build-sidecar.py",
"setup:sox": "powershell -ExecutionPolicy Bypass -File scripts/download-sox.ps1"
},
"author": "D3RO",
"license": "MIT",
"build": {
"extends": null,
"configFile": "electron-builder.yml"
},
"devDependencies": {
"@electron-toolkit/tsconfig": "^1.0.1",
"@types/better-sqlite3": "^7.6.13",
"@types/fluent-ffmpeg": "^2.1.28",
"@types/node": "^22.13.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.0",
"electron": "^33.3.0",
"electron-builder": "^26.8.1",
"electron-vite": "^2.3.0",
"vite": "^5.4.0",
"vitest": "^2.1.0"
},
"dependencies": {
"@d3ro/api-client": "*",
"@d3ro/core": "*",
"@d3ro/i18n": "*",
"@d3ro/ui": "*",
"@electron-toolkit/preload": "^3.0.2",
"@supabase/supabase-js": "^2.45.0",
"@electron-toolkit/utils": "^4.0.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@mui/icons-material": "^7.0.0",
"@mui/material": "^7.0.0",
"@nut-tree-fork/nut-js": "^4.2.6",
"@rollup/rollup-win32-x64-msvc": "^4.60.1",
"better-sqlite3": "^12.8.0",
"docx": "^9.6.1",
"drizzle-orm": "^0.45.2",
"electron-audio-loopback": "^1.0.6",
"electron-log": "^5.2.0",
"electron-store": "^10.0.0",
"fluent-ffmpeg": "^2.1.3",
"node-record-lpcm16": "^1.0.1",
"pdf-parse": "^2.4.5",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"uiohook-napi": "^1.5.5"
}
}