Skip to content

[Feat] FirebaseAnalytics 로그 수집 - #192

Merged
oungsi2000 merged 8 commits into
developfrom
feat/160
May 4, 2026
Merged

[Feat] FirebaseAnalytics 로그 수집#192
oungsi2000 merged 8 commits into
developfrom
feat/160

Conversation

@oungsi2000

@oungsi2000 oungsi2000 commented May 4, 2026

Copy link
Copy Markdown
Contributor

#️⃣ 이슈 번호

ex) #160


🛠️ 작업 내용

  • Firebase Analytics 로그를 수집합니다.

🙇🏻 중점 리뷰 요청

  • 특히 확인이 필요한 부분, 고민했던 부분 등을 적어주세요.

📸 이미지 첨부 (Optional)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 앱 내 사용자 활동(화면 이동, 버튼 클릭) 분석 추적 기능 추가
    • 알림 상호작용 및 참여 분석 추적 기능 추가
    • 화면 체류 시간 및 사용자 세션 분석 기능 추가
  • 버그 수정

    • 공지사항 알림 처리 개선으로 딥링크 기능 강화

oungsi2000 added 8 commits May 2, 2026 19:40
* **feat: `FirebaseAnalytics` 클래스화 및 의존성 주입 적용**
    * 기존 `object` 선언을 `class`로 변경하고 Metro를 통한 의존성 주입(`@Inject`)을 적용했습니다.
    * `FestivalLocalDataSource` 및 `DeviceLocalDataSource`를 주입받아 축제 ID와 사용자 UUID를 자동으로 수집하도록 개선했습니다.

* **feat: 기본 이벤트 파라미터 자동 설정 및 지연 전송 로직 구현**
    * 앱 버전, OS 버전, 디바이스 모델, 언어, 사용자 ID 등을 포함하는 기본 파라미터를 `setDefaultEventParameters`를 통해 설정합니다.
    * 초기화 작업이 완료되기 전 발생한 이벤트를 `Channel`에 보관했다가 초기화 후 순차적으로 전송하는 `PendingEvent` 처리 로직을 추가했습니다.
    * 모든 이벤트 로깅 시 현재 활성화된 `festival_id`가 자동으로 포함되도록 수정했습니다.

* **refactor: 플랫폼별 분석 로직 고도화 및 불필요한 메서드 제거**
    * **Android**: `Firebase.analytics`를 활용하여 기본 파라미터 및 `festival_id` 매핑 로직을 구현했습니다.
    * **iOS**: `utsname`을 사용한 상세 디바이스 모델 추출 및 `NSDate` 기반 타임스탬프 계산 로직을 추가했습니다.
    * 사용되지 않는 `getAppInstanceId`, `getSessionId` 메서드를 제거했습니다.

* **infra: 앱 그래프 내 분석 서비스 등록**
    * `FestabookAppGraph`에 `FirebaseAnalytics`를 추가하고, 비동기 작업을 위한 `IOCoroutineScope` 제공 로직을 구성했습니다.

# Conflicts:
#	composeApp/src/commonMain/kotlin/com/daedan/festabook/di/FestabookAppGraph.kt
* **feat: 공통 시간 측정 유틸리티 `currentTimeMillis` 구현**
    * Kotlin Multiplatform의 `expect/actual`을 사용하여 플랫폼별 현재 시간(ms) 측정 로직을 통합했습니다.
    * **Android**: `System.currentTimeMillis()`를 사용합니다.
    * **iOS**: `NSDate`와 `timeIntervalSince1970`을 사용하여 구현하고, 기존 `IosFirebaseAnalytics` 내 중복 코드를 제거했습니다.

* **feat: 알림 클릭 시 분석 이벤트(`notification_tapped`) 로깅 추가**
    * `FcmDeepLinkAction.OpenAnnouncement` 모델에 `notificationSentAt` 필드를 추가하여 알림 발송 시점을 기록합니다.
    * 알림 클릭 핸들러에서 알림 ID, 발송 시점, 그리고 클릭까지 걸린 시간(`elapsed_sec`)을 포함한 분석 이벤트를 전송하도록 구현했습니다.
    * `MainScreen` 진입 시 `app_foreground` 이벤트를 로깅하도록 추가했습니다.

* **refactor: 분석 도구 및 딥링크 처리 로직 개선**
    * `rememberAnalytics()` Composable을 추가하여 `AppGraph`에서 `FirebaseAnalytics` 인스턴스를 쉽게 참조할 수 있도록 개선했습니다.
    * Android 및 iOS의 메시징 서비스/델리게이트에서 공지사항 알림 처리 시 현재 타임스탬프를 함께 전달하도록 수정했습니다.
    * `AndroidFirebaseAnalytics`에서 기본 파라미터 설정 시 새로 정의한 `currentTimeMillis()`를 사용하도록 통일했습니다.
* **feat: 클릭 이벤트 로깅을 위한 `Modifier.logClick` 확장 함수 추가**
    * `Modifier.clickable`을 래핑하여 버튼 클릭 시 `button_id`와 `screen_name` 파라미터를 포함한 `button_click` 이벤트를 자동으로 전송합니다.

* **feat: 화면 진입 및 이탈 로깅을 위한 `ScreenViewLogger` 컴포저블 구현**
    * `DisposableEffect`를 활용해 화면 진입(`screen_view`)과 이탈(`screen_exit`) 시점을 기록합니다.
    * 이탈 시 화면 체류 시간(`duration_sec`)을 계산하여 함께 전송하도록 로직을 구성했습니다.

* **feat: 가시성 기반 로깅을 위한 `ScreenViewVisibilityLogger` 구현**
    * `isVisible` 상태 변화에 따라 화면 노출 여부를 판단하여 진입/이탈 이벤트를 전송합니다.
    * 체류 시간을 소수점 단위의 초(`Double`)로 정밀하게 계산하도록 구현했습니다.
* **feat: `DeepLinkKeys` 내 알림 전송 시각 키 정의**
    * 딥링크 데이터 관리를 위한 `KEY_NOTIFICATION_SENT_AT` 상수를 추가했습니다.

* **feat: `NotificationHelper` 알림 생성 시 현재 시각 포함**
    * 공지사항 알림(`ANNOUNCEMENT`) 생성 시, 인텐트에 현재 시각(`currentTimeMillis()`)을 `KEY_NOTIFICATION_SENT_AT`에 담아 전달하도록 수정했습니다.

* **refactor: `RememberDeepLinkHandler` 내 알림 시각 추출 및 처리 로직 반영**
    * 안드로이드 인텐트에서 `notificationSentAt` 값을 추출하여 `FcmDeepLinkAction.OpenAnnouncement`로 전달하도록 수정했습니다.
    * 처리가 완료된 `KEY_NOTIFICATION_SENT_AT` 데이터를 인텐트에서 제거하는 로직을 추가했습니다.
* **feat: 주요 화면에 `ScreenViewLogger` 및 `ScreenViewVisibilityLogger` 추가**
    * `HomeScreen`, `PlaceMapScreen`, `NewsScreen`, `ScheduleScreen`, `SettingScreen` 등 거의 모든 주요 화면(Screen) 컴포넌트에 진입 시 로그를 남기는 `ScreenViewLogger`를 추가했습니다.
    * `PlaceMapScreen`에는 가시성 상태에 따라 로깅 여부를 결정하는 `ScreenViewVisibilityLogger`를 적용했습니다.

* **feat: `logClick` 함수 내 추가 파라미터(`extraParam`) 지원**
    * 버튼 클릭 로그를 기록할 때 기존 `button_id`와 `screen` 외에도 사용자 정의 매개변수를 추가로 전달할 수 있도록 `extraParam` 파라미터를 추가했습니다.
    * `buildMap`을 사용하여 로그 이벤트에 포함될 데이터 구조를 확장했습니다.

* **style: `FestaingScreen` 내 오타 수정**
    * `ScreenViewLogger`에 전달되는 문자열 내 오타를 수정했습니다. (`FestaingScreen`)
