Skip to content

✨ [Feat] 명함 데이터 계층 — 명함첩 저장 · 카운트 조합 · QR · DI 배선 (#1195) - #1199

Merged
GthingkingG merged 5 commits into
developfrom
feature/1195
Aug 20, 2026
Merged

✨ [Feat] 명함 데이터 계층 — 명함첩 저장 · 카운트 조합 · QR · DI 배선 (#1195)#1199
GthingkingG merged 5 commits into
developfrom
feature/1195

Conversation

@GthingkingG

Copy link
Copy Markdown
Contributor

✨ PR 유형

✨ Feature — #1194 에서 정의한 Repository 인터페이스의 실제 구현과 앱 배선입니다.
명함첩 SwiftData 저장, 내 명함의 정본 프로필 위임, 마이페이지 카운트 조합, QR 생성,
DI 등록까지. 스택 4개 PR 중 3번째입니다.

⚠️ 선행 PR(#1193·#1194) 머지 전에는 diff 에 그 층 커밋이 함께 보입니다.

Closes #1195

🛠️ 작업내용

명함첩 저장소 (SwiftData)

  • CloudKit 동기화 호환 스키마(전 필드 옵셔널/기본값) — 이후 기기 간 동기화를 열어 둠
  • memberId 키 upsert — 같은 상대와 재교환하면 새 행이 아니라 기존 행 갱신
  • 검색은 이름·닉네임·파트·학교 매칭, CloudKit 중복 행은 결과에서 dedup

내 명함 저장소

  • 정본 프로필 파이프라인(/member/meProfile)에 위임 — 명함 전용 서버 API 는
    없습니다
    (서버·Android 레포 전수 조사 결과 신규 API 0개로 진행, Profile+MyCard 매핑)

카운트 저장소 · QR

  • 스터디·스크랩(서버) + 명함첩(로컬) 조합. 스크랩은 서버 totalElements 문자열 그대로 전달
  • CoreImage QR 생성기 — 생성·역스캔 왕복 테스트

DI 배선

  • BusinessCardUseCaseProvider + DIContainer+BusinessCard 등록,
    앱 실행 시 명함 레코드 포함 SwiftData 컨테이너 초기화

AC 체크

  • 인메모리 컨테이너에서 저장·검색·삭제·count가 동작하고, 재교환 시 기존 행이 갱신된다
    테스트 저장 후 전체 조회하면 같은 명함이 나온다 · 같은 memberId로 다시 저장하면 중복 없이 최신 명함으로 갱신된다 · 삭제하면 목록과 카운트에서 빠진다
  • 명함첩 검색이 이름·닉네임·파트·학교로 매칭되고 CloudKit 중복이 중복 노출되지 않는다
    테스트 이름·닉네임·파트·학교로 검색된다 (MP 받은명함_검색) · 공백 검색어는 전체 목록
  • fetchMyCard(forceRefresh:)가 정본 프로필 저장소에 인자를 그대로 위임한다
    테스트 forceRefresh를 정본 저장소에 그대로 전달하고 매핑 결과를 돌려준다
  • Router 계약 테스트로 스터디·스크랩 엔드포인트의 path·method·쿼리가 고정된다
    테스트 내 스터디 목록은 GET /api/v1/study-groups/managed · 스크랩 목록은 GET /api/v1/posts/scrapped — size 1로 totalElements만 취한다
  • 스크랩 카운트가 서버 totalElements 문자열을 변환 없이 전달한다 (절대 규칙 💄 [Design] 디자인 시스템 기반 토큰 및 스타일 구현 #2)
    테스트 APIResponse 래핑 응답의 totalElements를 String 그대로 통과시킨다
  • 생성한 QR을 역스캔하면 원본 페이로드가 그대로 복원된다
    테스트 생성한 QR을 역스캔하면 원본 페이로드가 나온다 · 빈 페이로드는 에러를 던진다
  • 앱 실행 시 SwiftData 컨테이너가 정상 초기화되고 DI resolve가 성공한다
    DIContainer+BusinessCard 배선 + 시뮬레이터 스모크로 확인
  • make test SCHEME=BusinessCardData 통과

📋 추후 진행 상황

📌 리뷰 포인트

  • 명함첩 upsert 키 전략 — memberId 우선, cardID 보조. QR 재스캔·재교환·CloudKit 중복이
    전부 이 두 키로 한 장에 수렴하는 구조가 맞는지
  • Response DTO custom init(from:) 규약decodeIntFlexibleIfPresent 사용,
    서버가 hasNext 를 문자열로 줘도 흡수 (서버가 hasNext를 문자열로 줘도 흡수한다)
  • 챌린저 기록 없는 응답의 폴백 — 기수 0·admin 으로도 명함이 만들어지는데
    (챌린저 기록이 없으면 기수 0·admin 폴백으로도 명함이 만들어진다), 서버 마스킹 정책이
    바뀌면 조용히 잘못된 명함이 저장될 수 있어 계약 테스트로 고정했습니다

✅ Checklist

PR이 다음 요구 사항을 충족하는지 확인해주세요!!!

@GthingkingG
GthingkingG requested a review from JEONG-J August 20, 2026 10:36
@GthingkingG GthingkingG self-assigned this Aug 20, 2026
@GthingkingG GthingkingG added the ✨ Feature 새로운 기능을 추가합니다. label Aug 20, 2026
- ReceivedCardRecord: 전 필드 기본값·unique 금지 (CloudKit 제약)
- memberId 기준 수동 upsert — 재교환 시 최신 명함으로 갱신
- 이름·닉네임·파트·학교 검색, 인메모리 컨테이너 테스트
- 빈 스캐폴드 BusinessCardData.swift 제거, Data 테스트 타겟 활성화
- Profile→MyCard 파생 규칙을 MyPage 정본 매핑과 일치(최신 기수 기록 우선·admin 폴백)
- 캐시·forceRefresh가 그대로 전파돼 명함 편집 즉시 갱신(MP-F06) 성립
- String intValue/nonEmpty 헬퍼는 파일 로컬 복제 — UMCFoundation에 없음(크로스 피처 금지)
- BusinessCardRouter: 카운트 전용 엔드포인트 복제 + 계약 테스트
- 얇은 카운트 DTO 2종 custom Codable (totalElements / 커서 항목 수)
- 스크랩 카운트는 서버 totalElements를 String 그대로 통과 (서버 정수 String 통일)
- hasNext는 decodeBoolFlexibleIfPresent로 문자열 Bool 흡수 (Activity 선례)
- APIResponse 래핑·raw 양쪽 흡수, 테스트 seam으로 baseURL fatalError 회피
- CIQRCodeGenerator 보정 M·정수 배율 12 — 실기기 스파이크 검증 파라미터
- 빈 페이로드·렌더 실패를 전용 에러로 구분
- CIDetector 역스캔 왕복 테스트로 페이로드 보존 검증
- UseCase 7종을 한 번에 주입하는 Presentation 진입점 (MyPage Provider 패턴)
- ReceivedCardRecord를 SwiftData Schema(CloudKit)에 합류
- registerBusinessCardDependencies: Repository 4종+Transport+Provider 등록
- transport는 이슈 #1196 전까지 Mock — DI 캐싱이라 실기기 구현은 세션 상태 리셋 필요
- 빈 스캐폴드 BusinessCardPresentation.swift 제거
@GthingkingG
GthingkingG merged commit f89a348 into develop Aug 20, 2026
2 checks passed
@JEONG-J
JEONG-J deleted the feature/1195 branch August 24, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능을 추가합니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Feature: 명함 데이터 계층 — 명함첩 저장 · 카운트 조합 · QR · DI 배선

1 participant