feat(desktop): SaaS [3] 사용자별 SQLite 격리 (빅뱅 Phase 1)

db/index.ts 전면 재설계:
- initDatabase/closeDatabase 폐기
- openForUser(userId), closeCurrent, getDatabase, getCurrentUserId 신 API
- 경로: userData/users/${userId}/d3ro.db
- applySchema() 추출 — 새 user DB마다 테이블 + ALTER 마이그레이션 재실행
- legacy d3ro-voice.db는 silent archive (archive-legacy-ISO.db로 rename만)

CloudSyncService 인증 lifecycle SSOT:
- _onAuthenticated(session, reason) 단일 진입점
  init() 세션 복원, handleAuthCallback() 신규 로그인 모두 수렴
  DB open 실패 시 세션 롤백 + sync-error emit
- _onSignOut() 안전 종료 시퀀스
  VoiceMode cancel → MeetingMode stopRecording → Caption stop →
  Realtime stop → auth.signOut → token clear →
  auth-changed(null) emit → closeCurrent
- VoiceMode/MeetingMode/Caption은 dynamic import로 순환 의존 회피

bootstrap.ts:
- database step 제거 (DB는 _onAuthenticated에서만 열림)
- cloud-sync step이 마지막 유지 (세션 복원 → DB open → auth-changed)
This commit is contained in:
윤찬 2026-04-11 09:58:00 +09:00
parent 5ad1d19c3a
commit 816f527592
4 changed files with 354 additions and 79 deletions

View file

@ -15,7 +15,6 @@ import { getSoundEffectService } from './services/SoundEffectService'
import { getAutoLaunchService } from './services/AutoLaunchService'
import { getAudioCaptureService } from './services/AudioCaptureService'
import { initLicenseService } from './services/LicenseService'
import { initDatabase } from './db'
import {
createMainWindow,
getMainWindow,
@ -46,7 +45,8 @@ export async function bootstrap(): Promise<void> {
const steps: BootstrapStep[] = [
{ name: 'logger', critical: false, fn: initLogger },
{ name: 'config', critical: false, fn: initConfig },
{ name: 'database', critical: true, fn: initDB },
// Phase 1 (SaaS 빅뱅): DB는 더 이상 bootstrap 타이밍에 열지 않는다.
// CloudSyncService._onAuthenticated(session)가 사용자별 DB를 연다.
{ name: 'license', critical: false, fn: initLicense },
{ name: 'create-windows', critical: true, fn: createWindows },
{ name: 'tray', critical: false, fn: initTray },
@ -61,6 +61,7 @@ export async function bootstrap(): Promise<void> {
{ name: 'llm-polling', critical: false, fn: initLLMPolling },
{ name: 'meeting-summary-wiring', critical: false, fn: initMeetingSummaryWiring },
{ name: 'meeting-mode', critical: false, fn: initMeetingMode },
// cloud-sync는 가장 마지막에 — 세션 복원 성공 시 DB를 열고 auth-changed emit.
{ name: 'cloud-sync', critical: false, fn: initCloudSync },
]
@ -90,10 +91,6 @@ async function initConfig(): Promise<void> {
initConfigService()
}
async function initDB(): Promise<void> {
initDatabase()
}
async function initLicense(): Promise<void> {
initLicenseService()
}