Skip to content

Feature/analytics event logging#233

Merged
Junhyukkkk merged 16 commits into
developfrom
feature/analytics-event-logging
Jun 10, 2026
Merged

Feature/analytics event logging#233
Junhyukkkk merged 16 commits into
developfrom
feature/analytics-event-logging

Conversation

@Junhyukkkk

@Junhyukkkk Junhyukkkk commented Jun 10, 2026

Copy link
Copy Markdown
Member

📌 관련 이슈

  • closes #

🔍 작업 내용

사용자 행동 데이터를 수집하기 위한 두 가지 인프라를 추가했습니다.

  1. 행동 로그(Analytics Event) — 투표/채팅/알림/가입 등 주요 행동을 서버에서 구조화된
    JSON 로그로 적재하는 공통 인프라
  2. UTM 가입 출처 추적 — UTM 링크로 들어온 비회원이 가입까지 이어졌을 때, 그 출처를
    users 테이블에 first-touch로 기록

📝 변경 사항

1. 행동 로그 인프라 (com.ject.vs.analytics)

  • AnalyticsEvent(순수 값 객체) + AnalyticsEventLogger(유일 진입점) 추가
  • 공통 필드 5개(user_id, anonymous_id, is_member, platform, occurred_at) 자동
    주입
  • 로그 실패가 비즈니스 로직에 영향 주지 않도록 로거에서 모든 예외 흡수
  • 투표/결과·공유/이모지/몰입형/무료투표/채팅/알림·푸시/가입 컨트롤러에 이벤트 로깅 연결
  • 서버 계산값 처리: 이모지 action(created/changed/canceled), 채팅 unread_total_count
    합산, is_first_message 판정

