d3ro-voice/apps/web/.next/static/chunks/184-5ad314c0e8c040f6.js
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
7.1 KiB
JavaScript

"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[184],{585:(e,t,r)=>{r.d(t,{A:()=>i,t:()=>l});var o=r(8020),a=r(3664);function l(e){return(0,a.Ay)("MuiDialogTitle",e)}let i=(0,o.A)("MuiDialogTitle",["root"])},1156:(e,t,r)=>{r.d(t,{A:()=>l});var o=r(8703),a=r(4568);let l=(0,o.A)((0,a.jsx)("path",{d:"M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4m-9-2V7H4v3H1v2h3v3h2v-3h3v-2zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4"}),"PersonAdd")},4090:(e,t,r)=>{r.d(t,{A:()=>m});var o=r(7620),a=r(2902),l=r(7138),i=r(7226),n=r(8613),p=r(5120),s=r(585),d=r(7331),c=r(4568);let u=(0,n.default)(i.A,{name:"MuiDialogTitle",slot:"Root"})({padding:"16px 24px",flex:"0 0 auto"}),m=o.forwardRef(function(e,t){let r=(0,p.b)({props:e,name:"MuiDialogTitle"}),{className:i,id:n,...m}=r,h=(e=>{let{classes:t}=e;return(0,l.A)({root:["root"]},s.t,t)})(r),{titleId:v=n}=o.useContext(d.A);return(0,c.jsx)(u,{component:"h2",className:(0,a.A)(h.root,i),ownerState:r,ref:t,variant:"h6",id:null!=n?n:v,...m})})},7331:(e,t,r)=>{r.d(t,{A:()=>o});let o=r(7620).createContext({})},9157:(e,t,r)=>{r.d(t,{A:()=>v});var o=r(7620),a=r(2902),l=r(7138),i=r(8613),n=r(9468),p=r(5120),s=r(8020),d=r(3664);function c(e){return(0,d.Ay)("MuiDialogContent",e)}(0,s.A)("MuiDialogContent",["root","dividers"]);var u=r(585),m=r(4568);let h=(0,i.default)("div",{name:"MuiDialogContent",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:r}=e;return[t.root,r.dividers&&t.dividers]}})((0,n.A)(e=>{let{theme:t}=e;return{flex:"1 1 auto",WebkitOverflowScrolling:"touch",overflowY:"auto",padding:"20px 24px",variants:[{props:e=>{let{ownerState:t}=e;return t.dividers},style:{padding:"16px 24px",borderTop:"1px solid ".concat((t.vars||t).palette.divider),borderBottom:"1px solid ".concat((t.vars||t).palette.divider)}},{props:e=>{let{ownerState:t}=e;return!t.dividers},style:{[".".concat(u.A.root," + &")]:{paddingTop:0}}}]}})),v=o.forwardRef(function(e,t){let r=(0,p.b)({props:e,name:"MuiDialogContent"}),{className:o,dividers:i=!1,...n}=r,s={...r,dividers:i},d=(e=>{let{classes:t,dividers:r}=e;return(0,l.A)({root:["root",r&&"dividers"]},c,t)})(s);return(0,m.jsx)(h,{className:(0,a.A)(d.root,o),ownerState:s,ref:t,...n})})},9404:(e,t,r)=>{r.d(t,{A:()=>D});var o=r(7620),a=r(2902),l=r(7138),i=r(2156),n=r(9407),p=r(1694),s=r(9688),d=r(5299),c=r(8020),u=r(3664);function m(e){return(0,u.Ay)("MuiDialog",e)}let h=(0,c.A)("MuiDialog",["root","backdrop","scrollPaper","scrollBody","container","paper","paperScrollPaper","paperScrollBody","paperWidthFalse","paperWidthXs","paperWidthSm","paperWidthMd","paperWidthLg","paperWidthXl","paperFullWidth","paperFullScreen"]);var v=r(7331),x=r(8235),A=r(8613),b=r(1774),f=r(9468),g=r(5120),y=r(7972),k=r(4568);let w=(0,A.default)(x.A,{name:"MuiDialog",slot:"Backdrop"})({zIndex:-1}),W=(0,A.default)(p.A,{name:"MuiDialog",slot:"Root"})({"@media print":{position:"absolute !important"}}),M=(0,A.default)("div",{name:"MuiDialog",slot:"Container",overridesResolver:(e,t)=>{let{ownerState:r}=e;return[t.container,t["scroll".concat((0,n.A)(r.scroll))]]}})({height:"100%","@media print":{height:"auto"},outline:0,variants:[{props:{scroll:"paper"},style:{display:"flex",justifyContent:"center",alignItems:"center"}},{props:{scroll:"body"},style:{overflowY:"auto",overflowX:"hidden",textAlign:"center","&::after":{content:'""',display:"inline-block",verticalAlign:"middle",height:"100%",width:"0"}}}]}),S=(0,A.default)(d.A,{name:"MuiDialog",slot:"Paper",overridesResolver:(e,t)=>{let{ownerState:r}=e;return[t.paper,t["scrollPaper".concat((0,n.A)(r.scroll))],t["paperWidth".concat((0,n.A)(String(r.maxWidth)))],r.fullWidth&&t.paperFullWidth,r.fullScreen&&t.paperFullScreen]}})((0,f.A)(e=>{let{theme:t}=e;return{margin:32,position:"relative",overflowY:"auto","@media print":{overflowY:"visible",boxShadow:"none"},variants:[{props:{scroll:"paper"},style:{display:"flex",flexDirection:"column",maxHeight:"calc(100% - 64px)"}},{props:{scroll:"body"},style:{display:"inline-block",verticalAlign:"middle",textAlign:"initial"}},{props:e=>{let{ownerState:t}=e;return!t.maxWidth},style:{maxWidth:"calc(100% - 64px)"}},{props:{maxWidth:"xs"},style:{maxWidth:"px"===t.breakpoints.unit?Math.max(t.breakpoints.values.xs,444):"max(".concat(t.breakpoints.values.xs).concat(t.breakpoints.unit,", 444px)"),["&.".concat(h.paperScrollBody)]:{[t.breakpoints.down(Math.max(t.breakpoints.values.xs,444)+64)]:{maxWidth:"calc(100% - 64px)"}}}},...Object.keys(t.breakpoints.values).filter(e=>"xs"!==e).map(e=>({props:{maxWidth:e},style:{maxWidth:"".concat(t.breakpoints.values[e]).concat(t.breakpoints.unit),["&.".concat(h.paperScrollBody)]:{[t.breakpoints.down(t.breakpoints.values[e]+64)]:{maxWidth:"calc(100% - 64px)"}}}})),{props:e=>{let{ownerState:t}=e;return t.fullWidth},style:{width:"calc(100% - 64px)"}},{props:e=>{let{ownerState:t}=e;return t.fullScreen},style:{margin:0,width:"100%",maxWidth:"100%",height:"100%",maxHeight:"none",borderRadius:0,["&.".concat(h.paperScrollBody)]:{margin:0,maxWidth:"100%"}}}]}})),D=o.forwardRef(function(e,t){let r=(0,g.b)({props:e,name:"MuiDialog"}),p=(0,b.default)(),c={enter:p.transitions.duration.enteringScreen,exit:p.transitions.duration.leavingScreen},{"aria-describedby":u,"aria-labelledby":h,"aria-modal":x=!0,BackdropComponent:A,BackdropProps:f,children:D,className:C,disableEscapeKeyDown:T=!1,fullScreen:P=!1,fullWidth:R=!1,maxWidth:j="sm",onClick:F,onClose:N,open:B,PaperComponent:H=d.A,PaperProps:Y={},scroll:_="paper",slots:E={},slotProps:I={},TransitionComponent:X=s.A,transitionDuration:z=c,TransitionProps:O,...K}=r,L={...r,disableEscapeKeyDown:T,fullScreen:P,fullWidth:R,maxWidth:j,scroll:_},V=(e=>{let{classes:t,scroll:r,maxWidth:o,fullWidth:a,fullScreen:i}=e,p={root:["root"],backdrop:["backdrop"],container:["container","scroll".concat((0,n.A)(r))],paper:["paper","paperScroll".concat((0,n.A)(r)),"paperWidth".concat((0,n.A)(String(o))),a&&"paperFullWidth",i&&"paperFullScreen"]};return(0,l.A)(p,m,t)})(L),q=o.useRef(),G=(0,i.A)(h),J=o.useMemo(()=>({titleId:G}),[G]),Q={slots:{transition:X,...E},slotProps:{transition:O,paper:Y,backdrop:f,...I}},[U,Z]=(0,y.A)("root",{elementType:W,shouldForwardComponentProp:!0,externalForwardedProps:Q,ownerState:L,className:(0,a.A)(V.root,C),ref:t}),[$,ee]=(0,y.A)("backdrop",{elementType:w,shouldForwardComponentProp:!0,externalForwardedProps:Q,ownerState:L,className:V.backdrop}),[et,er]=(0,y.A)("paper",{elementType:S,shouldForwardComponentProp:!0,externalForwardedProps:Q,ownerState:L,className:(0,a.A)(V.paper,Y.className)}),[eo,ea]=(0,y.A)("container",{elementType:M,externalForwardedProps:Q,ownerState:L,className:V.container}),[el,ei]=(0,y.A)("transition",{elementType:s.A,externalForwardedProps:Q,ownerState:L,additionalProps:{appear:!0,in:B,timeout:z,role:"presentation"}});return(0,k.jsx)(U,{closeAfterTransition:!0,slots:{backdrop:$},slotProps:{backdrop:{transitionDuration:z,as:A,...ee}},disableEscapeKeyDown:T,onClose:N,open:B,onClick:e=>{F&&F(e),q.current&&(q.current=null,N&&N(e,"backdropClick"))},...Z,...K,children:(0,k.jsx)(el,{...ei,children:(0,k.jsx)(eo,{onMouseDown:e=>{q.current=e.target===e.currentTarget},...ea,children:(0,k.jsx)(et,{as:H,elevation:24,role:"dialog","aria-describedby":u,"aria-labelledby":G,"aria-modal":x,...er,children:(0,k.jsx)(v.A.Provider,{value:J,children:D})})})})})})}}]);