프로필 아이디(@handle) 저장·검색 + 친구 프로필 사진 (2026-08-23)
오너 요청
"handle이 왜 저장이 안되지? 저장되게 해주고, handle로 검색할 수 있게 해줘. 친구 프로필 사진도 보이게 해줘." (전날 피드 친구 검색·팔로우 v1이 닉네임 검색·사진 미공급으로 랜딩한 데 대한 후속)
원인
- 온보딩 화면(
UiOnboarding)은draft.handle을 돌려주지만, 컨테이너(appController.completeMobileOnboarding→onboardingCommands→complete_onboardingpayload)가 그 키를 어디에도 싣지 않았다. DB에도profiles.handle컬럼이 없었다(데이터 모델 문서가 "v1은 유일 핸들 없음"으로 명시). - 친구 사진:
profile-images버킷 정책이 본인 폴더만 읽게 돼 있어 다른 사용자의 아바타 서명 URL을 만들 수 없었고, 검색/목록 RPC도 아바타 컬럼을 내지 않았다.
변경 — 마이그레이션 20260821470000_profile_handle_and_friend_avatar.sql
| 층 | 내용 |
|---|---|
| DB | profiles.handle text(^[a-z0-9_]{3,20}$ 체크, 유일 인덱스 profiles_handle_key, null 허용) · normalize_profile_handle_v1(선두 @·공백 제거·소문자, 위반 22023) · set_profile_handle_v1(p_handle)(본인 설정/변경, 멱등, 충돌 23505) · complete_onboarding 래퍼 재발행(payload.handle → v4 위임 전 같은 트랜잭션에서 확정, 충돌이면 완료 전체 롤백) · search_user_profiles_v1/list_following_v1 재발행(drop+create: handle·avatar_path·avatar_url 컬럼, 아이디 부분일치 매칭·정렬 아이디 정확→접두→닉네임) · storage 정책 profile_image_objects_read_authenticated(profile-images 읽기 = 로그인 사용자 전원, 쓰기는 기존 본인 폴더만) |
pgTAP profile_handle_v1.test.sql | 20 assert — 정규화·형식, 설정/멱등/충돌, 아이디 검색·avatar 컬럼(http만, data: 제외), 목록 컬럼, 온보딩 payload.handle 저장·충돌 롤백, storage 읽기/쓰기 정책 |
| 클라이언트 | onboardingCommands(draft.handle → write.handle 정규화) · appController.completeMobileOnboarding(handle 전달) · repository(selectCurrentProfile/uploadProfilePhoto select에 handle, payload.handle, setProfileHandle, signProfileImagePaths, 23505/22023 → LG_PROFILE_HANDLE_TAKEN/INVALID) · userErrorPolicy 문구 2건 · socialDomain.withFriendPhotos(avatar_url 우선, 아니면 경로 일괄 서명 7일) + setProfileHandle · profileController.saveProfileHandle(토스트·remoteProfile 반영) → appController/mobileApp/desktopApp 배선 · RPC 타입맵 |
| UI(최소) | ProfileScreen(모바일): 프로필 카드 아래 "아이디" 카드 — 무상태 <form>(기존 .row/.input/.btn 어휘) · DesktopProfileScreen: "아이디" 카드(dk-bm-* 어휘) · FeedScreen: @{handle || id} UUID 폴백 제거(handle 없으면 @ 줄 미표시) · followingStore: handle·photo 매핑 |
| 행동 테스트 | tests/react/profileHandle.test.mjs 7건(커맨드·리포지토리 번역·서명·문구·내 정보 화면 렌더), followingStore.test.mjs 갱신 |
| 문서 | onboarding-data-model.md(+ko) 아이디 절, onboarding-props.md, profile-screen-props.md, feed-props.md, rpc-catalog.md, PRD |
결정·메모
- 온보딩의
suggestedHandle(소셜 닉네임 기반 자동 제안)·실시간 중복 검증 UI는 미구현(요청 시). - 기존 사용자는 handle이 null이므로 내 정보 탭에서 한 번 설정해야 아이디로 검색된다. 닉네임 검색은 그대로 동작한다.
- 아이디 카드는 Design 시안 없이 기존 어휘로 최소 구성 — 시각 다듬기는 Claude Design 후속.
검증
- 로컬 샌드박스
db reset+supabase test db46파일·662 assert PASS. npm run check·check:unused·buildPASS.- 브라우저 스모크(로컬 스택): 내 정보 탭에서 아이디 저장 → 피드 친구 추가에서 친구 아이디로 검색 → 행에
@handle·프로필 사진(소셜 http / storage 서명) 표시 → 팔로우.