From 817b4a2580f7cef12b86b367ac92d118d67aaaaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EC=B0=AC?= Date: Sat, 11 Apr 2026 10:37:40 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20=EB=B9=85=EB=B1=85=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=ED=81=B4=201=EC=B0=A8=20wrap-up=20=E2=80=94=20?= =?UTF-8?q?=ED=95=B8=EB=93=9C=EC=98=A4=ED=94=84=20+=20Phase=205=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=EB=A6=AC=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빅뱅 Phase 1~6 완료 (Phase 5는 OAuth provider 연결 대기): - Phase 1: 사용자별 SQLite 격리 (816f527) - Phase 1.5: 로컬 모드 entry point (1a01cea) - Phase 2: 온보딩 + Cloud Sync 티저 (f1321df) - Phase 4: 티어 enforcement 로컬 해방 (46b77f1) - Phase 3: 로컬 우선 sync + login_required UI (ceadf1b) [재정의] - Phase 5: 3 클라이언트 일원화 검증 → OAuth provider 대기 - Phase 6: wrap-up (이 커밋) handoff-latest 새로 작성, 이전 스냅샷은 archive로 이동. project_status에 Phase 5 OAuth 연결 가이드 + 검증 체크리스트 기록. --- .../2026-04-11-0940-prior-bigbang.md | 136 +++++++++++ memory/handoff-latest.md | 223 ++++++++++-------- memory/project_status.md | 27 +++ 3 files changed, 289 insertions(+), 97 deletions(-) create mode 100644 memory/handoff-archive/2026-04-11-0940-prior-bigbang.md diff --git a/memory/handoff-archive/2026-04-11-0940-prior-bigbang.md b/memory/handoff-archive/2026-04-11-0940-prior-bigbang.md new file mode 100644 index 0000000..1b25928 --- /dev/null +++ b/memory/handoff-archive/2026-04-11-0940-prior-bigbang.md @@ -0,0 +1,136 @@ +# Session Handoff — 2026-04-11 09:40 (Mac, Big Bang 사이클 직전) + +> From: macOS (yunchan-ui-MacBookPro) +> Last commit: `dd1c305` — feat(desktop): SaaS [1+2] 빌드 타임 env + OAuth 강제 로그인 게이트 +> Branch: `main` +> Remote: `https://gitlab.twentyoz.kr:8443/d3r0/voice.git` + +## ✅ 이번 세션에서 한 일 (1M 컨텍스트, 데스크톱 Mac 안정화 + SaaS 1차) + +### 환경 +- Mac 부트스트랩: Node 22 (brew), sox 14, supabase CLI 2.84 +- `npm install --force` (rollup win32 옵셔널 dep 충돌 우회) +- `@electron/rebuild@3 --version=33.4.11` 완료 +- Sanity build: desktop/web typecheck, web `next build`, api-client vitest 19 passed + +### Supabase 배포 +- 프로젝트: `yunchan8804-blip's Project` (`llnocwyqvhgwpdjcqqyw`) +- `supabase link` + `db push` (8개 마이그레이션) +- `supabase functions deploy` (10개 Edge Functions) +- `apps/web/.env.local` + `server/supabase/.env.local` 작성 + +### V2-6차 [W][A~D] — 웹 고도화 +- W. fix: AppRouterCacheProvider Emotion key `'d3ro-mui'` → `'mui'` (숫자 3 → SSR 500) +- A. Dark/Light/Theme 토글 (`theme-mode-context.tsx`, 12개 locale `theme.*`) +- B. DocumentEditor Mermaid + Markdown 렌더 (`markdown-preview.tsx`) +- C. 회의 오디오 재생 (`meeting-audio-player.tsx`, Storage signed URL 1h) +- D. Dashboard 14일 추이 차트 (recharts) + +### V2-6차 [E~L] — 데스크톱 Mac 안정화 +- E. macOS 단축키 표기 ⌘⇧⌃⌥ (`format-hotkey.ts` + 호출 위치 4개) +- F. Sidecar `apps/desktop/sidecar/.venv/` 생성 + paths.ts venv 우선 +- G. HotkeyRecordModal 칩 'WIN' → ⌘ 표기 (getKeyName 플랫폼 분기) +- H. `bootstrap.ts` `hideRecordingTip` import 누락 → ReferenceError 픽스 +- I. macOS 시스템 beep 차단 — Electron `globalShortcut` 통합 (HotkeyService) +- J. Sidecar 동적 포트 (`_findFreePort`, orphan EADDRINUSE 회피) +- K. macOS Cmd+V paste — `TextInsertService` `LeftSuper`/`LeftControl` 분기 +- L. qwen3 reasoning 39초 — `/no_think` 토큰 + `stripReasoningBlocks` + 빈 응답 fallback + +### SaaS [1+2] — 데스크톱 fat client → 진짜 SaaS 클라이언트 변환 +- [1] **빌드 타임 Supabase env 주입** + - `electron.vite.config.ts`: `loadEnv('D3RO_')` + main `define` + - `apps/desktop/.env.local`: `D3RO_SUPABASE_URL/ANON_KEY` + - `ConfigService`: `BUILD_TIME_*` 상수, `configGet/Set`이 빌드 타임 우선 + 변경 차단 +- [2] **OAuth 첫 실행 강제 게이트** + - `CloudSyncState.saasMode: boolean` 추가 + - `LoginScreen.tsx` 신규 (Google/GitHub만) + - `App.tsx` `AuthGate` 상태머신 + - `CloudSyncSection` saasMode일 때 URL/Key 입력 필드 숨김 + +### 미완 / 확실히 알려진 이슈 +- Ollama `qwen3:4b`가 4B reasoning 모델이라 CPU에서 느림 → 사용자가 더 빠른 모델로 교체 권장 (`gemma3:1b` 또는 `qwen2.5:3b`) +- Accessibility 권한 첫 실행 시 macOS 권한 다이얼로그가 떠야 함 (안 뜨면 시스템 설정 → 손쉬운 사용에 Electron 추가) +- 데스크톱 SQLite는 여전히 단일 파일 (`userData/d3ro-voice/d3ro.db`) — 한 PC에 여러 사용자가 OAuth 로그인 시 데이터 섞일 위험 ← **빅뱅 핵심 작업** + +## 🚧 다음 세션: 빅뱅 사이클 (Desktop SaaS Client 완성) + +자세한 단계별 계획은 아래 "다음 세션 시작 프롬프트" 참조. + +요약 목표: +1. **사용자별 SQLite 격리** — `userData/users/${userId}/d3ro.db` +2. **회원가입/온보딩 흐름** — OAuth 첫 가입 시 환영 + 마이그레이션 +3. **cloud-first 정책** — Supabase source of truth, local read-through cache +4. **멀티 디바이스 sync 강화** +5. **티어 enforcement** — 데스크톱에서도 free quota 차단 +6. **데스크톱 ↔ 웹 ↔ 모바일 데이터 일원화 검증** + +## 🔑 다음 세션 시작 시 즉시 할 일 + +```bash +# 1. git pull +git pull origin main # 마지막 커밋 dd1c305 또는 그 이후 확인 + +# 2. 환경 검증 (이미 mac에 다 있음) +node --version # v22.x +which sox supabase # /opt/homebrew/bin/... +ls apps/desktop/sidecar/.venv/bin/python3 # exists +ls apps/desktop/.env.local # gitignored, exists + +# 3. 워크스페이스 재설치 필요 시 +npm install --force + +# 4. 데스크톱 dev 띄워서 LoginScreen 보이는지 확인 +npm run dev +# → 첫 화면이 LoginScreen이어야 함 (Google/GitHub 버튼) +``` + +## ⚠ 환경 / 주의사항 + +- **gitlab 푸시는 사용자 명시 후에만**: 이번 세션에선 push 안 했음. 다음 세션에서 빅뱅 작업 끝나면 사용자 확인 후 `git push origin main` +- **Ollama 모델**: `qwen3:4b` 설치됨, 느리면 `ollama pull gemma3:1b` 권장 +- **Accessibility 권한**: 데스크톱 핫키 동작에 필수 — macOS 시스템 설정에서 수동 허용 +- **Supabase 외부 키**: ANTHROPIC/OPENAI/RESEND/STRIPE는 아직 안 주입됨 → web의 `/chat`, `/knowledge`, `/billing`은 키 채워지기 전엔 동작 안 함 (사용자가 키 줄 때 `supabase secrets set`) +- **데스크톱 .env.local**: gitignored, 이번 세션에서 작성. 만약 다음 세션이 다른 PC에서 시작하면 `apps/desktop/env.example`을 보고 직접 작성 필요 +- **DB 마이그레이션**: 빅뱅 [1] 사용자별 SQLite 격리 시 기존 단일 DB의 데이터를 첫 로그인 사용자에게 귀속시키는 마이그레이션 필요. 데이터 손실 주의 + +## 📦 의존성 / 도구 +- Node 22.22.2 (brew) +- Python 3.13 (Framework) + venv at `apps/desktop/sidecar/.venv` +- Supabase CLI 2.84.2 +- Ollama (사용자가 별도 설치, qwen3:4b 모델) +- @electron/rebuild@3 33.4.11 +- Electron 33.4.11 + +## 🧪 마지막 검증 +| 게이트 | 상태 | +|---|---| +| desktop tsc | ✅ | +| desktop build (electron-vite) | ✅ | +| desktop dev (실제 실행) | ✅ Main window shown | +| Hotkey ⌘⇧1 + globalShortcut | ✅ accelerator=Shift+Cmd+1 등록 | +| Sidecar venv spawn | ✅ 한국어 96% 1.5초 오디오 → 426ms 전사 | +| Cmd+V paste | ✅ (사용자 확인 "되긴한다") | +| LLM refine | ⚠ qwen3:4b reasoning 끄기 후 첫 시도 미확인 — 사용자 검증 필요 | +| LoginScreen | ⚠ 이번 세션 마지막에 빌드만, 사용자 시각 확인 미수행 | + +## 📊 누적 통계 (이번 세션 포함) +- 신규 커밋: 13개 (V2-6차 [A~L] + SaaS [1+2]) +- 신규 파일: + - apps/web: theme-mode-context, markdown-preview, meeting-audio-player, meetings-trend-chart + - apps/desktop: format-hotkey, LoginScreen, sidecar/.venv, .env.local, env.example +- 수정: ConfigService(빌드 타임), CloudSyncService(saasMode), CloudSyncSection, App.tsx, HotkeyService(globalShortcut), LocalSTTService(_findFreePort), LocalLLMService(/no_think + stripReasoning), TextInsertService(Cmd+V), bootstrap(hideRecordingTip), ... + +## 🔗 참고 +- `memory/project_status.md` — 전체 현황 + V2-6차 [A~L] + SaaS [1+2] +- `docs/v2/00-v2-master-plan.md` — V2 마스터 플랜 +- `docs/v2/phase-V2-4.md` — 데스크톱 동기화 설계 +- `apps/desktop/.env.local` — 빌드 타임 Supabase env (gitignored) +- `apps/desktop/env.example` — 템플릿 +- `memory/handoff-archive/2026-04-10-2300-windows-to-mac.md` — 이전 핸드오프 + +--- + +# 🎯 다음 세션 시작 프롬프트 (사용자가 그대로 복사해서 붙여넣기) + +다음 세션에서 그대로 붙여넣을 프롬프트는 별도 파일에: +**`memory/big-bang-prompt.md`** diff --git a/memory/handoff-latest.md b/memory/handoff-latest.md index 1b25928..5bd3e16 100644 --- a/memory/handoff-latest.md +++ b/memory/handoff-latest.md @@ -1,136 +1,165 @@ -# Session Handoff — 2026-04-11 09:40 (Mac, Big Bang 사이클 직전) +# Session Handoff — 2026-04-11 (빅뱅 사이클 완료) > From: macOS (yunchan-ui-MacBookPro) -> Last commit: `dd1c305` — feat(desktop): SaaS [1+2] 빌드 타임 env + OAuth 강제 로그인 게이트 -> Branch: `main` +> Last commit: `ceadf1b` — feat(desktop): SaaS [6] 로컬 우선 sync + login_required UI (빅뱅 Phase 3) +> Branch: `main` (origin 기준 19 commits ahead) > Remote: `https://gitlab.twentyoz.kr:8443/d3r0/voice.git` -## ✅ 이번 세션에서 한 일 (1M 컨텍스트, 데스크톱 Mac 안정화 + SaaS 1차) +## ✅ 이번 세션에서 한 일 — 빅뱅 1차 완료 -### 환경 -- Mac 부트스트랩: Node 22 (brew), sox 14, supabase CLI 2.84 -- `npm install --force` (rollup win32 옵셔널 dep 충돌 우회) -- `@electron/rebuild@3 --version=33.4.11` 완료 -- Sanity build: desktop/web typecheck, web `next build`, api-client vitest 19 passed +### 비즈니스 모델 확정 +- **무료 로컬 = 사용자 entry point** (회원가입 없이 즉시 킬러 피처 체험, onboarding funnel 입구) +- **유료 클라우드 SaaS = 수익화** (OAuth 로그인 + pro 구독 + premium LLM + 멀티 디바이스 sync) +- 이전 세션 SaaS [2] OAuth 강제 게이트 **철회** -### Supabase 배포 -- 프로젝트: `yunchan8804-blip's Project` (`llnocwyqvhgwpdjcqqyw`) -- `supabase link` + `db push` (8개 마이그레이션) -- `supabase functions deploy` (10개 Edge Functions) -- `apps/web/.env.local` + `server/supabase/.env.local` 작성 +### 완료한 Phase (모든 커밋 로컬 `main`에 있음, push 미수행) -### V2-6차 [W][A~D] — 웹 고도화 -- W. fix: AppRouterCacheProvider Emotion key `'d3ro-mui'` → `'mui'` (숫자 3 → SSR 500) -- A. Dark/Light/Theme 토글 (`theme-mode-context.tsx`, 12개 locale `theme.*`) -- B. DocumentEditor Mermaid + Markdown 렌더 (`markdown-preview.tsx`) -- C. 회의 오디오 재생 (`meeting-audio-player.tsx`, Storage signed URL 1h) -- D. Dashboard 14일 추이 차트 (recharts) +**Phase 1 — 사용자별 SQLite 격리** (`816f527`) +- `db/index.ts` 전면 재설계: `openForUser(userId)`, `closeCurrent()`, `getDatabase()`, `isLocalMode()` +- 경로: `userData/users/${userId}/d3ro.db` (uuid) 또는 `_local` (익명) +- legacy `d3ro-voice.db` → silent archive rename +- CloudSyncService `_onAuthenticated(session, reason)` + `_onSignOut()` 단일 진입점 (SSOT) +- signOut 시퀀스: VoiceMode cancel → MeetingMode stopRecording → Caption stop → Realtime stop → auth.signOut → token clear → LicenseService.resetToFree → closeCurrent → openLocal → auth-changed(null) emit -### V2-6차 [E~L] — 데스크톱 Mac 안정화 -- E. macOS 단축키 표기 ⌘⇧⌃⌥ (`format-hotkey.ts` + 호출 위치 4개) -- F. Sidecar `apps/desktop/sidecar/.venv/` 생성 + paths.ts venv 우선 -- G. HotkeyRecordModal 칩 'WIN' → ⌘ 표기 (getKeyName 플랫폼 분기) -- H. `bootstrap.ts` `hideRecordingTip` import 누락 → ReferenceError 픽스 -- I. macOS 시스템 beep 차단 — Electron `globalShortcut` 통합 (HotkeyService) -- J. Sidecar 동적 포트 (`_findFreePort`, orphan EADDRINUSE 회피) -- K. macOS Cmd+V paste — `TextInsertService` `LeftSuper`/`LeftControl` 분기 -- L. qwen3 reasoning 39초 — `/no_think` 토큰 + `stripReasoningBlocks` + 빈 응답 fallback +**Phase 1.5 — 로컬 모드 = entry point** (`1a01cea`) +- `LOCAL_USER_ID = '_local'` + `openLocal()` 헬퍼 +- `bootstrap.ts`: `database` step 복원. 앱 시작 시 `openLocal()` 호출 → LoginScreen 없이 즉시 메인 UI +- `App.tsx`: AuthGate 상태머신 완전 제거, 항상 AppLayout 렌더 +- 로그아웃 시 `closeCurrent()` → `openLocal()` — 앱은 계속 로컬 모드로 동작 -### SaaS [1+2] — 데스크톱 fat client → 진짜 SaaS 클라이언트 변환 -- [1] **빌드 타임 Supabase env 주입** - - `electron.vite.config.ts`: `loadEnv('D3RO_')` + main `define` - - `apps/desktop/.env.local`: `D3RO_SUPABASE_URL/ANON_KEY` - - `ConfigService`: `BUILD_TIME_*` 상수, `configGet/Set`이 빌드 타임 우선 + 변경 차단 -- [2] **OAuth 첫 실행 강제 게이트** - - `CloudSyncState.saasMode: boolean` 추가 - - `LoginScreen.tsx` 신규 (Google/GitHub만) - - `App.tsx` `AuthGate` 상태머신 - - `CloudSyncSection` saasMode일 때 URL/Key 입력 필드 숨김 +**Phase 2 — 온보딩** (`f1321df`) +- `AppConfig.onboardingCompleted: boolean` 정식화 (types.ts + ConfigService defaults) +- 타입 캐스팅 3곳 제거 (AppLayout/OnboardingModal/SettingsModal) +- OnboardingModal 5 → 6 step: 환영 → 마이크 → 핫키 → Ollama → **Cloud Sync(선택)** → 완료 +- Cloud Sync step은 `saasMode === true`일 때만 노출. tagline + 3 benefit + "설정에서 언제든지 로그인". **로그인 버튼 미노출** (부담 zero, 유일 OAuth 진입점은 Settings→CloudSync) +- i18n ko/en `onboarding.cloud.*` 6 키 -### 미완 / 확실히 알려진 이슈 -- Ollama `qwen3:4b`가 4B reasoning 모델이라 CPU에서 느림 → 사용자가 더 빠른 모델로 교체 권장 (`gemma3:1b` 또는 `qwen2.5:3b`) -- Accessibility 권한 첫 실행 시 macOS 권한 다이얼로그가 떠야 함 (안 뜨면 시스템 설정 → 손쉬운 사용에 Electron 추가) -- 데스크톱 SQLite는 여전히 단일 파일 (`userData/d3ro-voice/d3ro.db`) — 한 PC에 여러 사용자가 OAuth 로그인 시 데이터 섞일 위험 ← **빅뱅 핵심 작업** +**Phase 4 — 티어 enforcement** (`46b77f1`) — 로컬 해방 + 클라우드 gate +- 기존 정책 폐기: DICTATION 20/일, LLM_PROCESS 10/일, LIVE_CAPTION/VOICE_MEMO/SCREEN_CONTEXT/MEETING_SUMMARY 등의 pro/pro_plus lock 전부 삭제 +- 신규 feature: `Feature.PREMIUM_LLM`, `Feature.CLOUD_SYNC` +- `CLOUD_FEATURES` Set + `canUse()`에 `isLocalMode()` 감지: 익명 로컬에서 cloud feature → `login_required` +- `syncFromCloud(tier)` + `resetToFree()` — CloudSyncService가 호출 +- `_fetchSubscriptionTier(userId)` — Supabase `subscriptions` 테이블 조회 -## 🚧 다음 세션: 빅뱅 사이클 (Desktop SaaS Client 완성) +**정책 매트릭스** +| Feature | 익명 `_local` | 로그인 free | pro | pro_plus | +|---|---|---|---|---| +| 로컬 16종 (DICTATION~OS_AUTOMATION) | ✅ 무제한 | ✅ 무제한 | ✅ 무제한 | ✅ 무제한 | +| PREMIUM_LLM | ❌ login_required | 🔸 5/일 | 🔸 500/일 | ✅ 무제한 | +| CLOUD_SYNC | ❌ login_required | ✅ | ✅ | ✅ | -자세한 단계별 계획은 아래 "다음 세션 시작 프롬프트" 참조. +**Phase 3 — 로컬 우선 sync + login_required UI** (`ceadf1b`) — 재정의 +- 원래 "Supabase = source of truth" 방향 철회. 로컬이 SoT, 클라우드 mirror. +- `_initialSync(reason)` 신규 — `_onAuthenticated` 끝에 fire-and-forget `pushAll → pullAll` +- `FeatureAccess.reason` / `UpgradePromptEvent.reason`에 `'login_required'` 추가 +- `UpgradePromptModal` login_required 케이스: "로그인 필요" title + "로그인하기" 버튼 → `d3ro:open-settings` custom event (tab=cloud) +- i18n ko/en `license.loginRequired.*` 3 키 -요약 목표: -1. **사용자별 SQLite 격리** — `userData/users/${userId}/d3ro.db` -2. **회원가입/온보딩 흐름** — OAuth 첫 가입 시 환영 + 마이그레이션 -3. **cloud-first 정책** — Supabase source of truth, local read-through cache -4. **멀티 디바이스 sync 강화** -5. **티어 enforcement** — 데스크톱에서도 free quota 차단 -6. **데스크톱 ↔ 웹 ↔ 모바일 데이터 일원화 검증** +**Phase 5 — 3 클라이언트 일원화 검증** → **OAuth provider 대기** (미완) + +**Phase 6 — wrap-up** (이 파일) + +## 🚧 남은 작업 / 다음 세션 우선순위 + +### 즉시 해야 할 것 (사용자 수동) +1. **Supabase Google/GitHub OAuth provider 연결**: + - https://supabase.com/dashboard/project/llnocwyqvhgwpdjcqqyw/auth/providers + - Google Cloud Console에서 OAuth Client ID 발급 (Web app, Authorized redirect URI: `https://llnocwyqvhgwpdjcqqyw.supabase.co/auth/v1/callback`) + - Supabase 대시보드 Google provider에 Client ID/Secret 입력 +2. **Edge Function secrets 주입** (사용자가 키 제공 시): + - `supabase secrets set ANTHROPIC_API_KEY=... OPENAI_API_KEY=...` + - 이게 없으면 PREMIUM_LLM 호출 경로 완성해도 실제 동작 안 함 +3. **커밋 push 여부 결정**: + - 이번 세션 신규 커밋 5개 (`816f527..ceadf1b`) + 이전 세션 커밋 포함 총 19 ahead + - 사용자 확인 후 `git push origin main` + +### 빅뱅 후속 (코드 작업, 다음 세션 이후) +- **PREMIUM_LLM 호출 경로 구현** (Phase 3.2): + - LocalLLMService에 cloud mode 추가 또는 새 PremiumLLMService + - `llm-proxy` Edge Function(Anthropic/OpenAI) 호출 + - `canUse(PREMIUM_LLM)` gate + `consumeQuota` hook + - ConfigService에 "premium LLM 사용" 스위치 추가 +- **auto push on write** (Phase 3.3): + - VoiceMode session-completed → `pushOne('history', row)` 자동 호출 + - MeetingMode 종료 → `pushOne('meetings', row)` + - 실패 시 queue에 enqueue +- **오프라인 WriteQueue** (Phase 3.4): + - `userData/users/${userId}/write-queue.json` 디스크 영속화 + - 온라인 복귀 시 자동 flush +- **Phase 5 실증**: OAuth provider 연결 후 데스크톱 ↔ 웹 ↔ 모바일 데이터 일원화 검증 (체크리스트는 `memory/project_status.md` SaaS [7] 섹션) +- **온보딩 10개 locale 번역** — 현재 ko/en만. ja/zh/zh-TW/es/fr/de/pt/ru/vi/th 추가 +- **Database 마이그레이션 — legacy d3ro-voice.db가 있는 환경 실측** — 이번 세션에서 archiveLegacyDbIfExists는 로그인 시점에만 발동하므로, 테스트 데이터(`d3ro-voice.db`)가 있는 사용자가 실제 로그인하기 전까지는 정상 상황 아래 트리거되지 않음 ## 🔑 다음 세션 시작 시 즉시 할 일 ```bash -# 1. git pull -git pull origin main # 마지막 커밋 dd1c305 또는 그 이후 확인 +# 1. git pull (혹시 push 했다면) +git pull origin main # 마지막 커밋 ceadf1b 또는 그 이후 확인 -# 2. 환경 검증 (이미 mac에 다 있음) -node --version # v22.x -which sox supabase # /opt/homebrew/bin/... -ls apps/desktop/sidecar/.venv/bin/python3 # exists -ls apps/desktop/.env.local # gitignored, exists +# 2. 환경 확인 (이미 mac에 다 설치됨) +node --version # v22.22.2 +ls apps/desktop/sidecar/.venv/bin/python3 # exists +ls apps/desktop/.env.local # gitignored, D3RO_SUPABASE_* -# 3. 워크스페이스 재설치 필요 시 -npm install --force - -# 4. 데스크톱 dev 띄워서 LoginScreen 보이는지 확인 +# 3. dev 재시작 npm run dev -# → 첫 화면이 LoginScreen이어야 함 (Google/GitHub 버튼) +# → LoginScreen 없이 바로 메인 UI 진입 +# → 모든 기존 기능 (LIVE_CAPTION, VOICE_MEMO, MEETING_SUMMARY 등) pro lock 해제됨 +# → ⌘⇧1 녹음 quota 제한 없음 +# → Settings → About → "온보딩 다시 보기" 로 새 6 step 플로우 확인 가능 ``` ## ⚠ 환경 / 주의사항 -- **gitlab 푸시는 사용자 명시 후에만**: 이번 세션에선 push 안 했음. 다음 세션에서 빅뱅 작업 끝나면 사용자 확인 후 `git push origin main` -- **Ollama 모델**: `qwen3:4b` 설치됨, 느리면 `ollama pull gemma3:1b` 권장 -- **Accessibility 권한**: 데스크톱 핫키 동작에 필수 — macOS 시스템 설정에서 수동 허용 -- **Supabase 외부 키**: ANTHROPIC/OPENAI/RESEND/STRIPE는 아직 안 주입됨 → web의 `/chat`, `/knowledge`, `/billing`은 키 채워지기 전엔 동작 안 함 (사용자가 키 줄 때 `supabase secrets set`) -- **데스크톱 .env.local**: gitignored, 이번 세션에서 작성. 만약 다음 세션이 다른 PC에서 시작하면 `apps/desktop/env.example`을 보고 직접 작성 필요 -- **DB 마이그레이션**: 빅뱅 [1] 사용자별 SQLite 격리 시 기존 단일 DB의 데이터를 첫 로그인 사용자에게 귀속시키는 마이그레이션 필요. 데이터 손실 주의 +- **모든 기존 사용자 데이터는 `users/_local/d3ro.db`에 있음**. 이번 세션 dev 실행 중 생성됨. +- **Legacy `d3ro-voice.db`는 archiveLegacyDbIfExists()가 첫 `openForUser` 시점에서만 rename** → 로그인 전까지는 원본 위치에 남아있을 수 있음 (bootstrap의 `openLocal()`도 `openForUser('_local')`이므로 실제로는 archive 트리거됨. 실측 필요). +- **OAuth provider 미연결**: `_onAuthenticated` 코드는 준비됐지만 로그인 버튼 누르면 Supabase가 400 에러 반환할 것. Phase 5 실증 전 provider 연결 필수. +- **기존 pro 락이 걸려있던 테스트들**: LicenseService 단위 테스트가 있다면 회귀 가능. 일단 typecheck/build는 통과. ## 📦 의존성 / 도구 + - Node 22.22.2 (brew) -- Python 3.13 (Framework) + venv at `apps/desktop/sidecar/.venv` +- Python 3.13 + venv at `apps/desktop/sidecar/.venv` - Supabase CLI 2.84.2 -- Ollama (사용자가 별도 설치, qwen3:4b 모델) -- @electron/rebuild@3 33.4.11 +- Ollama (사용자 설치, qwen3:4b 모델) - Electron 33.4.11 ## 🧪 마지막 검증 + | 게이트 | 상태 | |---|---| -| desktop tsc | ✅ | -| desktop build (electron-vite) | ✅ | -| desktop dev (실제 실행) | ✅ Main window shown | -| Hotkey ⌘⇧1 + globalShortcut | ✅ accelerator=Shift+Cmd+1 등록 | -| Sidecar venv spawn | ✅ 한국어 96% 1.5초 오디오 → 426ms 전사 | -| Cmd+V paste | ✅ (사용자 확인 "되긴한다") | -| LLM refine | ⚠ qwen3:4b reasoning 끄기 후 첫 시도 미확인 — 사용자 검증 필요 | -| LoginScreen | ⚠ 이번 세션 마지막에 빌드만, 사용자 시각 확인 미수행 | +| desktop `tsc --noEmit` | ✅ | +| desktop `npm run build` | ✅ | +| dev 런타임 cold start | ✅ `local database opened: users/_local/d3ro.db` → `Main window shown` | +| 파일시스템 `users/_local/d3ro.db` | ✅ 생성 확인 | +| 온보딩 UI 새 플로우 | ✅ 사용자 확인 "잘 나온다" | +| OAuth 로그인 실측 | ❌ provider 미연결 | +| Phase 4 로컬 해방 런타임 실측 | ⚠ 사용자가 dev 재시작 후 기존 pro lock 기능 써봐야 확정 | +| 커밋 push | ❌ 사용자 컨펌 대기 | -## 📊 누적 통계 (이번 세션 포함) -- 신규 커밋: 13개 (V2-6차 [A~L] + SaaS [1+2]) -- 신규 파일: - - apps/web: theme-mode-context, markdown-preview, meeting-audio-player, meetings-trend-chart - - apps/desktop: format-hotkey, LoginScreen, sidecar/.venv, .env.local, env.example -- 수정: ConfigService(빌드 타임), CloudSyncService(saasMode), CloudSyncSection, App.tsx, HotkeyService(globalShortcut), LocalSTTService(_findFreePort), LocalLLMService(/no_think + stripReasoning), TextInsertService(Cmd+V), bootstrap(hideRecordingTip), ... +## 📊 누적 통계 (이번 세션) + +- 신규 커밋: 5개 (`816f527`, `1a01cea`, `f1321df`, `46b77f1`, `ceadf1b`) +- 총 변경: 16 파일 (코드 10 + i18n 4 + memory 1 + types 1) +- 로컬 19 commits ahead of origin/main ## 🔗 참고 -- `memory/project_status.md` — 전체 현황 + V2-6차 [A~L] + SaaS [1+2] -- `docs/v2/00-v2-master-plan.md` — V2 마스터 플랜 -- `docs/v2/phase-V2-4.md` — 데스크톱 동기화 설계 + +- `memory/project_status.md` — 전체 현황 + 빅뱅 Phase 1~6 상세 +- `memory/big-bang-prompt.md` — 원래 빅뱅 계획 (일부 철회됨 — SaaS [2] OAuth 강제 게이트 철회, Phase 3 재정의) +- `memory/handoff-archive/2026-04-11-0940-prior-bigbang.md` — 이번 세션 시작 시점 스냅샷 +- `docs/v2/phase-V2-4.md` — 데스크톱 sync 원래 설계 (Phase 3 재정의 이전) - `apps/desktop/.env.local` — 빌드 타임 Supabase env (gitignored) -- `apps/desktop/env.example` — 템플릿 -- `memory/handoff-archive/2026-04-10-2300-windows-to-mac.md` — 이전 핸드오프 ---- +## 🎯 성공 기준 진행률 -# 🎯 다음 세션 시작 프롬프트 (사용자가 그대로 복사해서 붙여넣기) - -다음 세션에서 그대로 붙여넣을 프롬프트는 별도 파일에: -**`memory/big-bang-prompt.md`** +| # | 기준 | 상태 | +|---|---|---| +| 1 | 신규 사용자: LoginScreen 없이 바로 메인 UI → 로컬 기능 즉시 사용 | ✅ (Phase 1.5) | +| 2 | 온보딩 자동 표시 + Cloud Sync 티저 (로그인 부담 zero) | ✅ (Phase 2) | +| 3 | 핫키 ⌘⇧1 녹음 → 로컬 DB 저장, quota 제한 없음 | ✅ (Phase 4 정책) — 실측 대기 | +| 4 | 로컬 기능 16종 전부 free 사용 가능 (pro/pro_plus lock 해제) | ✅ (Phase 4 정책) — 실측 대기 | +| 5 | 다른 디바이스 로그인 시 같은 데이터 | ❌ OAuth provider 대기 | +| 6 | 사용자 A → signOut → 사용자 B 로그인 시 A 데이터 안 보임 | ❌ OAuth provider 대기 | +| 7 | PREMIUM_LLM / CLOUD_SYNC 접근 시 login_required UI | ✅ (Phase 3) — 실측 대기 | +| 8 | Free 사용자 PREMIUM_LLM 5/일 quota 초과 차단 | ⚠ feature 정의만, 호출부 미구현 | diff --git a/memory/project_status.md b/memory/project_status.md index 81406eb..7b211a7 100644 --- a/memory/project_status.md +++ b/memory/project_status.md @@ -208,6 +208,33 @@ OAuth provider도 아직 Supabase에 설정 안 된 상태. 강제 게이트는 - `~/Library/Application Support/d3ro-voice/users/${uuid}/d3ro.db` 파일 생성 확인 - 기존 `d3ro-voice.db`가 있는 환경에서 archive rename 동작 확인 +### SaaS [7] 3 클라이언트 일원화 검증 — **OAuth provider 연결 대기** (Phase 5) + +> Phase 1~4+3이 로컬/클라우드 feature gate + sync 인프라를 모두 배선했으나, +> 실제 로그인을 통해 "데스크톱 ↔ 웹 ↔ 모바일 같은 데이터 관찰"을 검증하려면 Supabase OAuth provider 연결이 선행되어야 함. + +**사용자가 해야 할 선행 작업 (Supabase 대시보드)** +1. https://supabase.com/dashboard/project/llnocwyqvhgwpdjcqqyw/auth/providers 접속 +2. **Google provider 활성화**: + - Google Cloud Console에서 OAuth 2.0 Client ID 발급 + - Application type: Web application + - Authorized redirect URIs: `https://llnocwyqvhgwpdjcqqyw.supabase.co/auth/v1/callback` + - Supabase 대시보드의 Google provider에 Client ID/Secret 입력 +3. **(선택) GitHub provider**도 동일 패턴으로 활성화 +4. 데스크톱 deep link scheme은 이미 `d3ro-voice://auth-callback`으로 설정됨 + +**OAuth 연결 후 검증 체크리스트 (다음 세션에서)** +- [ ] 데스크톱 Settings → Cloud Sync → Google 클릭 → 브라우저 동의 → 앱으로 deep link 콜백 +- [ ] `[auth:signin] DB opened for ${uuid}` 로그 + `users/${uuid}/d3ro.db` 파일 생성 +- [ ] `[auth:signin] Initial push done` + `Initial pull done` 로그 +- [ ] `subscriptions` 테이블에 free 티어 row 자동 생성 (auth trigger) +- [ ] LicenseService tier가 'free'로 sync됨 (tier-changed 이벤트) +- [ ] 웹 앱(`apps/web`) 에서 같은 계정으로 로그인 → 데스크톱에서 생성한 history/meetings 즉시 조회 +- [ ] 웹에서 meeting 편집 → 데스크톱에 Realtime으로 반영 (5초 이내) +- [ ] 모바일 Expo 앱에서 같은 계정 로그인 → 같은 데이터 +- [ ] 데스크톱 signOut → `LicenseService.resetToFree()` + `users/_local/d3ro.db`로 복귀 → 익명 로컬 모드 계속 동작 +- [ ] 로그아웃 상태에서 PREMIUM_LLM 호출 시도 시 `UpgradePromptModal` (login_required) 표시 + ### SaaS [6] 로컬 우선 sync + login_required UI (Phase 3, 2026-04-11) > 빅뱅 Phase 3의 원래 설계("Supabase = source of truth")는 로컬 entry point 철학과 충돌하므로 재정의.