Commit graph

8 commits

Author SHA1 Message Date
yunchan8804
61a96b3e9b feat(V2-6/V2-7/V2-8): Mobile MVP + Teams + Billing 스캐폴딩
V2-6 — Mobile (Expo) MVP
- apps/mobile/ 신규, npm workspace에서 제외 (Expo deps 부담 회피)
- Expo SDK 51 + Expo Router + AsyncStorage Supabase 클라이언트
- 화면: index/login/(tabs)/{meetings,record,profile}
- expo-av로 녹음 → Edge Function stt-proxy 호출
- expo-web-browser + expo-linking으로 OAuth 콜백 처리
- README에 setup/EAS build 가이드
- 루트 package.json workspaces를 명시 나열로 변경 (apps/mobile 제외)

V2-7 — 팀 기능 (Web)
- apps/web/src/app/teams/page.tsx — 가입한 팀 카드 그리드
- apps/web/src/app/teams/[id]/page.tsx — 멤버 + 공유 회의
- components/teams/create-team-form.tsx — 팀 생성 + owner 자동 team_members
- components/teams/invite-member-form.tsx — user_id 직접 초대 (V2-7b에서 invite flow)
- Sidebar에 Teams/Billing 메뉴 + 아이콘
- ko.json에 nav.teams/nav.billing 키 추가
- V2-2 teams/team_members RLS 활용

V2-8 — 결제 스캐폴딩
- apps/web/src/app/billing/page.tsx — Free/Pro/Team 가격표 + 현재 구독
- components/billing/checkout-button.tsx — Edge Function 호출 후 redirect
- server/supabase/functions/stripe-checkout/index.ts:
  - JWT 인증 -> 기존 customer 조회/생성 -> Checkout Session 생성
  - subscriptions 테이블에 customer_id upsert
- server/supabase/functions/stripe-webhook/index.ts:
  - checkout.session.completed -> subscriptions tier=pro/team active
  - customer.subscription.updated/created -> status/period 업데이트
  - customer.subscription.deleted -> tier=free, status=canceled
  - signature 검증은 placeholder (V2-8b에서 정식)
- server/supabase/config.toml에 두 함수 등록 (webhook verify_jwt=false)

검증:
- desktop typecheck OK (회귀 없음)
- web typecheck OK
- web next build OK (11 라우트)
- mobile은 별도 install 필요 (workspace 제외)

memory/project_status.md 갱신 — V2 마스터 플랜 전 페이즈 로컬 완료
2026-04-09 16:39:54 +09:00
yunchan8804
d0c33ca259 feat(V2-3): Web App MVP — Next.js 15 + @d3ro/api-client
packages/api-client (@d3ro/api-client) 신규:
- types.ts: 12개 테이블 Row/Insert/Update 타입 + Database 형식
- client.ts: createD3roSupabaseClient 팩토리 (placeholder fallback)
- auth.ts: signInWithOAuth/signOut/getSession/onAuthStateChange
- meetings.ts: 회의 + 메모 + 문서 + 전사 CRUD
- history.ts: 음성 입력 이력 CRUD
- usage.ts: 일일 쿼터 + 구독 조회
- 루트 barrel은 types만 re-export, 함수는 subpath import 전용

apps/web (@d3ro/web) 신규 — Next.js 15 App Router:
- transpilePackages: @d3ro/core, ui, i18n, api-client
- ThemeProvider (MUI + AppRouterCacheProvider)
- I18nProvider (localStorage 어댑터)
- AuthProvider (Supabase session Context)
- 라우트 9개:
  - / (auth 상태 기반 리다이렉트)
  - /login (Google/GitHub OAuth, 미설정 경고)
  - /auth/callback (code -> session 교환)
  - /dashboard (요약 카드 + 최근 회의)
  - /meetings (카드 그리드 리스트)
  - /meetings/[id] (transcripts/memos/documents)
  - /record (getUserMedia + MediaRecorder + stt-proxy)
- Sidebar, 인증 가드, 9바 웨이브폼, 레벨 미터

packages/ui 확장:
- MetalCard가 BoxProps 상속 (sx/onClick 등 전달)
- theme.ts에 typoSx(key) 헬퍼 추가 (d3roTypo -> MUI sx 변환)
- d3roPalette.tag.blue 추가 (M5 정리 포함)
- DS 컴포넌트 9개에 'use client' directive
- MetalDial 미사용 import 제거

packages/i18n 확장:
- ko.json에 7개 새 키 (nav.meetings/record/logout, login.*)

설계 결정:
- Database 제네릭 현재는 기본 타입 (V2-4에서 supabase gen types로 자동화)
- api-client barrel은 타입만 노출해서 컴파일 전파 차단
- DS 컴포넌트 client 경계 명시
- env 없어도 Next.js 빌드 성공 (placeholder URL/key)

검증:
- web typecheck OK
- desktop typecheck OK (회귀 없음)
- web next build OK (9 라우트 정적/동적 생성)
- desktop build OK (회귀 없음)
2026-04-09 02:52:31 +09:00
yunchan8804
77d514222e feat(V2-5): macOS 빌드 지원 — 플랫폼 분기 + electron-builder mac 타겟 + CI
플랫폼 분기 (paths.ts):
- EXE_SUFFIX 상수로 sox/sidecar/ffmpeg 실행파일 확장자 통합
- Windows에선 .exe 자동 부착, Mac/Linux에선 빈 문자열
- 미사용 getProjectRoot 헬퍼 제거