2. UTM 가입 출처 추적

  • 스키마/도메인: V14__add_user_signup_source.sql(users에
    signup_source/medium/campaign/content 컬럼), UtmAttribution 값 객체,
    User.assignSignupSource()
  • 수집 경로: GET /api/track/visit 엔드포인트(TrackingController) +
    utm_attribution 쿠키(first-touch, 30일, httpOnly, UtmCookie)
  • 가입 연결: OAuth2LoginSuccessHandler에서 쿠키 읽어 가입에 전달 → 신규 row 생성
    시에만 출처 기록 → signup_completed 로그에 utm_* 포함 → 쿠키 만료
  • first-touch 고정: 기존 사용자 재로그인 시 출처를 덮어쓰지 않음
  • findOrCreate/socialLogin을 오버로드로 추가해 기존 호출/테스트 호환 유지
  • /api/track/** 공개 엔드포인트 등록(SecurityPaths)

💬 리뷰어에게

  • 프론트 의존 1개: UTM은 SPA URL에 붙어 들어와 OAuth 왕복 시 사라지므로, 프론트가
    랜딩 시 /api/track/visitcredentials:'include'로 1회 호출해야 컬럼이 채워집니다.
    미호출 시 가입은 정상이고 signup_*만 null로 남습니다.
  • 행동 로그는 기존 로직에 부가적으로만 붙였고(예외 흡수), 기존 응답/흐름은 변경
    없음.
  • 기존 테스트 호환을 위해 메서드 시그니처를 바꾸지 않고 오버로드로 추가했습니다.

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 방문자 추적 및 UTM 캠페인 소스 저장 기능 추가
    • 채팅, 투표, 알림, 반응 등 사용자 행동 분석 이벤트 로깅 시스템 추가
    • 이모지 반응 시 동작 상태(생성/변경/취소) 추적 기능 추가
  • Bug Fixes

    • 무료 투표 횟수 초과 시 오류 처리 개선 및 상세 분석 로깅 추가

@Junhyukkkk Junhyukkkk self-assigned this Jun 10, 2026
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Junhyukkkk, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 19 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 67fdcca4-b348-457e-a1a8-d6facd522b9b

📥 Commits

Reviewing files that changed from the base of the PR and between cba2bbe and 38d9a41.

📒 Files selected for processing (1)
  • src/main/java/com/ject/vs/vote/domain/VoteDuration.java

Walkthrough

PR은 사용자 행동 추적을 위한 완전한 분석 이벤트 시스템을 구축합니다. 핵심 Analytics 인프라를 추가하고, UTM 퍼스트-터치 속성을 캡처하며, 채팅·투표·알림 컨트롤러 전반에 로깅을 통합합니다. 데이터 모델은 메시지 첫 번째 플래그, 알림 결과, 투표 취소 옵션, 이모지 동작 추적으로 확장됩니다.

Changes

Analytics Infrastructure and Event Tracking System

Layer / File(s) Summary
Analytics event model and logging infrastructure
src/main/java/com/ject/vs/analytics/AnalyticsEvent.java, src/main/java/com/ject/vs/analytics/AnalyticsEventLogger.java
AnalyticsEvent 값 객체는 이벤트 이름, 속성 맵, 사용자·익명 ID 오버라이드를 관리합니다. AnalyticsEventLogger Spring 컴포넌트는 현재 요청/보안 컨텍스트에서 사용자 정보를 수집하고 JSON 로그를 기록하며, 플랫폼을 User-Agent로 감지하고, 예외를 안전하게 처리합니다.
UTM first-touch attribution value object and cookie management
src/main/java/com/ject/vs/user/domain/UtmAttribution.java, src/main/java/com/ject/vs/config/UtmCookie.java
UtmAttribution 레코드는 source/medium/campaign/content를 저장하고 빈 값을 정규화합니다. UtmCookieutm_attribution 쿠키로 first-touch UTM을 저장·복원·만료하며, URL 인코딩과 key=value&... 형식 파싱을 사용합니다.
Tracking endpoint and OAuth2 login integration with UTM
src/main/java/com/ject/vs/analytics/TrackingController.java, src/main/java/com/ject/vs/config/OAuth2LoginSuccessHandler.java, src/main/java/com/ject/vs/config/SecurityPaths.java
TrackingController/api/track/visit로 first-touch UTM을 쿠키에 기록합니다. OAuth2LoginSuccessHandler는 쿠키에서 UTM을 읽어 로그인에 전달하고, 제공자 메서드를 포함한 signup_completed 이벤트를 로깅한 후 쿠키를 지웁니다. /api/track/**이 공개 엔드포인트로 추가됩니다.
User entity signup source fields and persistence
src/main/java/com/ject/vs/user/domain/User.java, src/main/java/com/ject/vs/user/port/UserService.java, src/main/java/com/ject/vs/auth/port/AuthService.java, src/main/resources/db/migration/V14__add_user_signup_source.sql
User 엔티티에 signupSource/Medium/Campaign/Content 필드 4개를 추가합니다. assignSignupSource 메서드는 UtmAttribution을 필드에 매핑합니다. UserService.findOrCreate 오버로드는 UTM을 받아 새 사용자에게 적용합니다. 데이터베이스 마이그레이션이 4개 VARCHAR(255) 열을 추가합니다.
Message first-message-in-room tracking
src/main/java/com/ject/vs/chat/port/in/dto/MessageResult.java, src/main/java/com/ject/vs/chat/port/ChatService.java, src/main/java/com/ject/vs/chat/adapter/event/ChatMessageEventListener.java
MessageResult 레코드에 isFirstMessage 불리언 필드를 추가합니다. ChatService.sendMessage는 저장 전에 메시지 존재 여부를 확인해 플래그를 계산합니다. getMessages는 기록 조회 시 false를 전달합니다. 이벤트 리스너는 새 필드를 반영합니다.
Notification markAsRead result type and implementation
src/main/java/com/ject/vs/notification/port/in/NotificationCommandUseCase.java, src/main/java/com/ject/vs/notification/port/NotificationCommandService.java, src/unitTest/java/com/ject/vs/notification/adapter/web/NotificationControllerTest.java
MarkAsReadResult 레코드는 type, voteId, wasRead를 반환합니다. NotificationCommandUseCase.markAsRead는 void 대신 결과를 반환합니다. NotificationCommandService는 읽기 상태를 캡처한 후 변경하고 결과를 반환합니다. 테스트는 결과 스텁을 추가합니다.
Vote cancellation returns previous option ID
src/main/java/com/ject/vs/vote/port/in/VoteCommandUseCase.java, src/main/java/com/ject/vs/vote/port/VoteCommandService.java, src/unitTest/java/com/ject/vs/vote/adapter/web/VoteControllerTest.java
VoteCommandUseCase.cancelLong (이전 optionId)을 반환합니다. VoteCommandService는 삭제 전에 참여를 조회해 optionId를 캡처하고 반환합니다. 테스트는 스텁을 willDoNothing()에서 값 반환으로 변경합니다.
Emoji reaction action classification
src/main/java/com/ject/vs/vote/domain/EmojiAction.java, src/main/java/com/ject/vs/vote/port/VoteEmojiCommandService.java, src/main/java/com/ject/vs/vote/port/in/VoteEmojiCommandUseCase.java, src/unitTest/java/com/ject/vs/vote/adapter/web/VoteEmojiControllerTest.java
EmojiAction enum은 CREATED/CHANGED/CANCELED 상태를 정의합니다. VoteEmojiCommandService는 기존 vs. 새 이모지 상태로부터 동작을 결정합니다. EmojiResult는 action 필드를 포함합니다. 테스트는 동작 값으로 업데이트됩니다.
Chat controller analytics event logging
src/main/java/com/ject/vs/chat/adapter/web/ChatController.java, src/unitTest/java/com/ject/vs/chat/adapter/web/ChatControllerTest.java
ChatControllerAnalyticsEventLogger를 주입받습니다. 목록 조회는 읽지 않은 합계와 방 수를 로깅합니다. 방 조회는 방 메타데이터를 로깅합니다. 메시지 조회는 메시지 수와 페이지 상태를 로깅합니다. 메시지 전송은 메시지 세부사항과 첫 메시지 플래그를 로깅합니다. 읽음 표시는 읽음 타임스탬프를 로깅합니다.
Vote and immersive vote controller analytics logging
src/main/java/com/ject/vs/vote/adapter/web/VoteController.java, src/main/java/com/ject/vs/vote/adapter/web/ImmersiveVoteController.java, src/main/java/com/ject/vs/vote/adapter/web/VoteResultController.java, src/main/java/com/ject/vs/vote/adapter/web/VoteEmojiController.java, src/main/java/com/ject/vs/vote/adapter/web/GuestFreeVoteController.java, src/unitTest/java/com/ject/vs/vote/adapter/web/*
VoteController는 detail/participate/cancel 이벤트를 로깅합니다. ImmersiveVoteController는 feed/participate/live/share 이벤트를 로깅합니다. VoteResultController는 결과와 공유 이벤트를 로깅합니다. VoteEmojiController는 action을 포함한 emoji_reacted 이벤트를 로깅합니다. GuestFreeVoteController는 무료 투표 상태를 로깅합니다.
Notification and device controller analytics logging
src/main/java/com/ject/vs/notification/adapter/web/NotificationController.java, src/main/java/com/ject/vs/notification/adapter/web/DeviceController.java, src/main/java/com/ject/vs/common/exception/GlobalExceptionHandler.java, src/unitTest/java/com/ject/vs/notification/adapter/web/*
NotificationController는 list_viewed (읽지 않은 수, 페이지네이션 포함)와 notification_opened 이벤트를 로깅합니다. DeviceController는 플랫폼을 포함한 push_token_registered를 로깅합니다. GlobalExceptionHandler는 URI에서 voteId를 추출해 free_limit_exceeded를 로깅합니다.
Test infrastructure mock beans for analytics logger
src/unitTest/java/com/ject/vs/**/*Test.java
모든 컨트롤러 테스트는 @MockBean AnalyticsEventLogger analytics와 import를 추가합니다. VoteControllerTest.cancel 스텁은 값을 반환하도록 변경됩니다. NotificationControllerTest는 결과 스텁을 추가합니다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

✨feature, feature

Suggested reviewers

  • tlarbals824
  • KII1ua

🐰 우아한 분석 시스템이 완성되어
모든 사용자의 발자국을 기록하고
UTM 쿠키는 신비로운 마커처럼
첫 방문을 잊지 않으니,
데이터는 흘러흘러 모여 📊✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.33% 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 제목이 '기능/분석 이벤트 로깅'으로 풀 리퀘스트의 주요 변경사항(분석 이벤트 로깅 인프라 추가 및 UTM 기반 가입 출처 추적)을 명확하게 요약하고 있습니다.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/analytics-event-logging

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.

@github-actions

Copy link
Copy Markdown

빌드 성공
배포 준비 완료!

@Junhyukkkk Junhyukkkk merged commit 219bdad into develop Jun 10, 2026
1 check was pending
@github-actions github-actions Bot deleted the feature/analytics-event-logging branch June 10, 2026 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant