Skip to content

[Feat/111] WebView 앱(Android/iOS) 출시 및 푸시/웹훅 구축 - #115

Merged
hamlsy merged 32 commits into
mainfrom
feat/111
Mar 23, 2026
Merged

[Feat/111] WebView 앱(Android/iOS) 출시 및 푸시/웹훅 구축#115
hamlsy merged 32 commits into
mainfrom
feat/111

Conversation

@hamlsy

@hamlsy hamlsy commented Mar 23, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added mobile app support for Android and iOS platforms via Capacitor
    • Implemented push notifications for mobile users
    • Added deep link support for app navigation and OAuth callbacks
    • Enabled anonymous user trial mode to explore the game without logging in
    • Introduced interactive tutorial system for first-time users
    • Enhanced hero section and onboarding experience for non-logged-in visitors
  • Improvements

    • Implemented mobile-optimized OAuth2 authentication flow
    • Modernized authentication token management

hamlsy and others added 30 commits March 17, 2026 14:29
-----
roadviewmain
ranking modal
practiceView
등 각 컴포넌트에 대한 접근 및 로그인 유도, 손실 회피율 증가
- HeroSection: 비로그인 시 항상 표시, 그라디언트 배경에 3단계 플로우·통계 안내
- IntroTutorialModal: 마지막 슬라이드에 '바로 체험하기' CTA 추가, skipTutorial 시 complete 이벤트 발행
- MainView: hero-banner-wrapper 복원, 모드 카드 색상 경량화, 튜토리얼 자동 실행 로직
- PracticeView: 인게임 순차 튜토리얼 힌트 4단계 추가 (로드뷰→지도열기→위치찍기→SPOT제출)
  - 힌트 버튼 사용 안내 보너스 힌트 포함
  - 체험하기 진입 시 매번 활성화, 반응형 지원

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- PracticeView: 힌트 말풍선을 slot 내부로 이동해 힌트 버튼 가림 버그 수정
- PracticeView: 새로고침 버튼 말풍선 추가 (지도 첫 오픈 시 5초 노출)
- PracticeView: 게임 시작 10초 후 Spot 제출 안내 말풍선 추가 (바운스 화살표)
- PracticeView: '지도에서 위치를 찍어보세요' → '지도에서 정답 위치를 찍어보세요'
- PracticeResultOverlay: 비회원 손실 회피 CTA를 결과창 맨 위로 이동
- MainView: 비로그인 로드뷰 카드 클릭 시 연습 모드 직행 → RoadViewMainView로 변경
- HeroSection: 3단계 플로우 및 CTA 버튼을 clamp() 기반 반응형으로 개편, 모바일에서 항상 가로 표시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
[Feat/113] 로드뷰 연습 모드 익명(비회원) 플레이 지원 및 온보딩 개선
- Android Manifest에 POST_NOTIFICATIONS, RECEIVE_BOOT_COMPLETED 권한 추가
- Android Manifest에 kospot:// OAuth 딥링크 intent-filter 추가
- capacitor.config.json에 iosScheme: "https" 추가 (CORS origin 일치)
- ios/App/App/Info.plist에 CFBundleURLSchemes kospot 등록

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- push.service.js: FCM 토큰 localStorage 저장 (로그아웃 시 삭제용)
- useAuth.js: 로그아웃 시 FCM 토큰 서버 삭제 후 localStorage 제거
- App.vue: onNotificationReceived 핸들러 추가 (포그라운드 수신 → 토스트)
- notificationTypes.js: GAME_INVITE, LEVEL_UP 타입 추가
- AccountSettings.vue: 미구현 알림 토글 disabled 처리 + 준비중 배지 표시
- AccountSettings.vue: alert() → notificationStore.addNotification() 토스트로 교체

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
hamlsy and others added 2 commits March 23, 2026 17:21
구현 완료된 항목 상태 반영:
- AndroidManifest, capacitor.config, Info.plist, useAuth, App.vue,
  AccountSettings, notificationTypes 완료 표시
- Firebase 설정 파일 및 환경변수는 개발자 직접 작업 필요 명시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@hamlsy
hamlsy merged commit a3ade2e into main Mar 23, 2026
1 of 2 checks passed
@hamlsy
hamlsy deleted the feat/111 branch March 23, 2026 08:42
@coderabbitai

coderabbitai Bot commented Mar 23, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7aa3a878-f90f-4532-a4ec-186593135829

📥 Commits

Reviewing files that changed from the base of the PR and between 48ef590 and 4af3c31.

⛔ Files ignored due to path filters (32)
  • android/app/src/main/res/drawable-land-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-xxxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-xxxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable/splash.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
  • ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png is excluded by !**/*.png
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (108)
  • .claude/settings.local.json
  • .github/workflows/mobile-android.yml
  • .github/workflows/mobile-ios.yml
  • .gitignore
  • .omc/project-memory.json
  • .omc/sessions/1f19dd6d-29f3-4f1d-9696-e6d063be7a2b.json
  • .omc/state/agent-replay-fa91cb7e-ea0f-49ba-a390-29ada7da1cd5.jsonl
  • .omc/state/checkpoints/checkpoint-2026-03-23T02-24-26-251Z.json
  • .omc/state/checkpoints/checkpoint-2026-03-23T08-13-04-511Z.json
  • .omc/state/idle-notif-cooldown.json
  • .omc/state/last-tool-error.json
  • .omc/state/mission-state.json
  • .omc/state/subagent-tracking.json
  • CLAUDE.md
  • KoSpot-frontend-private
  • README.md
  • android/.gitignore
  • android/app/.gitignore
  • android/app/build.gradle
  • android/app/capacitor.build.gradle
  • android/app/proguard-rules.pro
  • android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
  • android/app/src/main/AndroidManifest.xml
  • android/app/src/main/java/com/kospot/app/MainActivity.java
  • android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  • android/app/src/main/res/drawable/ic_launcher_background.xml
  • android/app/src/main/res/layout/activity_main.xml
  • android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  • android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  • android/app/src/main/res/values/ic_launcher_background.xml
  • android/app/src/main/res/values/strings.xml
  • android/app/src/main/res/values/styles.xml
  • android/app/src/main/res/xml/file_paths.xml
  • android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java
  • android/build.gradle
  • android/capacitor.settings.gradle
  • android/gradle.properties
  • android/gradle/wrapper/gradle-wrapper.properties
  • android/gradlew
  • android/gradlew.bat
  • android/settings.gradle
  • android/variables.gradle
  • capacitor.config.json
  • config/env.template
  • docs/ENVIRONMENT_SETUP.md
  • docs/MOBILE_APP_DESKTOP_TESTING_GUIDE.md
  • docs/OAUTH2_MOBILE_FLOW_GUIDE.md
  • docs/mobile-web-app-release-master-plan.md
  • ios/.gitignore
  • ios/App/App.xcodeproj/project.pbxproj
  • ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  • ios/App/App/AppDelegate.swift
  • ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
  • ios/App/App/Assets.xcassets/Contents.json
  • ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
  • ios/App/App/Base.lproj/LaunchScreen.storyboard
  • ios/App/App/Base.lproj/Main.storyboard
  • ios/App/App/Info.plist
  • ios/App/Podfile
  • package.json
  • plans/mobile-app-release-10step-execution-plan.md
  • plans/mobile-build-and-test-guide.md
  • plans/onboarding-anonymous-user-funnel.md
  • plans/onboarding-improvement.md
  • plans/push-notification-backend-tasks.md
  • plans/push-notification-frontend-plan.md
  • plans/regression-baseline-checklist.md
  • public/index.html
  • src/App.vue
  • src/core/api/apiClient.js
  • src/core/api/endPoint.js
  • src/core/api/mobile.api.js
  • src/core/auth/authStorage.service.js
  • src/core/auth/oauth.service.js
  • src/core/composables/useAuth.js
  • src/core/constants/notificationTypes.js
  • src/core/platform/deeplink.service.js
  • src/core/platform/navigation.service.js
  • src/core/platform/push.service.js
  • src/core/platform/runtime.js
  • src/core/platform/websocketUrl.js
  • src/core/services/appWebSocket.service.js
  • src/core/services/notificationWebSocket.service.js
  • src/core/services/tokenRefresh.service.js
  • src/features/admin/components/Banner/BannerManager.vue
  • src/features/auth/views/LoginView.vue
  • src/features/auth/views/OAuthCallbackView.vue
  • src/features/friend/services/friendWebSocket.service.js
  • src/features/game/multiplayer/roadview/views/BaseGameView.vue
  • src/features/game/multiplayer/room/views/RoomView.vue
  • src/features/game/shared/components/Kakao/KakaoMapGame/composables/useKakaoMapControls.js
  • src/features/game/single/main/components/DailyMvpCard.vue
  • src/features/game/single/main/components/RankingModal.vue
  • src/features/game/single/main/views/RoadViewMainView.vue
  • src/features/game/single/roadview/components/Result/PracticeResultOverlay.vue
  • src/features/game/single/roadview/services/roadViewApi.service.js
  • src/features/game/single/roadview/views/PracticeView.vue
  • src/features/intro/components/HeroSection.vue
  • src/features/intro/components/IntroTutorialModal.vue
  • src/features/main/components/UserLoginCard.vue
  • src/features/main/views/MainView.vue
  • src/features/shop/services/shop.service.js
  • src/features/shop/views/ShopView.vue
  • src/features/user/components/AccountSettings.vue
  • src/features/user/view/ProfileView.vue
  • src/router/index.js
  • src/router/userRoutes.js
  • src/shared/utils/common-styles.css

📝 Walkthrough

Walkthrough

This pull request introduces comprehensive mobile application support to the KoSpot frontend by integrating Capacitor for iOS and Android builds, implementing mobile-specific OAuth flows with one-time code exchange, establishing push notification infrastructure, and adding deep-linking capabilities. It includes native build configurations, platform-detection services, enhanced authentication handling, and extensive documentation for mobile deployment and testing workflows.

Changes

Cohort / File(s) Summary
Mobile Build Configuration (Android)
android/build.gradle, android/gradle.properties, android/settings.gradle, android/variables.gradle, android/gradle/wrapper/gradle-wrapper.properties, android/gradlew, android/gradlew.bat, android/capacitor.settings.gradle, android/app/build.gradle, android/app/capacitor.build.gradle, android/app/proguard-rules.pro
Gradle build configuration for Android project including SDK versions, dependencies (AndroidX, Capacitor plugins), wrapper settings, and build flags.
Mobile Build Configuration (Android Resources & Manifests)
android/app/src/main/AndroidManifest.xml, android/app/src/main/java/com/kospot/app/MainActivity.java, android/app/src/main/res/...
Android app entry point, manifest with deep-link schemes, drawable resources (app icons/launcher backgrounds), layout XML, strings, styles, and file provider configuration.
Mobile Build Configuration (Android Tests)
android/app/src/test/java/.../*.java, android/app/src/androidTest/java/.../*.java
Unit and instrumentation test scaffolding for Android app.
Mobile Build Configuration (Android Git Ignore)
android/.gitignore, android/app/.gitignore
Ignore rules for Android build outputs, IDE artifacts, and generated files.
Mobile Build Configuration (iOS)
ios/App/App.xcodeproj/project.pbxproj, ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist, ios/App/Podfile
Xcode project configuration, CocoaPods dependencies (Capacitor, push notifications), and workspace settings.
Mobile Build Configuration (iOS App Delegate & Resources)
ios/App/App/AppDelegate.swift, ios/App/App/Assets.xcassets/..., ios/App/App/Base.lproj/..., ios/App/App/Info.plist
iOS app lifecycle management, storyboards (launch/main), asset catalogs, app configuration, and URL schemes.
Mobile Build Configuration (iOS Git Ignore)
ios/.gitignore
Ignore rules for iOS build outputs, derived data, and CocoaPods artifacts.
GitHub Actions Mobile Build Workflows
.github/workflows/mobile-android.yml, .github/workflows/mobile-ios.yml
Manual-trigger workflows for building Android debug APK and iOS app on simulator, with Node/Gradle/Xcode setup and artifact uploads.
Capacitor Configuration
capacitor.config.json
Capacitor app metadata (app ID, name, web assets directory, URL schemes for Android/iOS).
Platform & Runtime Services
src/core/platform/runtime.js, src/core/platform/websocketUrl.js, src/core/platform/deeplink.service.js, src/core/platform/navigation.service.js, src/core/platform/push.service.js
Runtime platform detection (native vs web, Android vs iOS), WebSocket URL resolution, deep-link URL parsing and Capacitor listener registration, external URL opening, and push notification lifecycle management (registration, preference updates, token deletion).
Authentication Services
src/core/auth/authStorage.service.js, src/core/auth/oauth.service.js
Centralized token/auth state storage with localStorage abstraction and safe get/set wrappers; OAuth authorization URL building with mobile platform detection and query parameter injection.
API Client & Endpoints
src/core/api/apiClient.js, src/core/api/endPoint.js, src/core/api/mobile.api.js
Updated API client to use authStorage instead of direct localStorage; added mobile OAuth exchange endpoint (/auth/mobile/exchange) and mobile API endpoints for push token management (/mobile/push-tokens, /mobile/push-preference).
Core Services Updates
src/core/services/appWebSocket.service.js, src/core/services/notificationWebSocket.service.js, src/core/services/tokenRefresh.service.js, src/core/composables/useAuth.js
Updated WebSocket connections to use authStorage and resolveSockJsUrl(); token refresh to use centralized storage and hardRedirect(); auth composable refactored to use authStorage, add push registration on login, and token cleanup on logout.
Notification Constants & Types
src/core/constants/notificationTypes.js
Added GAME_INVITE and LEVEL_UP notification types with metadata (labels, icons, colors).
Authentication Views
src/features/auth/views/LoginView.vue, src/features/auth/views/OAuthCallbackView.vue
LoginView: added privacy notice and updated OAuth redirect to use buildOAuthAuthorizeUrl() with platform-conditional behavior (external URL for native app, hard redirect for web). OAuthCallbackView: added mobile OAuth one-time code exchange flow with fallback to legacy token-based flow, token persistence via authStorage, push registration, and router-based navigation.
Intro & Onboarding Components
src/features/intro/components/HeroSection.vue, src/features/intro/components/IntroTutorialModal.vue, src/features/main/components/UserLoginCard.vue, src/features/main/views/MainView.vue
HeroSection: redesigned for non-logged-in users with gradient background and game flow UI. IntroTutorialModal: added "try without login" CTA. UserLoginCard: added dual buttons (login/try). MainView: tutorial localStorage gating, hero/banner layout restructuring, guest-allowed route (/roadView/main), and game mode card styling updates.
Practice Game & Tutorial
src/features/game/single/roadview/views/PracticeView.vue, src/features/game/single/roadview/components/Result/PracticeResultOverlay.vue, src/features/game/single/roadview/services/roadViewApi.service.js
PracticeView: added multi-step in-game tutorial with interaction hints and auto-spot suggestions. PracticeResultOverlay: added guest CTA block with score display and login prompt. roadViewApi.service: added practice-token header support for anonymous practices and token storage/cleanup in sessionStorage.
Game Navigation & Ranking
src/features/game/multiplayer/roadview/views/BaseGameView.vue, src/features/game/multiplayer/room/views/RoomView.vue, src/features/game/single/main/components/DailyMvpCard.vue, src/features/game/single/main/components/RankingModal.vue, src/features/game/single/main/views/RoadViewMainView.vue
Updated navigation from window.location.href to router.replace() for SPA consistency; added login gating for rank game start; added unlogged user CTA blocks in ranking/stats sections; added DailyMvpCard with login confirmation.
Map & Game Controls
src/features/game/shared/components/Kakao/KakaoMapGame/composables/useKakaoMapControls.js
Added post-initialization relayout() call via requestAnimationFrame to trigger Kakao map tile rendering without changing center/zoom.
Admin & Shop Features
src/features/admin/components/Banner/BannerManager.vue, src/features/shop/views/ShopView.vue, src/features/shop/services/shop.service.js
BannerManager: updated navigation to use openExternalUrl() / hardRedirect(). ShopView: added isLoggedIn computed, login-gated purchase UI, and disabled-points styling. shop.service: removed debug console.log statements.
User Settings & Profile
src/features/user/components/AccountSettings.vue, src/features/user/view/ProfileView.vue
AccountSettings: added mobile push notification toggle with permission requests, status display, server preference management, and "coming soon" badges for other notification types. ProfileView: updated auth check to use authStorage.isAuthenticated().
Router & Auth Updates
src/router/index.js, src/router/userRoutes.js
Router: updated auth checks to use authStorage. userRoutes: removed /shop route (guest-accessible via main view instead).
App-Level Setup
src/App.vue
Added push notification and deep-link listener registration on mount with cleanup on unmount; integrated handlePushAction for router navigation from push payloads; updated token management to use authStorage.
Styles & Utilities
src/shared/utils/common-styles.css
Removed outdated CSS usage comments.
Configuration & Secrets
.claude/settings.local.json, config/env.template, .gitignore, .env.production, .env.staging
Added Claude AI settings, extended environment variables for OAuth, mobile, and push configuration; added iOS/Android secret patterns to gitignore.
Documentation & Planning
CLAUDE.md, README.md, docs/ENVIRONMENT_SETUP.md, docs/MOBILE_APP_DESKTOP_TESTING_GUIDE.md, docs/OAUTH2_MOBILE_FLOW_GUIDE.md, docs/mobile-web-app-release-master-plan.md, plans/mobile-app-release-10step-execution-plan.md, plans/mobile-build-and-test-guide.md, plans/onboarding-anonymous-user-funnel.md, plans/onboarding-improvement.md, plans/push-notification-backend-tasks.md, plans/push-notification-frontend-plan.md, plans/regression-baseline-checklist.md
Comprehensive guides for architecture, environment setup, mobile testing, OAuth mobile flow specification, push notification implementation, backend/frontend tasks, release coordination, and QA checklists.
OMC Agent State & Project Memory
.omc/settings.local.json, .omc/project-memory.json, .omc/sessions/..., .omc/state/...
AI agent session tracking and project metadata files (auto-generated by development tooling).
Git Submodule Update
KoSpot-frontend-private
Updated private submodule reference to newer commit.
Package Dependencies
package.json
Added Capacitor runtime packages (@capacitor/app, @capacitor/browser, @capacitor/core, @capacitor/push-notifications) and dev dependencies (@capacitor/android, @capacitor/ios, @capacitor/cli); added npm scripts for mobile sync and open (mobile:sync, mobile:android, mobile:ios).

Sequence Diagrams

sequenceDiagram
    participant User as User
    participant WebApp as WebApp<br/>(Frontend)
    participant Backend as Backend API<br/>(Spring Boot)
    participant OAuth as OAuth Server
    participant AppDeepLink as Native App<br/>(Capacitor)

    User->>WebApp: Clicks social login (mobile)
    WebApp->>WebApp: buildOAuthAuthorizeUrl()<br/>adds platform=app
    WebApp->>Backend: GET /oauth2/authorization/{provider}?platform=app
    Backend->>OAuth: Redirects to OAuth provider
    OAuth->>User: Shows login consent
    User->>OAuth: Approves auth
    OAuth->>Backend: Redirects with auth code
    Backend->>Backend: Detects platform=app<br/>generates one-time code
    Backend->>AppDeepLink: Redirects via kospot://auth/callback?code=...
    AppDeepLink->>WebApp: Deep link parsed & routed
    WebApp->>Backend: POST /auth/mobile/exchange<br/>{code, state}
    Backend->>Backend: Validates & consumes code
    Backend->>WebApp: Returns {accessToken, refreshToken}
    WebApp->>WebApp: authStorage.setTokens()
    WebApp->>User: Login success, navigate to /main
Loading
sequenceDiagram
    participant User as User/<br/>App
    participant WebApp as Vue App
    participant Capacitor as Capacitor<br/>Push Plugin
    participant FCM as Firebase Cloud<br/>Messaging
    participant Backend as Backend API

    User->>WebApp: App opens (mounted)
    WebApp->>Capacitor: initializePush()
    Capacitor->>Capacitor: requestPermissions()
    User->>User: Grants notification permission
    Capacitor->>FCM: register() for FCM token
    FCM->>Capacitor: Returns fcmToken
    Capacitor->>WebApp: onRegistration event
    WebApp->>WebApp: Cache fcmToken in localStorage
    WebApp->>Backend: PUT /mobile/push-tokens<br/>{token, platform, enabled...}
    Backend->>Backend: Store push_token record
    Backend->>WebApp: 200 OK

    rect rgb(200, 150, 255, 0.5)
    Note over Backend,FCM: Later: Notification dispatch
    Backend->>FCM: Send multicast via Admin SDK<br/>data.deeplink, title, body
    FCM->>Capacitor: Deliver notification
    end

    alt Foreground
        Capacitor->>WebApp: onNotificationReceived event
        WebApp->>WebApp: Update notificationStore
        WebApp->>User: Show in-app notification UI
    else Background/Terminated
        Capacitor->>User: System notification tray
        User->>Capacitor: User taps notification
        Capacitor->>WebApp: onNotificationActionPerformed
        WebApp->>WebApp: Extract data.deeplink
        WebApp->>WebApp: router.replace(deeplink)
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

This pull request introduces substantial, multi-faceted changes spanning mobile platform support (Capacitor setup for Android/iOS), new authentication flows (mobile OAuth with one-time code exchange), push notification infrastructure, and deep-linking. The changes are heterogeneous and span numerous files (50+) across frontend components, core services, build configurations, and documentation. Logic density is high in areas like OAuthCallbackView (mobile vs legacy flow), push.service.js (permission/registration/preference management), and the practice view tutorial. The native build configurations (Gradle, Xcode projects) require careful validation. Platform-specific conditional logic permeates the codebase. These factors combined necessitate comprehensive review of both new services and integration points.

Possibly related PRs

Poem

🐰 Hop hop, mobile dreams come true,
Capacitor weaves Android and iOS in two,
Deep links and push notifications bloom,
OAuth codes exchange in the native room,
From web to app, the journey unfolds anew! 🌿📱

✨ 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 feat/111

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