* **refactor: `ScreenViewLogger` 내 상태 관리 및 코드 정리**
    * `enteredTime`을 저장할 때 일반 `mutableStateOf<Long>` 대신 `mutableLongStateOf`를 사용하도록 변경하여 오토박싱을 방지했습니다.
    * 파일 끝의 불필요한 공백을 제거했습니다.

* **refactor: `IosFirebaseAnalytics` 의존성 주입 수정 및 미사용 임포트 제거**
    * `CoroutineScope` 주입 시 `@IO` 한정자(qualifier)를 추가하여 적절한 스코프가 주입되도록 명시했습니다.
    * `NSDate`, `date`, `timeIntervalSince1970` 등 iOS 플랫폼의 미사용 임포트를 정리했습니다.

* **style: 코드 포맷팅 및 미사용 임포트 제거**
    * `ClickableLogger.kt`: `logEvent` 호출 시 가독성을 위해 파라미터 줄바꿈 및 트레일링 콤마를 추가했습니다.
    * `AndroidAppGraph.kt`, `RememberDeepLinkHandler.android.kt`: 불필요한 임포트 구문을 제거했습니다.
    * `FestabookAppGraph.kt`: 불필요한 빈 줄을 제거했습니다.
    * `FestatingScreen.kt`: 임포트 순서를 조정했습니다.
* **feat: `FAQScreen`, `NoticeScreen` 내 아이템 클릭 로깅**
    * FAQ 및 공지사항 항목 클릭 시 각각 `faq_id`, `notice_id`를 포함하여 로깅하도록 수정했습니다.
    * 공지사항 및 유실물 화면의 새로고침 액션에 로깅을 추가했습니다.

* **feat: `HomeScreen` 및 메인 내비게이션 클릭 로깅**
    * 홈 화면에서 탐색, 페스타팅, 일정, 웨이팅 바 클릭 시 로깅을 수행합니다.
    * 하단 탭 바에서 각 탭 선택 시 탭 이름을 포함하여 로깅하도록 개선했습니다.

* **feat: 장소 관련 화면 클릭 로깅**
    * 장소 지도(`PlaceMapScreen`)의 카테고리 선택 및 리스트 아이템 클릭 시 로깅을 추가했습니다.
    * 장소 상세 및 미리보기 화면에서 상세 이동, 웨이팅 등록 등의 액션 로깅을 수행합니다.

* **feat: 웨이팅 및 설정 화면 액션 로깅**
    * `MyWaitingScreen`의 새로고침, 취소, 상세 이동 액션에 로깅을 적용했습니다.
    * 웨이팅 등록 화면의 인원 조절, 약관 동의, 등록 버튼 클릭 시 로깅을 수행합니다.
    * 설정 화면의 공지사항/정책 링크 클릭, 알림 설정 토글, 내 정보 저장 액션 등에 로깅을 추가했습니다.

* **feat: 검색 및 뒤로가기 액션 로깅**
    * 탐색 화면(`ExploreScreen`) 및 각 주요 화면의 뒤로가기 버튼 클릭 시 로깅을 수행하도록 수정했습니다.
@oungsi2000
oungsi2000 requested a review from parkjiminnnn May 4, 2026 09:07
@oungsi2000 oungsi2000 self-assigned this May 4, 2026
@oungsi2000 oungsi2000 added the ✨ Feat 새로운 기능이나 기능 개선 추가 label May 4, 2026
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: 506901b9-5c50-47b7-b5cb-16a27be63e1e

📥 Commits

Reviewing files that changed from the base of the PR and between d5c1150 and 400cceb.

📒 Files selected for processing (40)
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/di/AndroidAppGraph.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/logging/AndroidFirebaseAnalytics.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/logging/FirebaseAnalytics.android.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/logging/LoggingUtil.android.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/presentation/platform/RememberDeepLinkHandler.android.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/service/MyFirebaseMessagingService.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/service/NotificationHelper.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/di/FestabookAppGraph.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/logging/ClickableLogger.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/logging/FirebaseAnalytics.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/logging/LoggingUtil.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/logging/ScreenViewLogger.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/common/RememberAnalytics.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/explore/component/ExploreScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/explore/component/ExploreSearchResultList.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/festating/component/FestatingScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/home/component/HomeScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/main/component/FestabookBottomNavigationBar.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/main/component/MainScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/news/component/NewsScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/news/faq/component/FAQScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/news/lost/component/LostItemScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/news/notice/component/NoticeScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/component/PlaceCategoryScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/component/PlaceDetailPreviewScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/component/PlaceDetailPreviewSecondaryScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/component/PlaceListScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/component/PlaceMapScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/placeDetail/component/PlaceDetailScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/placeMap/waitingRegister/component/WaitingRegisterScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/platform/RememberDeepLinkHandler.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/schedule/component/ScheduleScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/setting/component/SettingScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/setting/waitinginfo/component/AddWaitingInfoScreen.kt
  • composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/waiting/component/MyWaitingScreen.kt
  • composeApp/src/iosMain/kotlin/com/daedan/festabook/delegate/DefaultUserNotificationDelegate.kt
  • composeApp/src/iosMain/kotlin/com/daedan/festabook/logging/FirebaseAnalytics.ios.kt
  • composeApp/src/iosMain/kotlin/com/daedan/festabook/logging/IosFirebaseAnalytics.kt
  • composeApp/src/iosMain/kotlin/com/daedan/festabook/logging/LoggingUtil.ios.kt
  • gradle.properties
💤 Files with no reviewable changes (3)
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/logging/FirebaseAnalytics.android.kt
  • composeApp/src/androidMain/kotlin/com/daedan/festabook/di/AndroidAppGraph.kt
  • composeApp/src/iosMain/kotlin/com/daedan/festabook/logging/FirebaseAnalytics.ios.kt

📝 Walkthrough

훑어보기

이 PR은 멀티플랫폼 expect/actual 객체에서 플랫폼 인식 추상 클래스 아키텍처로 Firebase Analytics를 리팩토링하고, 알림 타임스탬프를 딥링크 플로우에 통합하면서 UI 레이어 전반에 걸쳐 포괄적인 화면 조회 및 클릭 이벤트 로깅을 추가합니다.

변경 사항

분석 인프라 리팩토링 및 UI 로깅 계측

Layer / File(s) 요약
Analytics 기반 아키텍처 리팩토링
composeApp/src/commonMain/kotlin/com/daedan/festabook/logging/FirebaseAnalytics.kt
expect/actual 객체에서 추상 클래스로 전환: CoroutineScope, 로컬 데이터 소스를 주입받고, 초기화 중 이벤트를 버퍼링하며, 초기화 완료 후 플랫폼별 onLogEvent 구현으로 위임하는 로직 추가
로깅 유틸리티 추가
composeApp/src/commonMain/kotlin/com/daedan/festabook/logging/LoggingUtil.kt, ClickableLogger.kt, ScreenViewLogger.kt
currentTimeMillis() 멀티플랫폼 expect 함수, logClick() Composable(버튼 클릭 로깅), ScreenViewLogger/ScreenViewVisibilityLogger Composable(화면 진입/퇴출 로깅)
알림 타임스탬프 추적
composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/platform/RememberDeepLinkHandler.kt
DeepLinkKeys.KEY_NOTIFICATION_SENT_AT 상수 추가, FcmDeepLinkAction.OpenAnnouncementnotificationSentAt: Long 필드 추가
Android 플랫폼 구현
composeApp/src/androidMain/kotlin/com/daedan/festabook/logging/AndroidFirebaseAnalytics.kt, LoggingUtil.android.kt
AndroidFirebaseAnalytics 클래스: Firebase 기본 파라미터 설정, 이벤트 로깅 시 festival_id 자동 추가 및 타입별 직렬화; currentTimeMillis()System.currentTimeMillis()에 위임
iOS 플랫폼 구현
composeApp/src/iosMain/kotlin/com/daedan/festabook/logging/IosFirebaseAnalytics.kt, LoggingUtil.ios.kt
IosFirebaseAnalytics 클래스: 기본 파라미터 설정, 장치 모델 감지, 이벤트 로깅; currentTimeMillis()NSDate.timeIntervalSince1970 변환
DI 그래프 업데이트
composeApp/src/commonMain/kotlin/com/daedan/festabook/di/FestabookAppGraph.kt, composeApp/src/androidMain/kotlin/com/daedan/festabook/di/AndroidAppGraph.kt
FestabookAppGraphanalytics: FirebaseAnalytics@IO coroutineScope 추가; AndroidAppGraph에서 coroutineScope 제거
Composable 헬퍼
composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/common/RememberAnalytics.kt
rememberAnalytics() Composable 추가: 앱 그래프에서 FirebaseAnalytics 인스턴스 반환
화면 로깅 계측
composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/...
18개 화면(ExploreScreen, HomeScreen, NewsScreen, FAQScreen, PlaceDetailScreen 등)에 ScreenViewLogger 또는 ScreenViewVisibilityLogger 추가
클릭 로깅 계측
composeApp/src/commonMain/kotlin/com/daedan/festabook/presentation/...
ExploreSearchResultList, FestabookBottomNavigationBar, PlaceCategoryScreen, SettingScreen 등에서 사용자 인터랙션을 logClick()으로 래핑; 각 클릭 이벤트에 identifier, screenName, 선택적 extraParam 포함
딥링크 및 알림 처리 업데이트
composeApp/src/androidMain/kotlin/com/daedan/festabook/presentation/platform/RememberDeepLinkHandler.android.kt, service/MyFirebaseMessagingService.kt, service/NotificationHelper.kt
Intent 및 FCM 메시지에서 notificationSentAt 타임스탐프 전달; MainScreen에서 알림 탭 이벤트 로깅
iOS 알림 위임 업데이트
composeApp/src/iosMain/kotlin/com/daedan/festabook/delegate/DefaultUserNotificationDelegate.kt
알림 응답에서 notificationSendAt 타임스탐프 계산 및 딥링크 액션으로 전달
빌드 설정
gradle.properties
buildkonfig.flavor release에서 dev로 변경

Sequence Diagram

sequenceDiagram
    participant App as App
    participant Analytics as FirebaseAnalytics<br/>(Abstract)
    participant Platform as Platform<br/>(Android/iOS)
    participant Firebase as Firebase SDK
    participant LocalData as LocalDataSources

    App->>Analytics: initialize(scope, dataSource)
    activate Analytics
    Note over Analytics: Create pending event channel<br/>& launch initializingJob
    
    Analytics->>Platform: setDefaultEventParameters()
    activate Platform
    Platform->>LocalData: getFestivalId(), getUuid()
    LocalData-->>Platform: festival_id, user_id
    Platform->>Firebase: setDefaultEventParameters(params)
    Firebase-->>Platform: ✓
    deactivate Platform
    
    Analytics->>Analytics: flushPendingEvents()
    deactivate Analytics
    
    App->>App: render UI with ScreenViewLogger/logClick
    
    App->>Analytics: logEvent("button_click", params)
    activate Analytics
    alt initializingJob.isCompleted
        Analytics->>Platform: onLogEvent("button_click", merged_params)
        activate Platform
        Platform->>Firebase: logEvent("button_click", {..., festival_id})
        deactivate Platform
    else still initializing
        Analytics->>Analytics: buffer event to pending channel
    end
    deactivate Analytics
Loading

예상 코드 리뷰 난이도

🎯 4 (Complex) | ⏱️ ~60 분

🐰 로깅의 새로운 시대,
화면마다 분석의 빛,
클릭은 이제 음악이 되고,
데이터는 춤을 춘다네!


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Review rate limit: 2/3 reviews remaining, refill in 20 minutes.

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

@oungsi2000
oungsi2000 merged commit 4c6eff9 into develop May 4, 2026
4 of 6 checks passed
@oungsi2000
oungsi2000 deleted the feat/160 branch May 4, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feat 새로운 기능이나 기능 개선 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant