Skip to content

[fix] 알림 진입 시 토큰 재발급 경쟁 로그아웃 해결 및 INTIP 잔재 정리 - #49

Merged
hjunieee merged 8 commits into
mainfrom
refactor/rename-intip-to-unidorm
Oct 24, 2026
Merged

hjunieee merged 8 commits into
mainfrom
refactor/rename-intip-to-unidorm

Conversation

@hjunieee

@hjunieee hjunieee commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

개요 및 배경

오랫동안 앱을 쓰지 않다가 채팅 푸시 알림으로 진입하면 로그아웃되는 문제를 해결하고, 같은 흐름에서 WebViewContainer 구조 정리와 INTIP 앱에서 복사해 온 잔재 정리를 함께 담았습니다.

알림으로 콜드 스타트하면 루트 웹뷰와 채팅 서브 웹뷰가 동시에 뜨고, accessToken(7시간)이 만료된 상태라면 두 웹뷰가 같은 refreshToken으로 동시에 재발급을 요청합니다. 서버는 재발급 때마다 refreshToken을 교체(rotation)하므로 늦은 쪽이 거절되어 /logout으로 이동했습니다. 그냥 앱을 켤 때는 루트 웹뷰 하나만 재발급해서 문제가 없었습니다.

주요 변경 사항

1. 토큰 재발급을 네이티브 한 곳으로 (2aece66)

  • 브릿지에 requestTokenRefresh / tokenRefreshResult 요청-응답 추가
  • refreshWithToken: 진행 중 요청에 합류하고, 직전 교체 결과를 재사용해 같은 토큰으로 서버를 한 번만 호출. 결과는 tokenInfoUpdated로 모든 웹뷰에 전파
  • 재발급 시 만료 시각을 JWT exp에서 읽어 저장 (기존에는 이전 값 유지)
  • 페이지 로드 전 window.__unidormNativeFeatures로 tokenRefresh 지원을 알림 → 웹은 이 값이 있을 때만 네이티브에 위임하고, 구버전 앱·브라우저에서는 기존처럼 직접 재발급

2. WebViewContainer를 관심사별 훅으로 분리 (9b3cca8)

동작 변경 없이 브릿지 핸들러, 루트 생명주기, 푸시 라우팅, 토큰 동기화, 주입 스크립트를 src/components/webview/ 아래 훅으로 나눴습니다.

3. INTIP 잔재 정리 (f79df5b, 06d3872, 6d7e5c1, 17b3cfe)

  • iOS 스크립트 기본 bundle ID가 INTIP 앱(kr.inuappcenter.intip)으로 되어 있던 것을 com.inuappcenter.unidorm으로 수정
  • withIOSManualSigning의 대상 타깃 "INTIP" → "app" (prebuild가 만드는 실제 타깃명. 기존에는 수동 서명 설정이 적용되지 않았을 가능성)
  • Android 패키지, 도메인, URL 스킴, 표시 이름, Firebase 프로젝트, 키스토어 파일명, 학교 시스템 요청 User-Agent 등을 유니돔 값으로 수정
  • packages/intip-bridge → packages/unidorm-bridge(@unidorm/bridge), modules/intip-* → modules/unidorm-*, 주입 스크립트 전역 __intip* → __unidorm*
  • 브릿지를 INTIP 원본 저장소의 서브모듈로 가리키던 .gitmodules 항목·배포 설정 제거 (이 저장소의 packages/unidorm-bridge가 원본)
  • 딥링크의 intipmobileapp://·intip:// 수용 제거 (출시된 앱에서 쓴 적 없음)
  • 사용처 없는 INTIP 버킷 업로드 스크립트 3개, INTIP 전용 문서 2개 삭제

출시된 앱 호환

  • 포털 계정: SecureStore 키 intip_portal_* → unidorm_portal_*. 새 키에 없으면 옛 키에서 읽어 옮기고 옛 키를 지우므로 사용자가 다시 입력할 필요가 없습니다.
  • 웹이 부르는 옛 이름 __intipRequestCameraPermission, intipAgentResult는 새 이름과 함께 계속 정의·발송합니다. 웹 배포 후 지워도 된다고 주석에 적었습니다.
  • 변경은 모두 JS라 OTA로 배포 가능하며, 웹과 앱의 배포 순서는 상관없습니다.

웹 쪽 짝 PR

UNIDorm-web#389에 웹 변경(재발급 위임, 브릿지 계약 통일, INTIP 잔재 정리)이 있습니다.

검증 결과

  • Jest 26개 스위트, 228개 테스트 통과 (재발급 단일화 6개, 포털 계정 키 이전 4개 추가)
  • tsc --noEmit 통과, eslint 오류 없음
  • 기기 테스트와 expo prebuild/네이티브 빌드는 아직 하지 않았습니다. 확인 방법: 앱을 7시간 넘게 쓰지 않은 상태에서 채팅 알림으로 진입했을 때 로그아웃되지 않으면 해결

🤖 Generated with Claude Code

hjunieee and others added 7 commits October 24, 2026 19:38
알림으로 콜드 스타트하면 루트 웹뷰와 채팅 서브 웹뷰가 같은 refreshToken으로
동시에 재발급을 요청하고, 서버의 refreshToken 교체(rotation) 때문에 늦은 쪽이
거절되어 로그아웃되던 문제를 해결한다.

- 브릿지에 requestTokenRefresh / tokenRefreshResult 요청-응답 추가
- 네이티브 refreshWithToken: 진행 중 요청 합류 + 직전 교체 결과 재사용으로
  같은 토큰에 대해 서버를 한 번만 호출하고, 결과를 모든 웹뷰에 전파
- 재발급 시 만료 시각을 JWT exp에서 읽어 저장 (기존에는 이전 값 유지)
- 페이지 로드 전 window.__intipNativeFeatures 주입, "tokenRefresh" 기능 광고

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Behaviour-preserving split of the ~1,280-line container into hooks under
src/components/webview/; the component stays the composition root.

- useBridgeHandlers: channel.on(...) effect + onWebViewMessage routing
- useRootLifecycle: cache clear, foreground notifications, notification-open
  subscription, initial nav intent, FCM refresh/resume re-post, launch overlay
  timeout, native-stack navigator registration
- useNavIntentRouting: handleNavIntent, pendingPush/pendingNav/notificationOpened
  queues, share-intent and navigator-ready effects
- useTokenSync: adoptWebToken, token probe, sendTokenInfo + localStorage script
- useFcmToken: postFcmToken / deliverFcmToken
- usePermissionPriming: camera/location priming + media-route effect
- useInjectedScripts: before-content/document-end scripts, insets + band re-push
- useRegistryHandle, useSystemBack, useSpaNavigation, useRevealOverlay,
  useLoadRequestGuard, useBackGestureGuard

Fixes the three existing react-hooks/exhaustive-deps warnings (all
dependencies added are stable or already transitively present).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
intip-mobile-app을 복사해 시작하면서 남은 INTIP 앱의 식별자·도메인·이름을
유니돔 값으로 바꾼다. 구버전 iOS 앱(UNIDorm-iOS)과 app.json/app.config.js,
codemagic.yaml의 값을 기준으로 했다.

- iOS 스크립트 기본 bundle ID: kr.inuappcenter.intip(.dev) → com.inuappcenter.unidorm(.dev)
  (인자 없이 실행하면 INTIP 앱의 App Store 설정을 건드리던 문제)
- withIOSManualSigning의 대상 타깃 "INTIP" → "app" (prebuild가 만드는 실제 타깃명)
- Android 패키지, 도메인, URL 스킴, 표시 이름, Firebase 프로젝트(uni-dorm),
  키스토어 파일명(unidorm.jks), 프로비저닝 프로파일/산출물 이름 정리
- 학교 시스템 요청 User-Agent 접미사 INTIP-Mobile → UNIDorm-Mobile
- 문서의 INTIP 표기·API 호스트 표를 유니돔 기준으로 수정
- INTIP 앱 마이그레이션 명세(docs/requirement-scratch.md) 삭제

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- packages/intip-bridge → packages/unidorm-bridge, 패키지명 @unidorm/bridge
  (웹 복사본과 이름·내용 일치)
- modules/intip-{native-dialog,system-gestures} → modules/unidorm-*,
  모듈명 Unidorm*Module (두 모듈 모두 네이티브 구현 없이 폴백만 동작)
- 주입 스크립트·마커 전역 __intip* → __unidorm*
- 웹이 부르는 이름은 구버전 웹 호환을 위해 함께 유지:
  __intipRequestCameraPermission 별칭, intipAgentResult 이벤트 병행 발송
- 주석·문서·테스트 URL의 intip 표기 정리
- INTIP 앱 심사 거부 대응 문서(docs/requirement-content-moderation.md) 삭제

딥링크의 intipmobileapp:// / intip:// 수용, 기존 저장 키, 브릿지 원본 저장소
URL은 호환을 위해 그대로 둔다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 딥링크에서 intipmobileapp:// / intip:// 스킴 수용 제거
  (유니돔 앱은 이 스킴을 쓴 적이 없음)
- INTIP 버킷을 가리키던 개발 산출물 업로드 스크립트 3개 삭제
  (garage-put.sh, s3-smoke-test.sh, make-dev-install-page.sh — 사용처 없음)
- 브릿지를 INTIP 원본 저장소의 서브모듈로 가리키던 .gitmodules 항목과
  package.json repository 제거: 이 저장소의 packages/unidorm-bridge가 원본
- AGENTS.md, development.md, 주석의 서브모듈 설명을 현재 구조에 맞게 수정

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 포털 학번·비밀번호 SecureStore 키: intip_portal_* → unidorm_portal_*.
  이미 출시된 앱의 사용자가 다시 입력하지 않도록, 새 키에 없으면 옛 키에서
  읽어 새 키에 쓰고 옛 키를 지운다. 계정 해제 시에는 두 키 모두 지운다.
- 웹이 부르는 옛 이름(__intipRequestCameraPermission, intipAgentResult)에
  지워도 되는 조건을 주석으로 명시
- 브릿지의 GitHub Packages 배포 워크플로·publishConfig 삭제,
  README의 서브모듈·배포 안내를 현재 구조에 맞게 수정

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Icon Composer 레이어 이미지의 로고가 1024px 캔버스에서 가로 약 55%만
차지하고 있어 예전 앱보다 작게 보였다. 예전 네이티브 iOS 앱(UNIDorm-iOS)의
1024px 원본 아이콘(로고 약 80%, 배경색 동일)으로 교체하고, 개발용 아이콘도
같은 원본에 DEV 배지를 얹어 다시 만들었다. Android 적응형 아이콘은 그대로.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hjunieee
hjunieee merged commit af1e706 into main Oct 24, 2026
1 check passed
@hjunieee
hjunieee deleted the refactor/rename-intip-to-unidorm branch October 24, 2026 18:20
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.

1 participant