Skip to content

release 1.6.0 #25

Closed
SeongHoonC wants to merge 7 commits into
prodfrom
codex/bump-version-1-6-0
Closed

release 1.6.0 #25
SeongHoonC wants to merge 7 commits into
prodfrom
codex/bump-version-1-6-0

Conversation

@SeongHoonC

@SeongHoonC SeongHoonC commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Bump Expo app version to 1.6.0
  • Bump iOS build number and Android versionCode to 16
  • Align native iOS project version values with Expo config

Validation

  • npm run lint (passes with 5 existing warnings)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • WebView에서 뒤로 가기 및 외부 링크 처리 기능 개선
  • 변경사항

    • 앱 버전 1.6.0으로 업데이트
    • 앱 네비게이션 구조 개선
    • "더보기" 탭 및 "구독" 관련 화면 제거
    • 뒤로 가기 시 기본 경로 변경

seongwon030 and others added 7 commits June 2, 2026 13:37
- (tabs) 탭 레이아웃 및 구독/메뉴 네이티브 화면 제거, app/index.tsx로 홈 웹뷰 단일 호스트
- _layout Stack/anchor를 index로, 상세/웹뷰 back 폴백을 /로 변경
- home-webview-screen에 REQUEST_APP_VERSION→APP_VERSION 핸들러 추가
- ui/subscribe 제거(웹이 대체)
- NAVIGATE_BACK 메시지 수신 시 webView.goBack() (상세 '<' 버튼)
- Android 하드웨어 백: 웹뷰 히스토리 있으면 goBack, 없으면 종료
- iOS 엣지 스와이프 백 제스처 활성화 (allowsBackForwardNavigationGestures)
Resolve conflicts:
- ui/home/home-webview-screen.tsx: keep both canGoBackRef (Android back) and
  loadFailedRef (preload failure tracking); wire onNavigationStateChange together
  with the new handleError for onError/onHttpError
- app/(tabs)/_layout.tsx, app/(tabs)/more.tsx, ui/subscribe/{components/empty-state,subscribe-screen}.tsx:
  keep deletions (native tabs/subscribe removed in favor of single webview shell)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
onShouldStartLoadWithRequest로 moadong.com 외부 URL 탐색을 가로채
/webview/[slug] 화면으로 push — 개인정보처리방침(노션) 등 외부 링크에
네이티브 헤더와 뒤로가기 버튼이 표시됨

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handleShouldStartLoadWithRequest: iOS는 navigationType === 'click'인
  경우(사용자 탭)만 외부 URL로 인터셉트. 초기 로드·서버 리다이렉트('other')는
  통과시켜 스플래시 중 잘못된 화면 전환 방지
- handleMessage NAVIGATE_WEBVIEW: loaded 상태 guard 추가, 첫 로드 완료 전
  웹 페이지의 navigation 메시지 무시
- _layout.tsx: initialPathnameRef로 초기 경로 캡처, preload 중 pathname 변경에
  무관하게 homeWebViewPreloadSettled 조건 유지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: 네이티브 바텀탭 제거 → 단일 웹뷰 셸 + 앱 버전 브릿지
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

앱의 기본 라우팅 구조를 탭 기반에서 WebView 기반 단일 진입점으로 전환합니다. 버전을 1.5.2에서 1.6.0으로, 빌드 번호를 15에서 16으로 일관되게 업데이트하고, WebView 내 네비게이션 제어(뒤로가기, 버전 브릿지, 외부 링크 라우팅)를 강화합니다.

Changes

네비게이션 통합 및 WebView 강화

Layer / File(s) Summary
버전 및 빌드 메타데이터 업데이트
app.json, ios/app.xcodeproj/project.pbxproj, ios/app/Info.plist
앱 공개 버전(1.5.2 → 1.6.0) 및 빌드 번호(15 → 16)가 app.json, iOS Debug/Release 빌드 설정, Info.plist에 걸쳐 일관되게 업데이트됩니다.
루트 라우팅 및 스플래시 제어 재구성
app/_layout.tsx
초기 라우팅 기준점이 (tabs)에서 index로 변경되고, 홈 WebView preload 상태에 기반해 스플래시 차단 조건이 최초 라우트 기준으로 재평가됩니다. 네비게이션 스택의 루트 스크린도 함께 업데이트됩니다.
홈 화면 및 WebView 폴백 라우팅 업데이트
app/index.tsx, app/(tabs)/explore.tsx, app/webview/[slug].tsx, ui/club-detail/club-detail-screen.tsx
홈 화면 함수명이 HomeTab에서 Home으로 변경되고, 구독 화면 임포트가 제거되며, 뒤로 갈 수 없을 때의 폴백 경로가 /(tabs)/more에서 /로 통일됩니다.
WebView 네비게이션 제어 및 브릿지 확장
ui/home/home-webview-screen.tsx
WebView 메시지 핸들러에 NAVIGATE_BACK(히스토리 뒤로가기), REQUEST_APP_VERSION(앱 버전 전달), onShouldStartLoadWithRequest(외부 링크 가로채 /webview/[slug]로 라우팅)이 추가되고, Android 하드웨어 뒤로가기에서 WebView 히스토리 상태를 확인해 처리합니다.

Sequence Diagram

sequenceDiagram
  participant WebView as WebView 콘텐츠
  participant Handler as handleMessage
  participant Screen as HomeWebViewScreen
  participant NavState as 네비게이션<br/>상태 추적
  participant Router as 라우터
  participant Device as 디바이스<br/>(Android)
  
  WebView->>Handler: postMessage<br/>(NAVIGATE_BACK)
  Handler->>Screen: webViewRef.goBack()
  
  WebView->>Handler: postMessage<br/>(REQUEST_APP_VERSION)
  Handler->>Screen: postMessage(APP_VERSION,<br/>Constants.expoConfig?.version)
  Screen->>WebView: 앱 버전 전송
  
  WebView->>Screen: onShouldStartLoadWithRequest<br/>(외부 URL 로드)
  Screen->>NavState: onNavigationStateChange<br/>추적(canGoBack)
  
  alt 사용자 동작으로 판정<br/>(iOS: click / Android,Web: loaded)
    Screen->>Router: router.push(/webview/[slug]<br/>?external=true)
  else 자동 네비게이션
    Screen->>Screen: 로드 차단
  end
  
  Device->>NavState: 하드웨어<br/>뒤로 버튼 감지
  alt canGoBackRef = true
    NavState->>Screen: webViewRef.goBack()
  else canGoBackRef = false
    NavState->>Router: 기본 동작<br/>(뒤로 종료)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Moadong/moadong-react-native#21: 네이티브 탭 네비게이터 제거(app/(tabs)/_layout.tsx, more.tsx 삭제), 라우팅 앵커 변경(anchor: 'index'), WebView 뒤로가기 및 버전 브릿지 추가, 폴백 경로 변경이 동일한 코드 위치에서 일어납니다.
  • Moadong/moadong-react-native#22: 두 PR 모두 app/_layout.tsx의 초기 라우팅 및 스플래시 제어 로직(초기 화면 기준, 스플래시 유지 조건 평가)을 수정해 동일한 코드 경로를 다룹니다.
  • Moadong/moadong-react-native#24: 홈 WebView 스플래시/프리로드 흐름(app/_layout.tsx) 및 iOS/Android 빌드 메타데이터(app.json, ios/app/Info.plist)를 동시에 변경합니다.

Suggested reviewers

  • seongwon030
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목 'release 1.6.0'은 버전 범프라는 주요 변경사항을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/bump-version-1-6-0

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed due to a network error.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SeongHoonC SeongHoonC changed the title [codex] Bump app version to 1.6.0 release 1.6.0 Jun 13, 2026
@SeongHoonC SeongHoonC marked this pull request as ready for review June 13, 2026 07:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
ui/home/home-webview-screen.tsx (1)

108-113: ⚡ Quick win

브릿지 메시지 타입을 공용 계약으로 통합해 주세요.

REQUEST_APP_VERSION/APP_VERSION이 로컬 문자열 switch에만 있어 메시지 타입 계약이 분산됩니다. types/webview-message.types.ts와 공용 상수에 함께 반영해 타입/런타임 동기화를 유지하는 편이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/home/home-webview-screen.tsx` around lines 108 - 113, The code uses
literal message types ('REQUEST_APP_VERSION' and 'APP_VERSION') in the switch
and sendMessage call which spreads the message-type contract; update the
implementation to use the shared message-type constants/types from
types/webview-message.types.ts instead of hardcoded strings: import the exported
enum/consts (e.g., REQUEST_APP_VERSION, APP_VERSION or WebviewMessageType) and
replace the literal case label and sendMessage type field with those constants
so the runtime values match the shared type definitions and keep compile-time
synchronization via the shared types.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/_layout.tsx`:
- Around line 65-69: The ATT permission request currently runs after the splash
is released; move the ATT step to run before runBootstrapSequence so the
bootstrap order becomes: (1) Firebase remote-config forced update check, (2) iOS
ATT permission request, (3) access token retrieval/creation, (4) FCM token
registration, (5) subscribed clubs sync, (6) Mixpanel init; update the bootstrap
flow invoked by runBootstrapSequence (and any code gated by
shouldBlockSplash/homeWebViewPreloadSettled) to perform the ATT request as the
second step and ensure the UI remains blocked until runBootstrapSequence
completes.

In `@ui/home/home-webview-screen.tsx`:
- Around line 145-163: The code in handleShouldStartLoadWithRequest uses string
startsWith on baseOrigin which allows host prefix attacks; change the check to
parse the request.url with the URL constructor and compare urlObj.origin
strictly against the configured base origin (build baseOrigin as new
URL(process.env.EXPO_PUBLIC_WEBVIEW_URL ?? 'https://moadong.com').origin),
handle invalid URLs with try/catch (treat invalid/ unparsable URLs as external),
and then use that boolean in the existing user-initiated logic (keep
Platform.OS, loaded, and router.push usage unchanged).

---

Nitpick comments:
In `@ui/home/home-webview-screen.tsx`:
- Around line 108-113: The code uses literal message types
('REQUEST_APP_VERSION' and 'APP_VERSION') in the switch and sendMessage call
which spreads the message-type contract; update the implementation to use the
shared message-type constants/types from types/webview-message.types.ts instead
of hardcoded strings: import the exported enum/consts (e.g.,
REQUEST_APP_VERSION, APP_VERSION or WebviewMessageType) and replace the literal
case label and sendMessage type field with those constants so the runtime values
match the shared type definitions and keep compile-time synchronization via the
shared types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2dba77ee-fc48-45d4-b038-7af73900dd6a

📥 Commits

Reviewing files that changed from the base of the PR and between 2f4516f and 3079f01.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • app.json
  • app/(tabs)/_layout.tsx
  • app/(tabs)/explore.tsx
  • app/(tabs)/index.tsx.backup
  • app/(tabs)/more.tsx
  • app/_layout.tsx
  • app/index.tsx
  • app/webview/[slug].tsx
  • ios/app.xcodeproj/project.pbxproj
  • ios/app/Info.plist
  • ui/club-detail/club-detail-screen.tsx
  • ui/home/home-webview-screen.tsx
  • ui/subscribe/components/empty-state.tsx
  • ui/subscribe/components/index.ts
  • ui/subscribe/components/subscribed-club-list.tsx
  • ui/subscribe/hook/index.ts
  • ui/subscribe/hook/use-subscribe-screen.ts
  • ui/subscribe/index.ts
  • ui/subscribe/subscribe-screen.tsx
💤 Files with no reviewable changes (11)
  • ui/subscribe/hook/index.ts
  • ui/subscribe/components/empty-state.tsx
  • app/(tabs)/_layout.tsx
  • app/(tabs)/index.tsx.backup
  • ui/subscribe/subscribe-screen.tsx
  • ui/subscribe/components/index.ts
  • app/(tabs)/more.tsx
  • app/(tabs)/explore.tsx
  • ui/subscribe/hook/use-subscribe-screen.ts
  • ui/subscribe/components/subscribed-club-list.tsx
  • ui/subscribe/index.ts

Comment thread app/_layout.tsx
Comment on lines 65 to 69
const shouldBlockSplash =
forceUpdateRequired ||
!bootstrapSucceeded ||
(shouldWaitForHomeWebView && !homeWebViewPreloadSettled);
(initialPathnameRef.current === '/' && !homeWebViewPreloadSettled);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

ATT 요청 순서가 루트 부트스트랩 계약과 다릅니다.

현재 ATT 요청은 스플래시 해제 이후에만 실행되어, access token/FCM/구독/Mixpanel 초기화보다 늦게 호출됩니다. ATT 단계를 runBootstrapSequence 이전으로 이동해 가이드 순서를 맞춰 주세요.

