Skip to content

andevv/SpaceWalker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

146 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SpaceWalker

스페이스 멤버들과 일일 미션 사진을 공유하는 SNS형 iOS 앱입니다. Apple 로그인으로 시작해 Space를 선택하고, 캘린더·피드·지도·마이페이지 탭을 중심으로 미션 사진을 업로드/조회할 수 있습니다. 실서비스용 API 연동과 토큰 리프레시, 이미지 메타데이터 저장, 프리사인드 업로드 흐름을 구현했습니다.

  • 주요 역할: iOS 클라이언트 개발 (UIKit + Rx), 백엔드 연동, UX 설계
  • 타깃: iOS 16+, Xcode 26+ (CI 배포 기준)
Login Calendar Feed Feed Detail
Map Calendar Detail Calendar Detail - 2 My Page
My Page - Edit Nickname My Page - Privacy Policy My Page - Terms My Page - OSS License

프로젝트 구성 요약

  • 레이어 구조: App(엔트리/세션 라우팅) → Features(화면/상호작용) → Core(네트워크/레포지토리/유틸/모델) → Resources(정적 리소스/환경 파일)
  • 아키텍처 패턴: UIKit + MVVM(Rx) + Repository
  • 인증/세션 흐름: Apple 로그인 → 토큰 저장 → SceneDelegate 루트 분기(SignUp/SpaceSelect/MainTabBar)
  • 네트워크 전략: NetworkManager 중심 단일 요청 계층, 401 응답 시 토큰 리프레시 후 재시도
  • 미디어 업로드 전략: 프리사인드 URL 기반 업로드 + Realm 메타데이터 캐시로 복구 여지 확보

CI/CD (TestFlight Auto Deploy)

  • 트리거: main 브랜치 push 시 GitHub Actions 실행
  • 배포 목표: Fastlane으로 iOS 아카이브/서명/TestFlight 업로드 자동화
  • 러너 환경: macos-latest, Ruby 3.2, Xcode 26.0(실행 시점 26.0.1), TZ=Asia/Seoul
  • Fastlane lane: ios beta
    • app_store_connect_api_key 인증
    • KST 기준 타임스탬프 빌드번호 증가
    • CI 전용 keychain 생성/언락/설정
    • match 서명 동기화(읽기 전용)
    • build_app 아카이브
    • upload_to_testflight 업로드
  • 시크릿/보안 처리:
    • GitHub Secrets 사용: ASC_*, MATCH_*, KEYCHAIN_PASSWORD, BASE_URL, GOOGLE_SERVICE_INFO_PLIST_BASE64
    • CI 런타임 파일 생성: Secrets.swift, GoogleService-Info.plist (둘 다 git ignore 대상)

CI/CD 파이프라인 다이어그램

flowchart LR
    A["Code Push (main)"] --> B["GitHub Actions Trigger"]
    B --> C["Build Environment Setup"]
    C --> D["Load GitHub Secrets"]
    D --> E["Generate Ignored Runtime Files"]
    E --> F["Build & Signing (Fastlane)"]
    F --> G["Upload to TestFlight"]
    G --> H["Release Verification"]
Loading

핵심 기능

  • Apple 로그인: AuthenticationServices를 이용해 애플 계정으로 로그인. 토큰 저장 후 자동 세션 유지.
  • Space 선택/참여: 서버에서 내려주는 Space 리스트(최대 3개 선택)를 Rx 바인딩으로 처리. 유효하지 않은 ID 에러 핸들링 포함.
  • 캘린더 미션: FSCalendar 기반 월간 뷰, 미션 제목/필터 칩 표시. 사진 촬영 시 EXIF 메타데이터(촬영 시각, 위치, 해상도, 기기명, MIME 타입)를 추출·저장(Realm) 후 프리사인드 URL 업로드 → 미션 제출.
  • 피드: Masonry 스타일 워터폴 레이아웃, Space별 필터 칩, Kingfisher 이미지 캐싱, 페이지네이션, 좋아요 토글 중복요청 방지.
  • 지도: 위치 기반 사진/Space 조회(뷰 골격 준비) 및 위치 권한 처리.
  • 마이페이지: 프로필 이미지 업로드(프리사인드), 닉네임 수정, 약관/정책/오픈소스 라이선스 링크, 회원 탈퇴.
  • 위치 데이터 이전: MyPage에서 로컬 위치 메타데이터 내보내기/가져오기를 지원. 기기 교체 시 동일 사용자 기준 데이터 이전 가능.
  • 안정성: 401 응답 시 자동 토큰 리프레시 및 재요청. Rx 기반 dispose 관리, 전역 로깅(Apple Logger + 커스텀 헬퍼).

기술 스택

  • UI: UIKit, SnapKit, FSCalendar, Photos/AVFoundation/MapKit, SafariServices
  • Reactive: RxSwift/RxCocoa
  • Networking: Alamofire, 커스텀 NetworkManager(토큰 리프레시 + 더미 응답 지원)
  • Auth: Sign in with Apple
  • 이미지/캐시: Kingfisher, 프리사인드 URL 업로드
  • 로컬 저장: Realm (사진 메타데이터 캐시)
  • 기타: OSLog/Logger, CryptoKit(Nonce)

아키텍처

  • 계층 분리: App(엔트리/루트 전환) → Features(화면) → Core(네트워크·레포지토리·유틸·모델) → Resources.
  • 패턴: UIKit 기반 MVVM(Rx) + Repository. ViewController는 UI/바인딩, ViewModel은 입력/출력 스트림과 상태 관리, Repository가 네트워크/로컬 접근을 캡슐화.
  • 네트워크: 단일 NetworkManager가 Alamofire 요청을 감싸고, 401 시 토큰 리프레시 후 재시도. 더미 API 모드(requestDummy)를 같은 인터페이스로 제공해 개발/테스트를 단순화.
  • 세션/라우팅: SceneDelegate에서 토큰 유무와 /api/v1/space/my-space 결과에 따라 루트 VC를 전환(SignUpSpaceSelectMainTabBar). NetworkManager.onRequireReauthentication 콜백으로 재인증 플로우를 일원화.
  • 데이터 보관: Realm으로 촬영 메타데이터를 로컬에 저장해 업로드 실패 시 복구 여지 확보. Kingfisher로 원격 이미지 캐시.
  • 로컬 데이터 연속성: Realm 저장 경로를 iOS 백업 대상 경로로 운용하고, 앱 업데이트 시 기존 경로 DB를 신규 경로로 1회 이전(migration)하도록 구성.
  • 로깅: OSLog Logger + 헬퍼(LogAuth, LogNetwork, LogUI, LogGeneral)로 카테고리 기반 로그 관리.

위치 메타데이터 이전(Export/Import)

  • 배경: 위치정보를 서버에 저장하지 않고 온디바이스에서 처리해 개인정보 처리 범위를 최소화.
  • 백업/마이그레이션: Realm 파일을 iOS 백업 대상 경로에 배치해 Quick Start/백업 복원 시 데이터 연속성을 확보.
  • 사용자 이전 기능: MyPage에서 .swlocpack 파일로 내보내기/가져오기 지원.
  • 무결성 검증: 파일에 SHA-256 checksum을 포함하고 import 시 재계산/비교.
  • 소유자 검증: pack의 ownerUserId와 현재 로그인 사용자 ID를 비교해 타계정 파일 import 차단.
  • 호환성 정책: ownerUserId 또는 checksum이 없는 구버전 파일은 import를 거부.

폴더 구조

  • App/: AppDelegate, SceneDelegate – 앱 부팅, 루트 전환, 재인증 콜백.
  • Core/: 네트워크/디코더/유틸/로그/세션/Realm 모델, Repositories.
  • Features/
    • SignUp/: Apple 로그인, 약관/개인정보 링크.
    • SpaceSelect/: Space 선택, Rx MVVM 패턴(SpaceSelectViewModel).
    • Calendar/ CalendarDetail/: 미션 달력, 촬영·업로드·제출 흐름.
    • Feed/ FeedDetail/: 워터폴 피드, Space 필터, 좋아요.
    • Map/: 위치 기반 뷰.
    • MyPage/: 프로필/닉네임/정책/탈퇴.
    • MainTabBarController: 캘린더·피드·지도·마이페이지 탭 구성.
  • Resources/: 에셋, Secrets.swift(API baseURL), GoogleService-Info.plist.
  • Support/: Info.plist, 프로젝트 설정 파일.

주요 플로우 요약

  • 앱 진입 (SceneDelegate): 액세스 토큰 확인 → 없으면 SignUpViewController, 있으면 /api/v1/space/my-space 조회 후 Space가 없으면 SpaceSelectViewController, 있으면 메인 탭으로 진입.
  • 네트워크 공통 (NetworkManager): 모든 요청에 대해 401 발생 시 refresh → 성공 시 재시도, 실패 시 onRequireReauthentication 콜백으로 로그인 화면 전환.
  • 미션 업로드 (CalendarViewController + SpaceRepository): 촬영/앨범 → 메타데이터 추출/Realm 저장 → /upload 프리사인드 URL 획득 → S3 업로드 → /submit으로 미션 제출 및 공개 여부 설정.
  • 프로필 변경 (MyPageViewController): 프리사인드 URL 발급 → 이미지 업로드 → 프로필 업데이트 → Kingfisher 캐시 갱신.

환경 설정

  • API 엔드포인트는 Resources/Secrets.swiftbaseURL에서 관리. 환경에 맞게 수정. (Secrets.baseURL = "https://...")
  • Firebase: GoogleService-Info.plist를 사용. CI에서는 GOOGLE_SERVICE_INFO_PLIST_BASE64 시크릿으로 런타임 생성.
  • 백엔드 준비 전에는 NetworkManager.requestDummy/requestRawDataDummy를 활용해 더미 응답을 사용할 수 있도록 구현됨.

포인트

  • Rx 기반 플로우로 로그인→Space 선택→탭 전환까지 비동기 체인을 단순화.
  • 토큰 리프레시와 재시도, 재인증 콜백을 NetworkManagerSceneDelegate에서 일원화해 사용자 경험을 매끄럽게 유지.
  • 워터폴 피드, 캘린더 미션, 프로필 업로드 등 다양한 미디어/네트워크/스토리지 시나리오를 직접 설계.
  • 로컬 Realm 캐시로 촬영 메타데이터 보존 → 업로드 실패 시 복구 여지 확보.
  • OSLog 기반 카테고리 로그(Auth, Network, UI, General)로 문제 추적성 향상.

향후 개선 아이디어

  • 단위/통합 테스트 추가 (네트워크 목킹, ViewModel 단위 테스트).
  • 지도 탭에서 위치 기반 미션/피드 데이터 시각화 고도화.
  • 오프라인 업로드 재시도 큐 및 백그라운드 전송 지원.
  • 접근성(A11y) 라벨, 동적 폰트 대응 강화.

About

SpaceWalker: 일일 미션 사진첩

Resources

Stars

Watchers

Forks

Contributors