d3ro-voice/apps/web/.next/cache/eslint/.cache_mo8rwz
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

1 line
No EOL
8.1 KiB
Text

[{"D:\\workspace\\voice\\apps\\web\\src\\app\\auth\\callback\\route.ts":"1","D:\\workspace\\voice\\apps\\web\\src\\app\\dashboard\\layout.tsx":"2","D:\\workspace\\voice\\apps\\web\\src\\app\\dashboard\\page.tsx":"3","D:\\workspace\\voice\\apps\\web\\src\\app\\layout.tsx":"4","D:\\workspace\\voice\\apps\\web\\src\\app\\login\\page.tsx":"5","D:\\workspace\\voice\\apps\\web\\src\\app\\meetings\\page.tsx":"6","D:\\workspace\\voice\\apps\\web\\src\\app\\meetings\\[id]\\page.tsx":"7","D:\\workspace\\voice\\apps\\web\\src\\app\\page.tsx":"8","D:\\workspace\\voice\\apps\\web\\src\\app\\record\\page.tsx":"9","D:\\workspace\\voice\\apps\\web\\src\\components\\layout\\sidebar.tsx":"10","D:\\workspace\\voice\\apps\\web\\src\\components\\providers\\auth-provider.tsx":"11","D:\\workspace\\voice\\apps\\web\\src\\components\\providers\\i18n-provider.tsx":"12","D:\\workspace\\voice\\apps\\web\\src\\components\\providers\\theme-provider.tsx":"13","D:\\workspace\\voice\\apps\\web\\src\\components\\record\\mic-recorder.tsx":"14","D:\\workspace\\voice\\apps\\web\\src\\lib\\supabase-browser.ts":"15","D:\\workspace\\voice\\apps\\web\\src\\lib\\supabase-server.ts":"16","D:\\workspace\\voice\\apps\\web\\src\\app\\billing\\page.tsx":"17","D:\\workspace\\voice\\apps\\web\\src\\app\\teams\\page.tsx":"18","D:\\workspace\\voice\\apps\\web\\src\\app\\teams\\[id]\\page.tsx":"19","D:\\workspace\\voice\\apps\\web\\src\\components\\billing\\checkout-button.tsx":"20","D:\\workspace\\voice\\apps\\web\\src\\components\\teams\\create-team-form.tsx":"21","D:\\workspace\\voice\\apps\\web\\src\\components\\teams\\invite-member-form.tsx":"22"},{"size":987,"mtime":1775669901472,"results":"23","hashOfConfig":"24"},{"size":893,"mtime":1775670351085,"results":"25","hashOfConfig":"24"},{"size":3410,"mtime":1775670351094,"results":"26","hashOfConfig":"24"},{"size":852,"mtime":1775670351106,"results":"27","hashOfConfig":"24"},{"size":3966,"mtime":1775670351108,"results":"28","hashOfConfig":"24"},{"size":3124,"mtime":1775670351121,"results":"29","hashOfConfig":"24"},{"size":5308,"mtime":1775670351133,"results":"30","hashOfConfig":"24"},{"size":599,"mtime":1775670351143,"results":"31","hashOfConfig":"24"},{"size":992,"mtime":1775670351144,"results":"32","hashOfConfig":"24"},{"size":3938,"mtime":1775719825058,"results":"33","hashOfConfig":"24"},{"size":1426,"mtime":1775670351147,"results":"34","hashOfConfig":"24"},{"size":881,"mtime":1775670351148,"results":"35","hashOfConfig":"24"},{"size":888,"mtime":1775670351148,"results":"36","hashOfConfig":"24"},{"size":9595,"mtime":1775670351150,"results":"37","hashOfConfig":"24"},{"size":954,"mtime":1775670481133,"results":"38","hashOfConfig":"24"},{"size":1269,"mtime":1775670499155,"results":"39","hashOfConfig":"24"},{"size":4926,"mtime":1775719873334,"results":"40","hashOfConfig":"24"},{"size":4111,"mtime":1775719738640,"results":"41","hashOfConfig":"24"},{"size":5306,"mtime":1775719785132,"results":"42","hashOfConfig":"24"},{"size":2349,"mtime":1775719894509,"results":"43","hashOfConfig":"24"},{"size":3039,"mtime":1775719761946,"results":"44","hashOfConfig":"24"},{"size":3037,"mtime":1775719801280,"results":"45","hashOfConfig":"24"},{"filePath":"46","messages":"47","suppressedMessages":"48","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"g57i01",{"filePath":"49","messages":"50","suppressedMessages":"51","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"52","messages":"53","suppressedMessages":"54","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"55","messages":"56","suppressedMessages":"57","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"58","messages":"59","suppressedMessages":"60","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"61","messages":"62","suppressedMessages":"63","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"64","messages":"65","suppressedMessages":"66","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"67","messages":"68","suppressedMessages":"69","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"70","messages":"71","suppressedMessages":"72","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"73","messages":"74","suppressedMessages":"75","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"76","messages":"77","suppressedMessages":"78","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"79","messages":"80","suppressedMessages":"81","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"82","messages":"83","suppressedMessages":"84","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"85","messages":"86","suppressedMessages":"87","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"88","messages":"89","suppressedMessages":"90","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"91","messages":"92","suppressedMessages":"93","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"94","messages":"95","suppressedMessages":"96","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"97","messages":"98","suppressedMessages":"99","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"100","messages":"101","suppressedMessages":"102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"103","messages":"104","suppressedMessages":"105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"106","messages":"107","suppressedMessages":"108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"109","messages":"110","suppressedMessages":"111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"D:\\workspace\\voice\\apps\\web\\src\\app\\auth\\callback\\route.ts",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\dashboard\\layout.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\dashboard\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\layout.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\login\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\meetings\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\meetings\\[id]\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\record\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\layout\\sidebar.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\providers\\auth-provider.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\providers\\i18n-provider.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\providers\\theme-provider.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\record\\mic-recorder.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\lib\\supabase-browser.ts",[],[],"D:\\workspace\\voice\\apps\\web\\src\\lib\\supabase-server.ts",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\billing\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\teams\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\app\\teams\\[id]\\page.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\billing\\checkout-button.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\teams\\create-team-form.tsx",[],[],"D:\\workspace\\voice\\apps\\web\\src\\components\\teams\\invite-member-form.tsx",[],[]]