🔧 제안 수정 예시
-        // 2) Access Token -> FCM/구독 목록/Mixpanel 병렬 부트스트랩
-        await runBootstrapSequence();
+        // 2) iOS ATT 권한 요청
+        await requestTrackingPermissionAfterLaunch();
+        // 3) Access Token -> FCM/구독 목록/Mixpanel 초기화
+        await runBootstrapSequence();
-  useEffect(() => {
-    if (!bootstrapSucceeded || forceUpdateRequired || showSplash || Platform.OS !== 'ios') {
-      return;
-    }
-    ...
-  }, [bootstrapSucceeded, forceUpdateRequired, showSplash]);
+  // ATT는 prepare() 내부 순서에서 처리

As per coding guidelines, app/_layout.tsx must execute bootstrap in order: (1) Firebase Remote Config forced update check, (2) iOS ATT permission request, (3) access token retrieval/creation, (4) FCM token registration, (5) subscribed clubs list sync, (6) Mixpanel analytics initialization, and block UI until bootstrap completes.

Also applies to: 117-141, 177-195

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/_layout.tsx` around lines 65 - 69, The ATT permission request currently
runs after the splash is released; move the ATT step to run before
runBootstrapSequence so the bootstrap order becomes: (1) Firebase remote-config
forced update check, (2) iOS ATT permission request, (3) access token
retrieval/creation, (4) FCM token registration, (5) subscribed clubs sync, (6)
Mixpanel init; update the bootstrap flow invoked by runBootstrapSequence (and
any code gated by shouldBlockSplash/homeWebViewPreloadSettled) to perform the
ATT request as the second step and ensure the UI remains blocked until
runBootstrapSequence completes.

Source: Coding guidelines

Comment on lines +145 to +163
const handleShouldStartLoadWithRequest = useCallback(
(request: ShouldStartLoadRequest) => {
const baseOrigin = (process.env.EXPO_PUBLIC_WEBVIEW_URL ?? 'https://moadong.com').replace(/\/$/, '');
if (request.url.startsWith('http') && !request.url.startsWith(baseOrigin)) {
// iOS: navigationType === 'click' 은 사용자가 직접 링크를 탭한 경우만 해당
// 초기 로드·서버 리다이렉트는 'other' 이므로 인터셉트하지 않음
// Android: navigationType이 항상 'other'이므로 loaded 상태로 구분
const isUserInitiated = Platform.OS === 'ios'
? request.navigationType === 'click'
: loaded;
if (isUserInitiated) {
router.push({ pathname: '/webview/[slug]', params: { slug: 'external', url: request.url } });
return false;
}
return true;
}
return true;
},
[router, loaded],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

외부 URL 판별에 startsWith를 쓰면 도메인 prefix 우회가 가능합니다.

https://moadong.com.evil.tld 같은 URL이 내부 도메인으로 오인되어 WebView에 그대로 로드될 수 있습니다. URL.origin 기반의 엄격 비교로 바꿔 주세요.

🔒 제안 수정 예시
-      const baseOrigin = (process.env.EXPO_PUBLIC_WEBVIEW_URL ?? 'https://moadong.com').replace(/\/$/, '');
-      if (request.url.startsWith('http') && !request.url.startsWith(baseOrigin)) {
+      const baseOrigin = new URL(process.env.EXPO_PUBLIC_WEBVIEW_URL ?? 'https://moadong.com').origin;
+      let requestOrigin: string | null = null;
+      if (request.url.startsWith('http://') || request.url.startsWith('https://')) {
+        try {
+          requestOrigin = new URL(request.url).origin;
+        } catch {
+          return false;
+        }
+      }
+      if (requestOrigin && requestOrigin !== baseOrigin) {
         const isUserInitiated = Platform.OS === 'ios'
           ? request.navigationType === 'click'
           : loaded;
         if (isUserInitiated) {
           router.push({ pathname: '/webview/[slug]', params: { slug: 'external', url: request.url } });
           return false;
         }
         return true;
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/home/home-webview-screen.tsx` around lines 145 - 163, The code in
handleShouldStartLoadWithRequest uses string startsWith on baseOrigin which
allows host prefix attacks; change the check to parse the request.url with the
URL constructor and compare urlObj.origin strictly against the configured base
origin (build baseOrigin as new URL(process.env.EXPO_PUBLIC_WEBVIEW_URL ??
'https://moadong.com').origin), handle invalid URLs with try/catch (treat
invalid/ unparsable URLs as external), and then use that boolean in the existing
user-initiated logic (keep Platform.OS, loaded, and router.push usage
unchanged).

@SeongHoonC SeongHoonC closed this Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants