UX-05
Invite v0 — 실제 이메일 발송 없음, 운영자 수동 magic link
Medium
docs/b2b/hierarchy.md:58-61: "v0 email 발송 생략, owner가 magic link를 수동 콘솔에서 트리거". 회원 관점에서 "초대받았다"는 신호 0건. 시나리오 자체가 "owner가 카톡으로 알려줌" 상태. 운영 갭이 대시보드에 미반영.
발견: UX 에이전트
UX-06
동시성 — sessionManager / liveWorkoutContext가 single-instance, 다중 회원 병렬 시 cross-wire 위험
Medium
앱 전역 single-instance 프로바이더. 트레이너가 회원 A의 세션 시작 → 회원 B로 이동하면 컨텍스트 덮어씀. PT샵에서 트레이너 1명이 N대 기기 동시 운영 가능성을 시나리오가 가정 안 함. 명시적으로 "1대1 가정"이라 표시하거나 family provider로 전환.
발견: UX 에이전트
UX-07
트레이너 다중 샵 — RLS는 OK, UI는 single-shop 가정 (가장 최근 1개)
Medium
currentRoleProvider가 joinedAt desc로 1개만 반환. 두 샵에 trainer로 초대받은 사람은 첫 샵을 못 봄. 샵 선택 UI 없음.
발견: UX 에이전트
UX-08
OwnerDashboard 부재 — 트레이너별 활동/매출 통계 없음
Medium
hierarchy.md:127-135에 OwnerDashboard 미정의. ShopHomeScreen은 멤버 리스트만. 트레이너별 일/주 단위 세션 수, 회원 진척도 같은 KPI가 없어 오너가 운영 판단 불가.
발견: UX 에이전트
UX-09
트레이너 이탈 / 오너 이양 흐름 0건
Medium
memberships_owner_delete RLS 정책만 있고 UI에 trainer 제거 버튼 없음. centers.owner_id가 단일 컬럼 + one_owner_per_center UNIQUE INDEX이지만 이양 RPC/UI 부재 → 오너 사망/탈퇴 시 샵 잠김.
발견: UX 에이전트
DB-02
centers 테이블이 빈약 — 주소/영업시간/활성 여부 컬럼 없음
Medium
현재 id/name/owner_id/created_at만. 폐업/일시 휴업 표현 불가, 주소 검색 불가. is_shop_staff가 폐업 샵의 staff에게도 영원히 true.
위치: 20260413114331_*.sql:202-207
발견: DB 에이전트
DB-03
center_memberships에 left_at / soft-delete 없음 — trainer 퇴사 시 과거 supervised의 RLS staff path 즉시 끊김
Medium
membership row를 DELETE하면 is_shop_staff false → trainer가 작성한 과거 supervised 세션을 본인은 더 이상 못 보고, 새 staff도 read 불가. left_at 컬럼 + tombstone 정책 필요.
위치: 20260419004009_b2b_shop_hierarchy.sql:31-38
발견: DB 에이전트
DB-04
workout_sessions에 status / canceled 컬럼 없음 + 트레이너는 자기 supervised 세션 삭제 불가
Medium
"수업 중단/취소" 표현 수단 없음. sessions_delete는 user_id = auth.uid()만 허용 → 트레이너가 잘못 만든 세션 정리 불가.
위치: 20260419004009_b2b_shop_hierarchy.sql:151-152
발견: DB 에이전트
DOM-07
SetCutoffTrigger 자동 cutoff 미구현 — VL10/20/30/40, targetReached, timeout 모두 항상 user로
Medium
SetExecutor.completeSet는 cutoffTrigger: SetCutoffTrigger.user 박힘. VBT 자동 종료 로직(velocity loss 임계 도달, 목표 reps 달성)이 도메인 enum에는 있고 호출부엔 없음.
발견: 아키텍처 에이전트
SEC-03
B2C self 세션의 center_id가 항상 NULL인지 클라이언트 측 강제 없음 — 향후 노출 가능
Medium
현재 b2c가 center_id를 안 보내서 안전하지만, SupabaseWorkoutRepository.createSession은 인자대로 INSERT. 누가 잘못 호출하면 staff에 노출. 서버 트리거로 self 세션의 center_id 강제 NULL 필요.
발견: 보안 에이전트
SEC-04
invite_member rate limit 없음 + listUsers O(N) scan — DoS / enumeration 가능
Medium
listUsers({ perPage: 1000 })가 사용자 수 증가 시 수초 latency. 같은 user를 N개 샵이 동시에 owner/trainer/member로 등록 가능 — 의도인지 확인 필요.
위치: supabase/functions/invite_member/index.ts:111
발견: 보안 에이전트