๊ฐ์น๊ด ์ถฉ๋์์ ์์ํ๋ 1:1 ์ฒ ํ ๋ฐฐํ ํ๋ซํผ, Picke
๐ฏ Features | ๐ Architecture | ๐ Quick Start | ๐ OAuth Flow
Picke ๋ ์ผ์์ ๊ฐ์น๊ด ์ฐจ์ด๋ฅผ 1:1 ํ ๋ก ์ผ๋ก ํ์ด๋ด๋ ๋ชจ๋ฐ์ผ ํ ๋ก ยทํฌํ ํ๋ซํผ์ ๋๋ค. "์ค๋์ ๋ฐฐํ" ์ฃผ์ ์ ๋ํ ์ฌ์ ยท์ฌํ ํฌํ, ์ค์๊ฐ 1:1 ์ฑํ ํ ๋ก , ๊ทธ๋ฆฌ๊ณ ๋ฆฌ์บก ์นด๋๊น์ง ํ ํ๋ฆ์ผ๋ก ์ด์ด์ง๋๋ค.
๐ก ์ ๋ง๋ค์๋? SNS ์ ๋จ๋ฐฉํฅ ์๊ฒฌ ํ์ถ ๋์ , ์งง๊ณ ๋ช ํํ 1:1 ํ ๋ก ์ ํตํด "๋ด๊ฐ ์ ๊ทธ๋ ๊ฒ ์๊ฐํ๋์ง" ๋ฅผ ์ ๋ฆฌํ๊ณ ๋ค๋ฅธ ๊ฐ์น๊ด์ ๋ง์ฃผํ๋ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
ํ๋ก์ ํธ ๊ท์น์ AGENTS.md / CLAUDE.md ์ ์ ์๋์ด ์์ต๋๋ค.
ln -s AGENTS.md CLAUDE.md- Google / Kakao: WKWebView ๊ธฐ๋ฐ
authorize โ code ๊ฐ๋ก์ฑ๊ธฐโ ๋ฐฑ์๋ ํ ํฐ ๊ตํ - Apple Sign-In:
ASAuthorizationAppleIDProvider๋ค์ดํฐ๋ธ ํตํฉ - ์๋ ํ ํฐ ๊ฐฑ์ :
AccessTokenCredentialJWT exp ๋์ฝ๋ฉ + ๋ง๋ฃ 5๋ถ ์ ์๋ refresh - 401 ์๋ ์ฒ๋ฆฌ:
AuthInterceptor๊ฐ 401 ๊ฐ์ง โ refresh ์๋ โ ์คํจ ์ ์๋ ๋ก๊ทธ์์ ์๋ฆผ ๋ฐ์ก - USER_404 ๊ฐ์ ๋ก๊ทธ์์:
SessionInvalidationPlugin์ด ์๋ต ๋ฐ๋ ์๋ฌ์ฝ๋(USER_404) ๊ฐ์ง โ Keychain/์ธ์ ์ ๋ฆฌ ํ ๋ก๊ทธ์ธ ์ ํ
- ์ฌ์ ํฌํ โ 1:1 ์ฑํ ํ ๋ก โ ์ฌํ ํฌํ ์ ํ ํ๋ฆ
- ์ฌํฌํ ๋ก ๊ฐ์น๊ด์ด ๋ฐ๋์๋์ง ์ถ์
- ๋ฆฌ์บก ์นด๋ ์๋ ์์ฑ + ๊ณต์
- ์ฑํ
๋ฐฉ ์ค๋์ค ์ฌ์ + ๋ก๋ฉ ์คํจ ์ ์๋จ floating ์ค๋ฅ ๋ฐฐ๋(
FloatingErrorView)
- ์ฑํ ๋ฐฉํ 1:1 ์์ฑ ํ ๋ก
- ๊ด์ (=๋๊ธ) ๋ฑ๋กยท์์ ยท์ญ์ + ๋๋๊ธ, ์ข์์, ์ ๊ณ
- ํฌํ ์ง์(optionId)๋ณ ๊ด์ ๋ฑ๋ก / ์ง์ ํญ ํํฐ
- ๋ณธ์ธ ๊ธ "๋" ํ์ + ์์ ยท์ญ์ ๋ฉ๋ด, ๋ฑ๋กยท๊ฐฑ์ ์ ์ค์ผ๋ ํค
- ํ๋ ์ดํ ๋ ํ ํผ๋
- ํฅ๋ฏธ ๊ธฐ๋ฐ ๋ฐฐํ ์ถ์ฒ(ํ๋ ์ดํ
ํ๋ฉด) โ
GET /battles/{id}/recommendations/interesting - ์นดํ ๊ณ ๋ฆฌยทํ๊ทธ ํ์
- ํ ํฝ ๊ฒ์
- ํ๋กํ ์นด๋ / ๋ณด์ ํฌ์ธํธ + ๋ฌด๋ฃ ์ถฉ์ (๋ฆฌ์๋ ๊ด๊ณ )
- ํฌ์ธํธ ๋ด์ญ, ๋ด ๋ฐฐํ ๊ธฐ๋ก, ๋ด ์ฝํ ์ธ ํ๋(๋๊ธ/์ข์์), ๊ณต์ง์ฌํญยท์ด๋ฒคํธ
- ๋์ ์ฒ ํ์ ์ ํ(recap) โ ๋ฐฐํ 5๊ฐ ๋ฏธ๋ง ์ ์ ๊ธ ํ๋ฉด ๋ถ๊ธฐ, ์ ๋๋ฉ์ด์ ๋ ์ด๋ ์ฐจํธ + ๊ณต์
- ๋ฐฐํ ์ฃผ์ ์ ์, ์๋ฆผ ์ค์
- ํ์ ํํด โ ํํด ์ฌ์ (๋ณต์ ์ ํ) ์ ๋ ฅ ํ๋ฉด ๋ถ๋ฆฌ, ์ ์ถ ์ ๋๋ฐ์ด์ค ํ ํฐ ํด์ + ์ธ์ ์ข ๋ฃ
- ์๋ฆผ๋ฐ๊ธฐ ๋ชฉ๋ก โ ์นดํ ๊ณ ๋ฆฌ ํญ(์ ์ฒดยท์ฝํ ์ธ ยท๊ณต์ง์ฌํญยท์ด๋ฒคํธ) + ๋ฌดํ ์คํฌ๋กค
- ํญ ์ ์ฝ์ ์ฒ๋ฆฌ / ๋ชจ๋ ์ฝ์ โ
GET /api/v1/notifications, ์ฝ์์PATCH .../readยท/read-all - ๋ฏธ์ฝ์ ๋นจ๊ฐ์ โ
@Shared(.appStorage("HasUnreadNotification"))๋ก ํยทํ๋กํ ์ข ์์ด์ฝ์ ํ์- ๊ฐ๋ณ/๋ชจ๋ ์ฝ์ ์ ์ฆ์ ์ ๊ฑฐ, ์ ํธ์ ์์ ์ ๋ค์ ํ์, ์ฑ ์ฌ์คํ์๋ ์ํ ์ ์ง
- APNs ๋ค์ด๋ ํธ ๋ฐ์ก (Firebase SDK ๋ฏธ์ฌ์ฉ) โ ๊ถํ ์์ฒญยทํ ํฐ ์์ ํ
POST /api/v1/devices๋ฑ๋ก(platform: "IOS"), ๋ก๊ทธ์์/ํํด ์ ํด์ - ์๋ฆผ ํญ โ ํ์ด๋ก๋(
type/url)๋ฅผPickeDeeplink๋ก ๋ณํํด ๋ฐฐํ ์์ธ ๋ฑ์ผ๋ก ๋ผ์ฐํ , ์ฝ๋ ์คํํธ ๋๊ธฐ ๋ฅ๋งํฌ ์ฒ๋ฆฌ - ์ปค์คํ
URL scheme
picke://battle/55ยทpicke://perspective/45?commentId=678(onOpenURL)
- ์คํ๋์์์ App Store(iTunes lookup) ์ต์ ๋ฒ์ ๋น๊ต โ ์ ๋ฐ์ดํธ ํ์ ์ ์๋ด alert
- "์ง๊ธ ์ ๋ฐ์ดํธ" โ App Store, "๋์ค์" โ ์ ์ ์ง์
- GoogleMobileAds ๋ฆฌ์๋ ๋์์ ์์ฒญ โ ํฌ์ธํธ ์ถฉ์ (๊ด๊ณ ์ ๋ ID ๋
REWARD_AD_UNITconfig ์ฃผ์ ) RewardedAdClient(UseCase) โ ๋ก๋ยทํ์ยท๋ณด์ ์ฝ๋ฐฑ์ async ๋ก ์ถ์ํ
AnalyticsUseCaseโ ํ์ ์์ ์ด๋ฒคํธ + PICKรฉ ํต์ฌ ์ด๋ฒคํธ ๋ช ์ธ์ ์ค์(์ด๋ฒคํธ ํตํฉ ์ ๋ต)sign_up/battle_step(pre_voteยทaudio_endยทpost_vote) /report_action/community_action/ad_revenue+ ๋ก๊ทธ์ธ ์identify
Picke-iOS/
โโโ ๐ฑ Projects/
โ โโโ App/ # ๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์
ํ๊ฒ
โ โ โโโ Sources/
โ โ โ โโโ Application/ # AppDelegate(APNs) / PushTokenStore / Deeplink ๋ธ๋ฆฌ์ง
โ โ โ โโโ Di/ # WeaveDI ๋ฑ๋ก (DiRegister, AppPresentationContextProvider)
โ โ โ โโโ Reducer/ # TCA Root AppReducer
โ โ โ โโโ View/ # Root Views
โ โ โโโ Derived/ # Tuist ์์ฑ plist
โ โ
โ โโโ Presentation/ # ๐จ UI Layer
โ โ โโโ Auth/ # ๋ก๊ทธ์ธ / ์จ๋ณด๋ฉ / ์ธ์ฆ ์ฝ๋๋ค์ดํฐ
โ โ โโโ Battle/ # ์ค๋์ ๋ฐฐํ / ๋น ๋ฅธ ๋ฐฐํ ํ๋ฉด ๋ชจ๋ธ๊ณผ ๋ฉ์ธ ํ๋ก์ฐ
โ โ โโโ Chat/ # ํฌํ / ์ฑํ
๋ฐฉ / ๊ด์ ยท๋๋๊ธ / ํ๋ ์ดํ
โ โ โโโ Hifi/ # ํ์ยท๊ฒ์ ๊ธฐ๋ฐ Hi-Fi ํ๋ฉด
โ โ โโโ Home/ # ํ ํผ๋ / ์ถ์ฒ / ์ค์ผ๋ ํค
โ โ โโโ MainTab/ # ํญ ๋ผ์ฐํ
/ GNB
โ โ โโโ Notification/ # ์๋ฆผ๋ฐ๊ธฐ ๋ชฉ๋ก / ์นดํ
๊ณ ๋ฆฌ ํญ / ๋ฏธ์ฝ์ ๋ฑ์ง
โ โ โโโ Profile/ # ๋ง์ดํ์ด์ง / ํฌ์ธํธ / ์ค์ / ํํด / ๋ฐฐํ์ ์ / ๋ฐฐํ๊ธฐ๋ก / ์ฝํ
์ธ ํ๋ / ๊ณต์ง / ๋ฆฌ์บก / ๋ฌด๋ฃ์ถฉ์
โ โ โโโ Splash/ # ์คํ๋์ / ์ฑ ์
๋ฐ์ดํธ ์ฒดํฌ
โ โ โโโ Web/ # ์ฝ๊ด / ์ธ๋ถ ๋งํฌ WebView
โ โ โโโ Presentation/ # ๊ณตํต ํ๋ ์ ํ
์ด์
์ ํธ
โ โ
โ โโโ Domain/ # ๐ฅ Business Logic Layer
โ โ โโโ Entity/ # Auth / Battle / Comment / Home / OAuth / Profile / Notification / Device / Deeplink / AppUpdate / Share / Error ์ํฐํฐ
โ โ โโโ DomainInterface/ # Repository / Manager ์ธํฐํ์ด์ค (Device ยท AppUpdate ํฌํจ)
โ โ โโโ UseCase/ # Auth / Battle / Comment / Home / OAuth / Profile / Notification / Device / AppUpdate / Analytics / Ad ์ ์ค์ผ์ด์ค
โ โ
โ โโโ Data/ # ๐ก Data Layer
โ โ โโโ API/ # Base / Auth / Battle / Comment / Home / Perspective / Profile / Notification / Device endpoint
โ โ โโโ Service/ # Moya TargetType + ์์ฒญ ๋ฐ๋
โ โ โโโ Model/ # BaseResponseDTO + DTO โ Entity ๋งคํผ
โ โ โโโ Repository/ # RepositoryImpl + OAuth / AudioPlayer ๊ตฌํ
โ โ
โ โโโ Network/ # ๐ Network Layer
โ โ โโโ Networking/ # ๋คํธ์ํฌ ํด๋ผ์ด์ธํธ export
โ โ โโโ Foundations/ # APIHeader / TokenProviding / KeychainTokenProvider
โ โ โโโ ThirdPartys/ # AsyncMoya / WeaveDI ๋ฑ SPM ์ฌ๋
ธ์ถ
โ โ
โ โโโ Shared/ # ๐ง Shared Layer
โ โโโ DesignSystem/ # ๊ณตํต UI / ์ปฌ๋ฌ ํ ํฐ / ์ด๋ฏธ์ง / Toast / Floating ๋ฐฐ๋ / ํ์
โ โโโ Shared/ # ๊ณต์ ๋ชจ๋ธยทํ์ฅ
โ โโโ ThirdParty/ # ์จ๋ํํฐ ๋ํผ
โ โโโ Utill/ # ๋ ์ง / ์ซ์ / ๋ฌธ์์ด ํ์ ์ ํธ๋ฆฌํฐ
โ
โโโ ๐ง Tuist/
โ โโโ Package.swift # SPM ์์กด์ฑ ์ ์
โ โโโ ProjectDescriptionHelpers/ # ๋ชจ๋ ํ
ํ๋ฆฟ / Plist ํฌํผ
โโโ ๐งฉ Plugins/
โโโ DependencyPlugin/ # ๋ชจ๋ ์์กด์ฑ ํฌํผ (.Data / .Domain / .Network ...)
โโโ DependencyPackagePlugin/ # SPM ์์กด์ฑ ํฌํผ (.SPM.asyncMoya ...)
โโโ ProjectTemplatePlugin/ # ProjectConfig / Project.makeModule
graph TD
A[Presentation: SwiftUI + TCA Feature] --> B[Domain: UseCase + Entity]
B --> C[DomainInterface: Repository Protocol]
D[Data: RepositoryImpl] --> C
D --> E[Data: DTO Model + Service + API]
E --> F[Network: AsyncMoya + Header + Token]
G[Shared: DesignSystem / Utill] --> A
G --> B
G --> D
A -.-> H[Auth / Battle / Chat / Home / Hifi / MainTab / Splash / Web]
B -.-> I[Auth / Battle / Comment / Perspective / Search UseCase]
D -.-> J[Auth / Battle / Comment / Home / OAuth / Perspective / Search Repository]
๋ ์ด์ด๋ณ๋ก ๋ฌถ์ด ๋ณด๊ฑฐ๋(Grouped) ๋ชจ๋ ๋ชจ๋์ ํผ์ณ ๋ณธ(Expanded) ์๊ฐํ์ ๋๋ค. (TuistSpider ๊ฒฐ๊ณผ)
Presentation โ Domain (UseCase Protocol)
โ
Domain/UseCase โ Domain (Repository Protocol)
โ
Data/Repository โ Domain (Entity + Repository Protocol)
โ
Data/Model โ Domain (Entity ๋ณํ)
โ
Data/Service โ Data/API + Network/Foundations
ํต์ฌ ์ค๊ณ ์์น
- โ Presentation ์ Domain ์ UseCase ๋ง ์์กดํฉ๋๋ค.
- โ Domain/UseCase ๋ Repository Protocol ์ ํตํด ์ธ๋ถ IO ๋ฅผ ํธ์ถํฉ๋๋ค.
- โ Data/Repository ๋ Domain ์ Repository Protocol ์ ๊ตฌํํ๊ณ Entity ๋ฅผ ๋ฐํํฉ๋๋ค.
- โ Data/Model ์ DTO ์ Entity ๋ณํ์ ๋ด๋นํฉ๋๋ค.
- โ Data/Service ๋ endpoint / method / parameter ์ ์๋ง ๋ด๋นํฉ๋๋ค.
- โ ๋ชจ๋ ๋ฐ์ดํฐ ํ๋ฆ์ Domain ์ ์ค์ฌ์ผ๋ก ์งํํฉ๋๋ค.
์ฑ
โ 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 ๊ฐฑ์
ASAuthorizationAppleIDProvider ๋ก ๋ฐ์ credential / nonce / authorizationCode ๋ฅผ ๊ทธ๋๋ก ๋ฐฑ์๋์ ์ ๋ฌ.
AccessTokenCredential๊ฐ access token JWT ์exp๋ฅผ ๋์ฝ๋ฉํด ๋ง๋ฃ ์์ ๋ณด๊ดAuthInterceptor.adapt์์ ๋ง๋ฃ 5๋ถ ์ ์ด๋ฉดTokenRefreshManager๊ฐ ๋จ์ผํ๋ refresh ์ํ- 401 ์๋ต ์
retry๋ก ํ ํฐ ๊ฐฑ์ ํ ์ฌ์๋, ์คํจ ์NSNotification.refreshTokenExpired๋ฐ์ก + ์๋ ๋ก๊ทธ์์
- ๐ฏ 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 ์ ๊ธฐ๋ฐ ์คํ
- SwiftUI โ ์ ์ธํ UI
- SDWebImageSwiftUI โ ๋น๋๊ธฐ ์ด๋ฏธ์ง ๋ก๋ฉ / ์บ์ฑ
- Firebase iOS SDK โ Crashlytics / Messaging
- Mixpanel โ ํ๋ ๋ถ์ / Session Replay
- Google Mobile Ads โ ๊ด๊ณ
- LogMacro โ ์ปค์คํ ๋ก๊น ๋งคํฌ๋ก
- IssueReporting โ ๊ฐ๋ฐ ๋จ๊ณ ์ด์ ์ถ์
- XCTestDynamicOverlay โ ํ ์คํธ ํ๊ฒฝ ์ค๋ฒ๋ ์ด
- Clocks โ ์๊ฐ ๊ด๋ จ ์ ํธ๋ฆฌํฐ
- ConcurrencyExtras โ Swift Concurrency ํ์ฅ
- Swift 6.0 โ ์ต์ Swift ์ธ์ด ๊ธฐ๋ฅ
- Tuist โ ํ๋ก์ ํธ ์์ฑ / ๋ชจ๋ ์์กด์ฑ ๊ด๋ฆฌ
- Swift Package Manager โ ํจํค์ง ์์กด์ฑ ๊ด๋ฆฌ
- fastlane + Bundler โ TestFlight / App Store ๋น๋ยท์ ๋ก๋ ์๋ํ
- ๐ป Xcode: 16.0 ์ด์
- ๐ฑ iOS: 17.0 ์ด์
- โก Swift: 6.0 ์ด์
- ๐ง Tuist: 4.x ์ด์
- ๐ป Xcode: 16.0 ์ด์
- ๐ฑ iOS: 17.0 ์ด์
- โก Swift: 6.0 ์ด์
- ๐ง Tuist: 4.x ์ด์
git clone https://github.com/Roy-wonji/Picke-iOS.git
cd Picke-iOScurl -Ls https://install.tuist.io | bashrbenv install 3.3.9
rbenv global 3.3.9
bundle install# ์ ์ฒด ์ํฌํ๋ก์ฐ (๊ถ์ฅ)
./make build # clean โ install โ generate
# ๋จ๊ณ๋ณ ์คํ
./make clean # ๋น๋ ์ฐ์ถ๋ฌผ ์ ๋ฆฌ
./make install # SPM ์์กด์ฑ ์ค์น
./make generate # 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
| Provider | redirect_uri | ๋น๊ณ |
|---|---|---|
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 # ์ ์ฒด ํ
์คํธ ์คํexport MATCH_KEYCHAIN_PASSWORD="<match keychain password>"
bundle exec fastlane ios QA # TestFlight ์
๋ก๋
bundle exec fastlane ios release # App Store ๋ฐฐํฌMATCH_KEYCHAIN_PASSWORD๊ฐ ์ค์ ๋์ด ์์ผ๋ฉด fastlane์ด match_keychain์ ๋จผ์ unlockํด์ macOS ํค์ฒด์ธ ๋น๋ฐ๋ฒํธ ํ์
์ ์ค์
๋๋ค.
์ด ํ๋ก์ ํธ๋ MIT ๋ผ์ด์ ์ค ํ์ ๋ฐฐํฌ๋ฉ๋๋ค. ์์ธํ ๋ด์ฉ์ LICENSE ํ์ผ์ ์ฐธ๊ณ ํ์ธ์.
- iOS Lead Developer: ์์์ง (@Roy-wonji)
- main: ํ๋ก๋์ ๋ฐฐํฌ์ฉ
- develop: ๊ฐ๋ฐ ํตํฉ ๋ธ๋์น
- feature/*: ๊ธฐ๋ฅ๋ณ ๊ฐ๋ฐ ๋ธ๋์น
- fix/*: ๋ฒ๊ทธ ํฝ์ค ๋ธ๋์น
- develop ์์ feature/ ๋ธ๋์น ์์ฑ
- ๊ธฐ๋ฅ ๊ฐ๋ฐ โ ์์ฒด ์ปค๋ฐ ๋จ์ SRP ๋ถ๋ฆฌ
- feature/ โ develop Pull Request, ์ฝ๋ ๋ฆฌ๋ทฐ
- develop โ main ๋ฐฐํฌ Pull Request
- ํ๊ตญ์ด ์ฌ์ฉ
- ๊ด๋ จ GitHub ์ด์ ๋ฒํธ ๋งค์นญ (์:
#20 #2) - ํ์:
<type>: <์์ฝ> #<issue> feat / fix / refactor / chore / docs / test
- ๐ง ์ด๋ฉ์ผ: suhwj81@gmail.com
- ๐ ๋ฒ๊ทธ ์ ๊ณ : Issues
- ๐ก ๊ธฐ๋ฅ ์ ์: Discussions

