feat(desktop): SaaS [5] 티어 enforcement — 로컬 해방 + 클라우드 gate (빅뱅 Phase 4)
비즈니스 모델 확정: - 익명 로컬 사용자 → 로컬 기능 16개 전부 무제한 (entry point) - 클라우드 기능 (PREMIUM_LLM, CLOUD_SYNC) → 로그인 필수 - 로그인 free → PREMIUM_LLM 5/일, CLOUD_SYNC 허용 - 로그인 pro → PREMIUM_LLM 500/일 (fair use cap) - 로그인 pro_plus → PREMIUM_LLM 무제한 기존 정책 폐기: - DICTATION 20/일 quota 삭제 - LLM_PROCESS 10/일 quota 삭제 - LIVE_CAPTION/VOICE_MEMO/SCREEN_CONTEXT/VOICE_COMMAND/LLM_CHAIN pro lock 해제 → free - FILE_TRANSCRIPTION/VOICE_CONVERSATION/DICTATION_TEMPLATE/ MEETING_SUMMARY/LOCAL_RAG/OS_AUTOMATION pro_plus lock 해제 → free types.ts: - Feature enum: PREMIUM_LLM, CLOUD_SYNC 추가 - FeatureAccess.reason: 'login_required' 추가 LicenseService.ts: - QUOTA_LIMITS / FEATURE_MIN_TIER 전면 재작성 - CLOUD_FEATURES Set 신규 - canUse(): CLOUD_FEATURES && isLocalMode() → login_required 조기 반환 - syncFromCloud(tier): Supabase subscriptions 티어를 electron-store에 캐시 + tier-changed emit - resetToFree(): 로그아웃 시 pro/pro_plus 캐시 + 라이센스 필드 전부 null - isLocalMode() import 추가 CloudSyncService.ts: - _fetchSubscriptionTier(userId): subscriptions 테이블에서 활성 티어 조회 (row 없음 / 비정상 값 → free 폴백) - _onAuthenticated: DB open → tier fetch → syncFromCloud → auth-changed → Realtime - _onSignOut: Voice/Meeting/Caption stop → Realtime stop → auth.signOut → token clear → license.resetToFree → closeCurrent → openLocal → emit null 검증: - desktop tsc --noEmit ✅ - desktop npm run build ✅ - 로컬 사용자 모든 기존 기능 접근 가능 (pro lock 완전 제거)
This commit is contained in:
parent
f1321df83c
commit
46b77f1118
4 changed files with 208 additions and 35 deletions
|
|
@ -208,6 +208,52 @@ OAuth provider도 아직 Supabase에 설정 안 된 상태. 강제 게이트는
|
|||
- `~/Library/Application Support/d3ro-voice/users/${uuid}/d3ro.db` 파일 생성 확인
|
||||
- 기존 `d3ro-voice.db`가 있는 환경에서 archive rename 동작 확인
|
||||
|
||||
### SaaS [5] 티어 enforcement — 로컬 해방 + 클라우드 gate (Phase 4, 2026-04-11)
|
||||
|
||||
> 사용자 표현: "로컬 사용자는 풀어줘야해! 클라우드 동기화 같은 것과 고급 api가 막히는거지"
|
||||
>
|
||||
> 기존 LicenseService는 DICTATION 20/일, LLM_PROCESS 10/일 quota + LIVE_CAPTION/VOICE_MEMO/SCREEN_CONTEXT/... 대부분이 pro lock 이었음. 로컬 entry point 철학과 정면 충돌 → 전면 교체.
|
||||
|
||||
**정책 매트릭스 (Phase 4 확정)**
|
||||
|
||||
| Feature 종류 | 익명 로컬 `_local` | 로그인 free | pro | pro_plus |
|
||||
|---|---|---|---|---|
|
||||
| 로컬 기능 16종 | ✅ 무제한 | ✅ 무제한 | ✅ 무제한 | ✅ 무제한 |
|
||||
| PREMIUM_LLM (신규) | ❌ login_required | 🔸 5/일 | 🔸 500/일 | ✅ 무제한 |
|
||||
| CLOUD_SYNC (신규) | ❌ login_required | ✅ | ✅ | ✅ |
|
||||
|
||||
- `packages/core/src/types.ts`:
|
||||
- `Feature` enum에 `PREMIUM_LLM`, `CLOUD_SYNC` 추가
|
||||
- `FeatureAccess.reason`에 `'login_required'` 추가 (익명 로컬 모드에서 cloud feature 요청 시)
|
||||
- `LicenseService.ts`:
|
||||
- `QUOTA_LIMITS.free` — DICTATION/LLM_PROCESS 20/10 삭제, `PREMIUM_LLM: 5`만 남김
|
||||
- `QUOTA_LIMITS.pro` — `PREMIUM_LLM: 500` (fair use cap)
|
||||
- `FEATURE_MIN_TIER` — 기존 16개 feature 전부 `'free'`로 완화. 신규 `PREMIUM_LLM`/`CLOUD_SYNC`도 `'free'` (로그인만 하면 접근 가능, 티어는 quota로만 구분)
|
||||
- `CLOUD_FEATURES: Set<Feature>` 신규 — 익명 로컬 모드 감지용
|
||||
- `canUse()` — `CLOUD_FEATURES.has(feature) && isLocalMode()` → `login_required` 반환. 그 외는 기존 tier/quota 로직
|
||||
- `syncFromCloud(tier)` 신규 — Supabase `subscriptions` 티어를 electron-store에 캐시 + `tier-changed` emit
|
||||
- `resetToFree()` 신규 — 로그아웃 시 호출. licenseKey/activatedAt/lastVerifiedAt/offlineGraceUntil 모두 null로 리셋
|
||||
- `db/index.ts`의 `isLocalMode()` import 추가
|
||||
- `CloudSyncService.ts`:
|
||||
- `_fetchSubscriptionTier(userId)` 신규 — `subscriptions` 테이블에서 `{tier, status: 'active'}` 조회. 없으면 free, 비정상 티어도 free 폴백
|
||||
- `_onAuthenticated()`:
|
||||
- DB 오픈 → **subscription tier fetch → LicenseService.syncFromCloud(tier)** → auth-changed emit → Realtime
|
||||
- fetch 실패 시 warn만 찍고 현재 티어 유지 (오프라인 grace)
|
||||
- `_onSignOut()`:
|
||||
- Voice/Meeting/Caption stop → Realtime stop → auth.signOut → token clear → **LicenseService.resetToFree()** → closeCurrent → openLocal → auth-changed(null) emit
|
||||
- **검증**
|
||||
- desktop `tsc --noEmit` ✅
|
||||
- desktop `npm run build` ✅ (main bundle 정상)
|
||||
- 익명 로컬 사용자는 이제 기존 기능(LIVE_CAPTION/VOICE_MEMO/MEETING_SUMMARY/FILE_TRANSCRIPTION 등 16개) 전부 사용 가능 — **pro lock 완전 제거**
|
||||
- 실측 검증 대기:
|
||||
- 기존 녹음/후처리가 quota 메시지 없이 계속 작동
|
||||
- PREMIUM_LLM 호출 경로는 Phase 3에서 추가 예정 → 지금은 feature 정의만
|
||||
|
||||
**Phase 4에서 의도적으로 뺀 것**
|
||||
- PREMIUM_LLM 실제 호출 경로 — Phase 3(cloud-first)에서 Edge Function `llm-proxy` 호출 로직과 함께
|
||||
- daily_usage를 Supabase로 동기화 — 현재는 로컬 SQLite `daily_usage` 테이블로만 추적 (사용자별 격리 DB라 문제 없음)
|
||||
- UpgradePromptModal 텍스트 업데이트 — `login_required` 케이스용 새 메시지는 Phase 3/5에서
|
||||
|
||||
### SaaS [4] 회원가입 / 온보딩 (Phase 2, 2026-04-11)
|
||||
|
||||
> 기존 `OnboardingModal`을 로컬 모드 entry point에 맞게 정리 + Cloud Sync 티저 step 추가.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue