Skip to content

Latest commit

 

History

History
407 lines (319 loc) · 15.2 KB

File metadata and controls

407 lines (319 loc) · 15.2 KB

Picke iOS

가치관 충돌에서 시작하는 1:1 철학 배틀 플랫폼, Picke

Platform Language iOS Xcode TCA Tuist Fastlane

🎯 Features | 🏗 Architecture | 🚀 Quick Start | 🔐 OAuth Flow


📖 프로젝트 소개

Picke 는 일상의 가치관 차이를 1:1 토론으로 풀어내는 모바일 토론·투표 플랫폼입니다. "오늘의 배틀" 주제에 대한 사전·사후 투표, 실시간 1:1 채팅 토론, 그리고 리캡 카드까지 한 흐름으로 이어집니다.

💡 왜 만들었나? SNS 의 단방향 의견 표출 대신, 짧고 명확한 1:1 토론을 통해 "내가 왜 그렇게 생각하는지" 를 정리하고 다른 가치관을 마주하는 경험을 제공합니다.

🛠 Setup

AI 도구 연동

프로젝트 규칙은 AGENTS.md / CLAUDE.md 에 정의되어 있습니다.

ln -s AGENTS.md CLAUDE.md

✨ 주요 기능

🔐 소셜 로그인 (server-mediated OAuth)

  • Google / Kakao: WKWebView 기반 authorize → code 가로채기 → 백엔드 토큰 교환
  • Apple Sign-In: ASAuthorizationAppleIDProvider 네이티브 통합
  • 자동 토큰 갱신: AccessTokenCredential JWT exp 디코딩 + 만료 5분 전 자동 refresh
  • 401 자동 처리: AuthInterceptor 가 401 감지 → refresh 시도 → 실패 시 자동 로그아웃 알림 발송

🥊 오늘의 배틀

  • 사전 투표 → 1:1 채팅 토론 → 사후 투표 의 한 흐름
  • 재투표 로 가치관이 바뀌었는지 추적
  • 리캡 카드 자동 생성 + 공유

💬 토론 / 댓글

  • 채팅방형 1:1 토론
  • 콘텐츠별 댓글·대댓글
  • 신고·차단

🧭 탐색 / 홈

  • 큐레이팅된 홈 피드
  • 카테고리·태그 탐색
  • 토픽 검색

👤 마이페이지

  • 내 콘텐츠 활동 / 토론 기록
  • 나의 철학자 유형
  • 포인트 내역 / 알림 / 설정

🏗 프로젝트 아키텍처

🎯 Clean Architecture × Tuist 멀티 모듈

Picke-iOS/
├── 📱 Projects/
│   ├── App/                       # 메인 애플리케이션 타겟
│   │   ├── Sources/
│   │   │   ├── Application/       # AppDelegate, SceneDelegate
│   │   │   ├── Di/                # WeaveDI 등록 (DiRegister, AppPresentationContextProvider)
│   │   │   ├── Reducer/           # TCA Root AppReducer
│   │   │   └── View/              # Root Views
│   │   └── Derived/               # Tuist 생성 plist
│   │
│   ├── Presentation/              # 🎨 UI Layer
│   │   ├── Auth/                  # 로그인 / 코디네이터 / Toast
│   │   ├── Home/                  # 홈 피드 / 큐레이팅 / 스켈레톤
│   │   ├── MainTab/               # 탭 라우팅 / GNB
│   │   ├── Splash/                # 스플래시
│   │   └── Presentation/          # 공통 프레젠테이션 유틸
│   │
│   ├── Domain/                    # 🔥 Business Logic Layer
│   │   ├── Entity/                # Auth / Home / OAuth / Error 도메인 엔티티
│   │   ├── DomainInterface/       # Auth / Home / OAuth Repository + Manager 인터페이스
│   │   └── UseCase/               # AuthUseCaseImpl, UnifiedOAuthUseCase, Provider/{Apple,Google,Kakao}
│   │
│   ├── Data/                      # 📡 Data Layer
│   │   ├── Model/                 # BaseResponseDTO / Auth·Home DTO + Entity Mapper
│   │   ├── API/                   # PieckeDomain, AuthAPI, HomeAPI, BaseAPI
│   │   ├── Service/               # AuthService / HomeService (BaseTargetType), 요청 바디
│   │   └── Repository/            # Auth·Home RepositoryImpl + OAuth Repository
│   │       ├── Auth/              # Interceptor, RefreshToken Session, Pool, MoyaProvider 확장
│   │       └── OAuth/             # Apple / Google / Kakao / Web OAuth 구현
│   │
│   ├── Network/                   # 🌐 Network Layer
│   │   ├── Networking/            # 네트워크 클라이언트 export
│   │   ├── Foundations/           # APIHeader / TokenProviding / KeychainTokenProvider
│   │   └── ThirdPartys/           # AsyncMoya / WeaveDI 등 SPM 재노출
│   │
│   └── Shared/                    # 🔧 Shared Layer
│       ├── DesignSystem/          # 공통 UI / 컬러 / 이미지 / Toast
│       ├── Shared/                # 공유 모델·확장
│       ├── ThirdParty/            # 써드파티 래퍼
│       └── Utill/                 # 공통 유틸리티
│
├── 🔧 Tuist/
│   ├── Package.swift              # SPM 의존성 정의
│   └── ProjectDescriptionHelpers/ # 모듈 템플릿 / Plist 헬퍼
└── 🧩 Plugins/
    ├── DependencyPlugin/          # 모듈 의존성 헬퍼 (.Data / .Domain / .Network ...)
    ├── DependencyPackagePlugin/   # SPM 의존성 헬퍼 (.SPM.asyncMoya ...)
    └── ProjectTemplatePlugin/     # ProjectConfig / Project.makeModule

🏛️ Clean Architecture Pattern

graph TD
    A[🎨 Presentation Layer] --> B[🔥 Domain Layer]
    B --> C[📡 Data Layer]
    D[🌐 Network Layer] --> C
    E[🔧 Shared Layer] --> A
    E --> B
    E --> C

    A -.-> F[SwiftUI Views]
    A -.-> G[TCA Reducers]
    B -.-> H[UseCases]
    B -.-> I[Entities]
    C -.-> J[Repositories]
    C -.-> K[API Services]
Loading

🕸️ TuistSpider 확장 뷰

레이어별로 묶어 보거나(Grouped) 모든 모듈을 펼쳐 본(Expanded) 시각화입니다. (TuistSpider 결과)

Grouped Expanded

🔄 의존성 방향 원칙

Presentation → Domain (UseCase / Entity)
       ↓
Domain/UseCase → Domain (Interface / Entity)
       ↓
Data/Repository → Domain (Interface / Entity) + Data (Model + Service + API)
       ↓
Data/Service → Data (API) + Network/Foundations (APIHeader) + Domain/Entity (요청 식별값)
       ↓
Network/Foundations → Network/ThirdPartys (AsyncMoya, WeaveDI)

핵심 설계 원칙

  • Presentation 은 Domain UseCase / Entity 만 직접 참조
  • Domain 은 외부 계층에 의존하지 않는 순수 비즈니스 로직
  • Data/Repository 는 Domain 인터페이스를 구현, DTO ↔ Entity 매핑 담당
  • Data/Service 는 endpoint / header / method / parameter 정의만 담당하고 DTO Model 에 의존하지 않음
  • ✅ 모든 데이터 흐름은 Domain 을 중심으로 진행

🔐 OAuth 인증 플로우

Google / Kakao — WKWebView server-mediated OAuth