런타임 서비스 Mac 분기:
- SoundEffectService: darwin → /usr/bin/afplay,
  linux → aplay 분기 추가 (execFile로 안전하게)
- ScreenContextService._getActiveWindowInfo:
  win32 → PowerShell + user32.dll (기존),
  darwin → osascript (System Events frontmost process + 윈도우 타이틀)
  Linux는 미지원 (null)

electron-builder.yml:
- mac 타겟 추가 (dmg + zip, arm64 + x64 매트릭스)
- hardenedRuntime, gatekeeperAssess, entitlements 설정
- extendInfo로 NSMicrophoneUsage / NSCameraUsage / NSAppleEvents /
  NSSystemAdministration 권한 메시지
- dmg 레이아웃 (드래그 to /Applications)
- linux AppImage placeholder
- notarize: false 기본, NOTARIZE 환경변수로 활성화

build/entitlements.mac.plist:
- allow-jit, allow-unsigned-executable-memory (Electron 필수)
- audio-input, camera, network.client
- automation.apple-events (활성 윈도우 조회용)
- files.user-selected.read-write
- allow-dyld-environment-variables (sox/ffmpeg 라이브러리 로드)

scripts/build-sidecar.py:
- IS_WINDOWS / IS_MACOS / EXE_SUFFIX 도입
- Windows에서만 --noconsole 플래그
- 빌드 결과 경로 + size 출력 플랫폼 통합

scripts/install-sox.sh (신규):
- Mac/Linux용 SoX 번들 스크립트
- macOS는 otool로 dylib 의존성 식별 후 함께 복사,
  install_name_tool로 rpath를 @loader_path로 변경
- electron-builder의 extraResources 대상 디렉토리에 배치

resources/icons/ (신규):
- README.md만 커밋, 실제 아이콘 파일은 분리
- sips/iconutil/imagemagick으로 .icns/.ico/.png 생성 가이드

.github/workflows/build-mac.yml (신규):
- macos-14 runner (Apple Silicon), arm64/x64 matrix
- brew sox, npm install, @electron/rebuild,
  install-sox.sh, build-sidecar.py, electron-builder dist
- CSC/NOTARIZE 환경변수 자동 처리
- artifact 업로드 (dmg + zip, retention 7일)

docs/v2/phase-V2-5-mac-guide.md (신규):
- 사전 조건, 시스템 의존성, dev 실행, dist 빌드,
  Code signing + Notarization, CI 트리거, 트러블슈팅

검증 (Windows에서):
- typecheck 통과 (Mac 분기 추가에도 회귀 없음)
- build 통과
- dev 런타임 정상

Mac 검증은 사용자 본인 Mac에서 수행 (V2-5 사용자 액션).
2026-04-08 15:57:16 +09:00
yunchan8804
97eb886ec3 feat(V2-2): Supabase 인프라 — 스키마 + RLS + Edge Functions 스캐폴딩
server/supabase/ 신규 디렉토리:

config.toml — Supabase CLI 설정
  - 프로젝트 ID, DB 포트, auth providers (Google/GitHub/Apple),
    edge_runtime, functions.*.verify_jwt 설정

migrations/ (PostgreSQL DDL, 시간순):
  - 20260409000001_initial_schema.sql
    12개 테이블: profiles, teams, team_members, meetings,
    meeting_memos, meeting_documents, transcripts, history,
    dictionary, memo_tags, daily_usage, subscriptions
    + 인덱스 + FK CASCADE + transcripts Realtime publication
  - 20260409000002_rls_policies.sql
    개인 전용(history/dictionary): user_id = auth.uid()
    팀 공유(meetings 등): 본인 OR team_members 조회 subquery
    daily_usage: 읽기만, 쓰기는 service_role RPC
  - 20260409000003_auth_triggers.sql
    handle_new_user — auth.users INSERT → profiles+subscriptions 자동 생성
    moddatetime — 8개 테이블 updated_at 자동 갱신
    increment_daily_usage — service_role 전용 쿼터 RPC
  - 20260409000004_storage_buckets.sql
    audio/exports/avatars 3개 버킷 + 경로 기반 접근 정책
    (파일 경로가 {user_id}/...로 시작해야 쓰기 허용)

functions/ (Deno/TypeScript Edge Functions):
  - _shared/cors.ts — CORS 헤더 + preflight 핸들러
  - _shared/auth.ts — requireUser (JWT 검증 + User 반환)
  - _shared/quota.ts — 티어별 쿼터 체크 + consume + service role client
  - stt-proxy/index.ts — Google Cloud STT 래퍼 스캐폴딩
    placeholder 응답, 실제 API 호출 코드는 주석으로 포함
  - llm-proxy/index.ts — Anthropic Messages API 래퍼 스캐폴딩
    티어별 허용 모델 정책 (free=Haiku, pro=Sonnet, team=Opus)

설계 문서:
  - docs/v2/phase-V2-2.md — 상세 설계 (스키마/RLS/Edge Functions/Realtime)
  - docs/v2/phase-V2-2-setup.md — 사용자 액션 가이드 (Supabase 계정/
    OAuth 등록/CLI/배포/검증)

apps/desktop typecheck 통과 (server/는 Deno 런타임이라 별도).
실제 Supabase 프로젝트 배포는 사용자가 phase-V2-2-setup.md 따라 수행.
2026-04-08 15:21:08 +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