309 lines
19 KiB
Markdown
309 lines
19 KiB
Markdown
# FANUZU 앱 골격 (Flutter)
|
|
|
|
> 2주차 산출물 · 발주사 (주)팬케이크 / 수행사 스위치 주식회사(Sweech)
|
|
> 별첨2 2주차 「첫 빌드(앱 골격)」의 빌드 포함 범위 = **Flutter 앱 골격 · 5탭 네비게이션 · 소셜 로그인 · 디자인시스템**
|
|
|
|
## 1. 이 골격의 범위
|
|
|
|
| | 내용 |
|
|
|---|---|
|
|
| **포함** | 앱 기동 · 코스믹 다크 테마(design-tokens.md 생성) · 5탭 셸 네비게이션 · 로그인 화면(S-A-LOGIN) 4종 소셜 버튼 · 인증 인터페이스와 Google/Apple 실 코드 경로 · Firebase 초기화(미설정 시 목 모드) |
|
|
| **미포함** | 각 탭의 실제 화면(3주차 이후) · 온보딩 나머지 6화면(S-A-INTRO · S-A-TERMS · S-A-PROFILE · S-A-ARTIST · S-A-PLANET-NEW · S-A-PERMS) · 도메인 로직(POP·FPI·퀘스트·이클립스) · 상태관리 라이브러리 |
|
|
|
|
미포함 항목을 지금 만들지 않은 이유: **RN/Flutter 승인이 아직 없다(2주차_확인요청항목 Q1).**
|
|
미승인 시 폐기할 수 있도록 골격과 도메인 로직을 섞지 않았다. 5탭 라벨·화면 ID·토큰처럼
|
|
언어와 무관한 계약 정보만 코드에 들어가 있다.
|
|
|
|
## 2. 빌드·실행
|
|
|
|
전제: Flutter stable 3.41.7 / Dart 3.11.5 (검증에 쓴 버전), Android SDK 36, Xcode 26.6
|
|
|
|
```bash
|
|
cd app
|
|
flutter pub get
|
|
flutter run # 실기기·시뮬레이터
|
|
flutter analyze # 정적 분석
|
|
flutter test # 스모크·회귀 테스트 9건
|
|
flutter build apk --debug # Android 디버그 APK
|
|
```
|
|
|
|
빌드 산출물은 `build/app/outputs/flutter-apk/app-debug.apk` 에 떨어진다.
|
|
|
|
> ⚠️ **`pubspec.yaml` 의 의존성을 추가·변경·업그레이드하면 최소 지원 OS 하한을 재계산할 것.**
|
|
> 절차: `주간보고/2주차/src/2주차_플러그인_선검증리포트.md` §3.5
|
|
>
|
|
> 최소 지원 OS 는 **별첨1 v1.0 에 계약값으로 박힌다**(견적서 1228행). 지킬 수 없는 하한을
|
|
> 계약에 적으면 그 아래 단말의 장애가 개발사 책임이 된다. 선검증 리포트의 값은
|
|
> 2026-08-08 시점 측정치이므로, 이 앱의 의존성이 바뀌면 그 값은 그 순간 거짓이 된다.
|
|
>
|
|
> 2026-08-08 기준 합집합: **Android API 29 · iOS 15.0**
|
|
> (이 프로젝트 단독값은 Android API 24 · iOS 15.0 — Android 29 는 `geofence_foreground_service`,
|
|
> iOS 15.0 은 `firebase_auth` 가 올린 값이다. 퀘스트 플러그인이 들어오는 6주차 전에 `minSdk` 를 29 로 올려야 한다.)
|
|
|
|
## 3. 디자인 토큰 — 손으로 옮기지 않는다
|
|
|
|
`lib/core/theme/tokens.dart` 는 **생성물**이다. 직접 고치면 시안(`시안/assets/ds.css`)과 어긋난다.
|
|
|
|
```bash
|
|
cd app
|
|
python3 tool/gen_tokens.py # PyYAML 필요: pip install pyyaml
|
|
```
|
|
|
|
* 입력: `design/design-tokens.md` 의 `<!-- TOKENS -->` 아래 yaml 블록 (SoT)
|
|
* 출력: `lib/core/theme/tokens.dart`
|
|
* 부수 검증: `design-tokens.md` 의 `contrast_checks` 22쌍을 WCAG 로 재계산해 표로 출력하고,
|
|
**AA(4.5:1) 미달이 하나라도 있으면 exit 1**. 테마가 대비를 깎았는지 여기서 걸린다.
|
|
* `lib/core/theme/app_theme.dart` 가 이 토큰으로 `ThemeData` 를 조립한다. 색·크기를 여기서 새로 만들지 마라.
|
|
|
|
**생성하지 않는 토큰** — CSS 전용 표현이라 Flutter 등가물이 없다:
|
|
`cosmic_fx.glow-*` · `grad-*` · `nebula` · `starfield` · `elevation.*`.
|
|
필요해지는 주차에 `tool/gen_tokens.py` 헤더의 목록에서 하나씩 내려서 추가한다.
|
|
|
|
## 4. Firebase — 지금은 목(mock) 모드
|
|
|
|
`google-services.json` / `GoogleService-Info.plist` 가 아직 없다. **가짜 파일을 만들어 두지 않았다.**
|
|
|
|
`lib/core/firebase/firebase_boot.dart` 가 `Firebase.initializeApp()` 을 시도하고,
|
|
실패하면 `FirebaseMode.mock` 으로 내려간 뒤 사유를 로그(`[FirebaseBoot] mode=mock :: ...`)로 남긴다.
|
|
앱은 정상적으로 뜬다.
|
|
|
|
파일이 투입되면 **코드 수정 없이** `FirebaseMode.live` 로 올라가고, 목 모드 전용 UI는 자동으로 사라진다.
|
|
|
|
### 목 모드에서의 로그인
|
|
|
|
Firebase 설정이 없으면 실 소셜 로그인이 물리적으로 불가능하다. 그런데 별첨2 2주차 발주사 확인
|
|
항목에 「앱 설치·**로그인**·탭 이동 확인」이 있다. 그래서 로그인 화면 하단에
|
|
**「목 세션으로 탭 둘러보기」** 입구를 목 모드에서만 노출한다.
|
|
|
|
* 화면에 목 모드임과 그 사유가 함께 표시된다 — 실 로그인으로 오인할 여지가 없다.
|
|
* `FirebaseBoot.reason` 은 사용자에게 보이는 문자열이라 **내부 파일 경로를 넣지 않는다.**
|
|
경로와 원시 예외는 `FirebaseBoot.detail` 로 분리해 로그에만 남긴다.
|
|
|
|
**가드가 두 겹인 이유 (교차검증 A-01 반영)**
|
|
|
|
```dart
|
|
bool get isMockSessionAvailable => !FirebaseBoot.isLive && !_releaseMode;
|
|
```
|
|
|
|
처음에는 `!FirebaseBoot.isLive` 한 겹만 두고 "설정 파일이 들어오면 자동으로 막힌다" 고 적었는데,
|
|
**그 설명은 틀렸다.** `FirebaseBoot.init()` 은 모든 예외를 삼키고 목 모드로 내려가므로,
|
|
설정 파일이 정상 투입된 릴리스 빌드라도 초기화가 어떤 이유로든 실패하면(플랫폼 초기화 실패,
|
|
리소스 패키징 오류, 기기 환경) 목 모드가 되고 우회 입구가 배포 앱에 노출된다.
|
|
|
|
그래서 빌드 모드로 한 겹 더 막았다. **릴리스 빌드에서는 어떤 경우에도 열리지 않는다.**
|
|
`kReleaseMode` 는 컴파일 상수라 테스트에서 뒤집을 수 없어, `AuthRepository({bool? releaseMode})`
|
|
로 주입 지점을 열어 두고 릴리스 동작을 테스트로 고정했다(회귀 가드 4종).
|
|
가드를 지우면 테스트 3개가 깨진다 — 확인했다.
|
|
|
|
## 5. 미투입 항목
|
|
|
|
### 5-1. 스위치(개발사) 내부 조치 — 발주사 요청 사항 아님
|
|
|
|
| ID | 항목 | 투입 위치 | 없으면 |
|
|
|---|---|---|---|
|
|
| S1 | Firebase 프로젝트(dev/prod) 개설 | — | 아래 S2 를 만들 수 없다 |
|
|
| S2 | `google-services.json` | `app/android/app/google-services.json` | 목 모드로 기동. Google 로그인 차단 |
|
|
| S2 | `GoogleService-Info.plist` | `app/ios/Runner/GoogleService-Info.plist` | 목 모드로 기동. Google·Apple 로그인 차단 |
|
|
|
|
> S2 투입 시 Android 는 `android/settings.gradle.kts` 에 `com.google.gms.google-services` 플러그인
|
|
> 추가가 함께 필요하다. 지금은 설정 파일이 없어 플러그인을 적용하지 않았다 —
|
|
> 적용한 채로 파일이 없으면 Gradle 빌드 자체가 실패한다.
|
|
|
|
### 5-2. 발주사 확인 필요
|
|
|
|
| ID | 항목 | 투입 위치 | 없으면 |
|
|
|---|---|---|---|
|
|
| Q3 | 카카오 네이티브 앱 키 | 미정(플러그인 도입 시 확정) | 카카오 버튼이 「키 미투입」 안내를 반환 |
|
|
| Q3 | 네이버 client ID / secret | 미정 | 네이버 버튼이 「키 미투입」 안내를 반환 |
|
|
| Q5 | 스토어 등록 명의 | — | 3주차 TestFlight·Play 내부트랙 제출 불가 |
|
|
| Q14 | 앱 식별자 확정 | `android/app/build.gradle.kts` · `ios/Runner.xcodeproj` | 현재 `kr.co.sweech.fancake` 로 잠정. **스토어 등록 후에는 변경 불가** |
|
|
| ~~Q6~~ | 공식 FANUZU 심볼 원본 | `assets/brand/` | **2026-08-13 반영 완료.** 제공본이 심볼 전용이라 앱 아이콘은 공식 자산으로 생성했고 로그인 워드마크는 `FANUZU` 텍스트를 유지 |
|
|
| Q15 | 하단 탭 아이콘 자산 | `assets/icons/` | Material 기본 아이콘 5종으로 잠정 |
|
|
|
|
### 5-3. 폰트
|
|
|
|
폰트 파일이 리포에 없다. `pubspec.yaml` 의 `fonts:` 블록이 **주석 처리된 채로** 투입 위치만 표시돼 있다.
|
|
|
|
| 용도 | 패밀리 | 투입 위치 | 출처 |
|
|
|---|---|---|---|
|
|
| 제목 | Gmarket Sans | `assets/fonts/GmarketSansTTF{Light,Medium,Bold}.ttf` | webfontworld/gmarket |
|
|
| 본문 | Pretendard Variable | `assets/fonts/PretendardVariable.ttf` | orioncactus/pretendard |
|
|
| 수치 | JetBrains Mono | `assets/fonts/JetBrainsMono-Regular.ttf` | JetBrains |
|
|
|
|
미투입 상태에서는 **시스템 폰트로 폴백**된다. 크기·굵기·행간·자간은 토큰 값 그대로 적용되므로
|
|
투입 전후 레이아웃 차이는 자소 폭 수준에 그친다.
|
|
|
|
## 6. 소셜 로그인 상태
|
|
|
|
화면명세 `S-A-LOGIN.md` 와 시안이 4종(카카오·네이버·Apple·Google)이고, 버튼 순서·라벨을 그대로 옮겼다.
|
|
|
|
| 제공자 | 상태 | 구현 | 막고 있는 것 |
|
|
|---|---|---|---|
|
|
| 카카오 | 스텁 | `KeylessSocialProvider` | 앱 키(Q3) |
|
|
| 네이버 | 스텁 | `KeylessSocialProvider` | 앱 키(Q3) |
|
|
| Apple | 실 코드 경로 | `AppleSignInProvider` | Firebase 설정(S2) + Xcode Capability |
|
|
| Google | 실 코드 경로 | `GoogleSignInProvider` | Firebase 설정(S2) |
|
|
|
|
설계 원칙: **「키 미투입」은 예외가 아니라 상태다.** 예외를 던지지 않고
|
|
`AuthNotConfigured(provider, missing)` 를 반환해 "무엇이 없어서 못 쓰는지"를 화면에 그대로 보여 준다.
|
|
|
|
**이메일 가입은 구현하지 않았다.** CD-18 미확정(Q2)이라 `SocialAuthProvider` 인터페이스에
|
|
구현체 하나가 더 붙을 자리만 비워 뒀다. **기능 플래그 상수는 두지 않았다** — 읽는 분기가 없는
|
|
플래그는 "false 라서 닫혀 있다" 는 착각만 만들고, 누가 true 로 바꿔도 아무 일이 일어나지 않는다
|
|
(교차검증 A-02). 지금 이메일을 닫고 있는 것은 `AuthRepository._defaultProviders()` 에
|
|
구현체가 없다는 사실 하나다.
|
|
|
|
## 7. 계약 고정 표기 — 5탭
|
|
|
|
```
|
|
HOME · INSIDE · GALAXY · STATION · MY
|
|
```
|
|
|
|
근거 3개가 서로 일치한다:
|
|
|
|
| 근거 | 위치 |
|
|
|---|---|
|
|
| 견적서 v2.1 「5탭 네비게이션」 | `Docs/Fancake_팬덤플랫폼_견적서.html` |
|
|
| 크래프트 게이트 C15 | `design/craft-allowlist.yaml` → `APP_TABS` |
|
|
| 시안 하단 탭바 | `시안/screens/S-{H-HOME,I-LOUNGE,G-PLANET,S-HUB,M-HOME}.html` 의 `<nav class="tabbar">` |
|
|
|
|
**한글화·치환·순서 변경 금지.** 스모크 테스트가 `design/craft-allowlist.yaml` 을 직접 읽어
|
|
문자열과 순서를 정확 일치로 검증한다 — 앱 코드만 고치면 테스트가 깨진다.
|
|
|
|
탭별 루트 화면:
|
|
|
|
| 탭 | 화면 ID | 화면명 |
|
|
|---|---|---|
|
|
| HOME | S-H-HOME | 오늘의 퀘스트 |
|
|
| INSIDE | S-I-LOUNGE | 팬덤 라운지 |
|
|
| GALAXY | S-G-PLANET | 내 행성 |
|
|
| STATION | S-S-HUB | STATION 허브 |
|
|
| MY | S-M-HOME | 마이 페이지 |
|
|
|
|
## 8. 폴더 구조
|
|
|
|
```
|
|
app/
|
|
├── pubspec.yaml
|
|
├── analysis_options.yaml flutter_lints + strict-casts/raw-types/inference
|
|
├── tool/gen_tokens.py design-tokens.md → tokens.dart 생성기
|
|
├── firebase/ T1(Firestore 설계) 영역 — 규칙·인덱스
|
|
├── test/app_smoke_test.dart 스모크 3종
|
|
└── lib/
|
|
├── main.dart FirebaseBoot.init() → runApp
|
|
├── app.dart MaterialApp.router + 테마 주입
|
|
├── core/
|
|
│ ├── theme/tokens.dart ← 생성물. 손대지 마라
|
|
│ ├── theme/app_theme.dart ThemeData 조립 (MD3 · ColorScheme.dark)
|
|
│ ├── router/app_router.dart 5탭 셸 + 로그인 라우트 + AppShell
|
|
│ ├── firebase/firebase_boot.dart
|
|
│ └── ui/tab_placeholder.dart
|
|
└── features/
|
|
├── auth/ 인터페이스 · 제공자 4종 · 저장소 · 로그인 화면
|
|
└── home/ inside/ galaxy/ station/ my/ 탭 루트 플레이스홀더
|
|
```
|
|
|
|
## 9. 검증 결과
|
|
|
|
<!-- VERIFY:BEGIN 실행 출력 그대로. 손으로 고치지 마라. -->
|
|
2026-08-14 재실행. macOS 27.0 · Flutter 3.41.7 (stable) · Dart 3.11.5 · Android SDK 36 · Xcode 26.6
|
|
|
|
```
|
|
$ flutter analyze
|
|
Analyzing app...
|
|
No issues found! (ran in 3.2s)
|
|
|
|
$ flutter test
|
|
00:00 +0: loading /Users/Kinos/Projects/p-fancake/app/test/app_smoke_test.dart
|
|
00:00 +0: 1. 앱이 예외 없이 뜨고 로그인 화면이 나온다
|
|
00:00 +1: 2. 하단 탭 5개가 계약 표기·순서 그대로 렌더된다
|
|
00:00 +2: 릴리스 빌드에서는 목 우회 입구가 열리지 않는다 목 모드 + 릴리스면 isMockSessionAvailable 이 false 다
|
|
00:00 +3: 릴리스 빌드에서는 목 우회 입구가 열리지 않는다 릴리스에서 signInWithMockSession 을 불러도 로그인되지 않는다
|
|
00:00 +4: 릴리스 빌드에서는 목 우회 입구가 열리지 않는다 릴리스 빌드 로그인 화면에 목 세션 버튼이 없다
|
|
00:00 +5: 릴리스 빌드에서는 목 우회 입구가 열리지 않는다 디버그 빌드에서는 목 세션 버튼이 있다 (가드가 과하게 잠그지 않았는지)
|
|
00:00 +6: 제공자 4종의 미투입 안내에 내부 파일 경로가 들어가지 않는다
|
|
00:00 +7: 화면에 띄우는 사유에 내부 파일 경로가 들어가지 않는다
|
|
00:00 +8: 3. 탭을 전환하면 각 탭 루트 화면이 바뀐다
|
|
00:00 +9: All tests passed!
|
|
|
|
$ flutter build apk --debug
|
|
Running Gradle task 'assembleDebug'... 219.5s (첫 빌드 — NDK 28.2 자동 설치 포함)
|
|
✓ Built build/app/outputs/flutter-apk/app-debug.apk (164,432,730 bytes · 약 156.8 MiB · debug)
|
|
10.6s (증분 재빌드)
|
|
|
|
$ flutter build ios --debug --no-codesign
|
|
Running pod install... 72.1s
|
|
Running Xcode build... 63.1s
|
|
✓ Built build/ios/iphoneos/Runner.app
|
|
|
|
$ python3 tool/gen_tokens.py
|
|
생성: lib/core/theme/tokens.dart (169줄)
|
|
… contrast_checks 25쌍 재계산 …
|
|
전 쌍 AA 통과. (최저 color-on-neon-violet / color-neon-violet = 5.09:1)
|
|
```
|
|
|
|
**테스트 9종은 Firebase 설정 파일이 없는 상태(목 모드)에서 통과한 결과다.**
|
|
|
|
음성 검증 2회 — 테스트가 실제로 게이트 역할을 하는지 직접 깨뜨려 확인했다.
|
|
|
|
| 변조 | 결과 |
|
|
|---|---|
|
|
| `appTabs` 의 `STATION` → `스테이션` | 2·3번 실패. 되돌린 뒤 재통과 |
|
|
| `isMockSessionAvailable` 에서 `&& !_releaseMode` 제거 | 릴리스 가드 3개 실패. 되돌린 뒤 재통과 |
|
|
|
|
`contrast_checks` 25쌍에는 앱 테마가 조립하며 새로 만드는 3쌍(선택 탭 라벨 9.21:1 ·
|
|
인디케이터 위 선택 라벨 7.93:1 · 인디케이터 위 비선택 라벨 8.05:1)이 포함돼 있다.
|
|
토큰 문서에만 있는 쌍을 검사하면 위젯 테마에서 대비가 무너져도 생성기가 통과를 찍는다(교차검증 A-04).
|
|
|
|
### 토큰 대조 — 시안 CSS ↔ 생성된 Dart
|
|
|
|
`시안/assets/ds.css` 의 `:root` 변수와 `tokens.dart` 의 색 토큰을 값 비교했다.
|
|
|
|
```
|
|
ds.css 변수 119개 · tokens.dart 색 토큰 51개 · 공통 51개
|
|
값 불일치: 0개
|
|
```
|
|
|
|
### 실기기 기동 확인 (Android 에뮬레이터 · API 36)
|
|
|
|
APK 를 설치·실행해 목 모드 기동과 탭 이동을 확인했다. `FATAL EXCEPTION` 0건.
|
|
|
|
```
|
|
$ adb install -r build/app/outputs/flutter-apk/app-debug.apk
|
|
Success
|
|
|
|
$ adb logcat | grep FirebaseBoot
|
|
I flutter : [FirebaseBoot] mode=mock :: Firebase 설정 파일이 없어 목(mock) 모드로 기동했습니다.
|
|
투입 대상: app/android/app/google-services.json
|
|
app/ios/Runner/GoogleService-Info.plist
|
|
I flutter : [FirebaseBoot] detail :: PlatformException(java.lang.Exception: Failed to load
|
|
FirebaseOptions from resource. Check that you have defined values.xml correctly. …)
|
|
```
|
|
|
|
확인한 동선: 로그인 화면 렌더(소셜 4버튼 라벨 일치) → 「목 세션으로 탭 둘러보기」 →
|
|
5탭 셸 진입 → STATION 탭 전환 시 `S-S-HUB` 로 화면 전환.
|
|
<!-- VERIFY:END -->
|
|
|
|
## 10. 알려진 제약
|
|
|
|
<!-- LIMITS:BEGIN -->
|
|
| # | 제약 | 영향 | 해소 시점 |
|
|
|---|---|---|---|
|
|
| L1 | Firebase 설정 파일 미투입 → 목 모드 | **실 소셜 로그인 불가.** 로그인 버튼은 「키 미투입」 안내를 반환 | S2 (3주차 빌드 전) |
|
|
| L2 | `com.google.gms.google-services` Gradle 플러그인 **미적용** | 지금은 이게 정상이다. 설정 파일 없이 플러그인만 적용하면 Gradle 빌드가 실패한다. 파일 투입과 **동시에** `android/settings.gradle.kts` · `android/app/build.gradle.kts` 에 추가해야 한다 | S2 |
|
|
| L3 | 카카오·네이버 SDK 미도입 | 스텁만 있다. 실 연동 시 `kakao_flutter_sdk_user` · 네이버 SDK 추가와 함께 `KeylessSocialProvider` 를 실 구현체로 교체 | Q3 회신 후 |
|
|
| L4 | 폰트 파일 미투입 | 시스템 폰트로 폴백. 크기·굵기·행간·자간은 토큰 값대로 적용됨 | 라이선스 원본 확보 시 |
|
|
| L6 | 탭 아이콘이 Material 기본(Q15) | 시안 탭바에는 아이콘이 없어 대조 대상이 없다 | 3주차 |
|
|
| L7 | **iOS 최소 지원 버전을 13.0 → 15.0 으로 올렸다** | `firebase_auth` 6.x 가 15.0 이상을 요구해 13.0 으로는 `pod install` 이 실패했다. 기준 단말 iPhone 11(S4)은 iOS 18까지 지원하므로 범위 영향 없음. `ios/Podfile` · `Runner.xcodeproj` 3곳 수정 | 반영 완료 |
|
|
| L8 | **릴리스 서명 키 없음 → `flutter build apk --release` 는 의도적으로 실패한다** | 서명 키는 스토어 등록 명의(Q5·S3)가 정해져야 만들 수 있다. Flutter 기본 템플릿은 이 상태에서 **debug 키로 조용히 서명**해 Play 가 거부하는 산출물을 "성공"으로 내놓는다 — 그 경로를 막고 사유를 띄우도록 `android/app/build.gradle.kts` 를 고쳤다. 키가 생기면 `android/key.properties`(storeFile·storePassword·keyAlias·keyPassword)만 놓으면 된다. 해당 파일과 `*.jks`/`*.keystore` 는 `app/android/.gitignore` 가 이미 막고 있다(확인함) | Q5·S3 |
|
|
| L8-1 | debug APK 164,432,730 bytes(약 156.8 MiB) | debug 빌드 특성(미난독화·전 ABI 포함). release + `--split-per-abi` 로 크게 줄어들지만 **L8 때문에 아직 실측하지 못했다** | Q5·S3 |
|
|
| L9 | 첫 Gradle 빌드에서 Kotlin 데몬 경고 1회 | `e: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0` — 자동 재시도로 성공했고 산출물에 영향 없음. 증분 빌드에서는 재현되지 않음 | — |
|
|
| L9-1 | iOS 런치 화면 색 변경은 **컴파일 검증만** 했다 | `LaunchScreen.storyboard` 배경을 흰색 → `color-cosmic-void`(#000)로 바꿨다. Android 는 에뮬레이터에서 눈으로 확인했지만 iOS 는 시뮬레이터 실행을 하지 않아 빌드 성공까지만 확인했다 | 3주차 실기기 빌드 |
|
|
| L10 | 온보딩 6화면 라우트 없음 | S-A-INTRO · S-A-TERMS · S-A-PROFILE · S-A-ARTIST · S-A-PLANET-NEW · S-A-PERMS | 3주차 |
|
|
| L11 | 상태관리 라이브러리 없음 | 골격 범위라 `ChangeNotifier` 하나로 충분하다. 도메인 로직이 들어오는 3주차에 도입 여부를 판단 | 3주차 |
|
|
| L12 | `app/ios/Podfile.lock` 이 리포 `.gitignore` 에 잡혀 있다 | Pod 버전이 고정되지 않아 빌드 재현성이 떨어진다. 커밋 대상으로 되돌릴지 리드 판단 필요 | 리드 확인 |
|
|
|
|
**시연 시 유의** — 실 소셜 로그인은 L1 때문에 동작하지 않는다. 「목 세션으로 탭 둘러보기」로
|
|
탭 이동을 확인하시고, 로그인 자체는 3주차 빌드에서 확인 부탁드립니다.
|
|
<!-- LIMITS:END -->
|