앱
  │  authorize URL (response_type=code, redirect_uri=https://picke.store/oauth/<p>)
  ▼
WKWebView (OAuthWebViewController)
  │  사용자 동의 → 구글/카카오가 redirect_uri 로 302
  │  WKNavigationDelegate.decidePolicyFor 가 picke.store/oauth/<p>?code=... 가로채기
  │  decisionHandler(.cancel)   ← 401 응답 송신 차단
  ▼
authorizationCode 추출 → dismiss
  ▼
UnifiedOAuthUseCase
  │  POST /api/v1/auth/login/<provider>
  │  body: { authorizationCode, redirectUri }
  ▼
AuthRepositoryImpl
  │  BaseResponseDTO<LoginDataDTO> 디코딩 → LoginEntity
  ▼
KeychainManager 저장 + AuthSessionManager.credential 갱신

Apple — 네이티브 Sign-In

ASAuthorizationAppleIDProvider 로 받은 credential / nonce / authorizationCode 를 그대로 백엔드에 전달.

토큰 자동 갱신

  • AccessTokenCredential 가 access token JWT 의 exp 를 디코딩해 만료 시점 보관
  • AuthInterceptor.adapt 에서 만료 5분 전이면 TokenRefreshManager 가 단일화된 refresh 수행
  • 401 응답 시 retry 로 토큰 갱신 후 재시도, 실패 시 NSNotification.refreshTokenExpired 발송 + 자동 로그아웃

🛠 기술 스택

Core Technologies

  • 🎯 Architecture: The Composable Architecture (TCA)
  • 📦 Modularization: Tuist 4.x (Micro Feature Architecture)
  • 💉 Dependency Injection: WeaveDI 3.4.1
  • 🔀 Navigation: TCAFlow (커스텀)
  • ⚡ Concurrency: Swift Concurrency (async/await)

📚 주요 라이브러리

🎯 아키텍처 & 상태 관리

  • ComposableArchitecture — 단방향 상태 관리
  • TCAFlow ⭐️ — TCA 기반 화면 전환 / 네비게이션 (커스텀)
  • WeaveDI ⭐️ — 의존성 주입 컨테이너 (커스텀)

🔐 인증 & 보안

  • AuthenticationServices — Apple Sign-In, ASWebAuthenticationSession
  • WebKit — WKWebView 기반 server-mediated OAuth (Google / Kakao)
  • AppAuth-iOS — OAuth 2.0 / OpenID Connect 클라이언트 (옵션)

🌐 네트워킹

  • AsyncMoya ⭐️ — async/await 기반 HTTP 클라이언트 (커스텀)
  • Alamofire / Moya — AsyncMoya 의 기반 스택

🎨 UI & UX

🔥 백엔드 / 분석

🛠 개발 도구 & 유틸리티

📊 로깅 & 디버깅

  • LogMacro — 커스텀 로깅 매크로
  • IssueReporting — 개발 단계 이슈 추적
  • XCTestDynamicOverlay — 테스트 환경 오버레이

⚡ 성능 & 동시성

  • Clocks — 시간 관련 유틸리티
  • ConcurrencyExtras — Swift Concurrency 확장
  • Swift 6.0 — 최신 Swift 언어 기능

🔧 빌드 & 배포

  • Tuist — 프로젝트 생성 / 모듈 의존성 관리
  • Swift Package Manager — 패키지 의존성 관리
  • fastlane — 자동화된 빌드 / 배포 (예정)

📱 지원 환경

  • 💻 Xcode: 16.0 이상
  • 📱 iOS: 17.0 이상
  • ⚡ Swift: 6.0 이상
  • 🔧 Tuist: 4.x 이상

🚀 빠른 시작

✅ 필수 요구사항

  • 💻 Xcode: 16.0 이상
  • 📱 iOS: 17.0 이상
  • ⚡ Swift: 6.0 이상
  • 🔧 Tuist: 4.x 이상

🛠 설치 및 실행

1️⃣ 저장소 클론

git clone https://github.com/Roy-wonji/Picke-iOS.git
cd Picke-iOS

2️⃣ Tuist 설치

curl -Ls https://install.tuist.io | bash

3️⃣ 프로젝트 빌드 / 생성

# 전체 워크플로우 (권장)
./make build      # clean → install → generate

# 단계별 실행
./make clean      # 빌드 산출물 정리
./make install    # SPM 의존성 설치
./make generate   # Xcode 프로젝트 생성

4️⃣ Xcode 열기

open Picke.xcworkspace

⚙️ 환경 설정

다음 키들을 Picke-Dev.xcconfig / Picke-Stage.xcconfig / Picke-Prod.xcconfig 에 채워주세요.

BASE_URL              = picke.store
GOOGLE_CLIENT_ID      = YOUR_GOOGLE_WEB_CLIENT_ID
GOOGLE_IOS_CLIENT_ID  = YOUR_GOOGLE_IOS_CLIENT_ID
REVERSED_CLIENT_ID    = YOUR_REVERSED_CLIENT_ID
KAKAO_REST_API_KEY    = YOUR_KAKAO_REST_API_KEY

🌐 OAuth 사전 등록

Provider redirect_uri 비고
Google https://picke.store/oauth/google Web client ID + Google Cloud Console 등록 필요
Kakao https://picke.store/oauth/kakao Kakao Developers 콘솔 등록 필요
Apple (네이티브) App Store Connect → Sign in with Apple

🛠️ 주요 명령어

🔄 기본 워크플로우

./make build      # 전체 빌드 프로세스 (권장)
./make generate   # 프로젝트 생성만
./make clean      # 빌드 산출물 정리
./make install    # 의존성 설치

🚨 문제 해결

tuist clean       # Tuist 캐시 정리
./make clean      # 모든 빌드 파일 정리

🔍 코드 품질 / 그래프

tuist graph       # 의존성 그래프 생성
tuist test        # 전체 테스트 실행

📄 라이선스

이 프로젝트는 MIT 라이선스 하에 배포됩니다. 자세한 내용은 LICENSE 파일을 참고하세요.

👥 팀 & 크레딧

💻 개발팀

🛠 기술 스택

  • iOS: Swift Xcode Fastlane

  • Server: AWS EC2 AWS Swagger

  • Design: Figma

  • VCS: Git GitHub

🐈‍⬛ Git 브랜칭 전략

1️⃣ Git Branching Strategy

  • main: 프로덕션 배포용
  • develop: 개발 통합 브랜치
  • feature/*: 기능별 개발 브랜치
  • fix/*: 버그 픽스 브랜치

📋 워크플로우

  1. develop 에서 feature/ 브랜치 생성
  2. 기능 개발 → 자체 커밋 단위 SRP 분리
  3. feature/develop Pull Request, 코드 리뷰
  4. developmain 배포 Pull Request

✍️ 커밋 메시지

  • 한국어 사용
  • 관련 GitHub 이슈 번호 매칭 (예: #20 #2)
  • 형식: <type>: <요약> #<issue>
  • feat / fix / refactor / chore / docs / test

📞 문의 및 지원


Made with ❤️ by Picke Team

Star this repo