Skip to content

Commit

Permalink
[BSVR-232] 믹스패널 이벤트 추가 (#165)
Browse files Browse the repository at this point in the history
* feat : mixpanel 추가

* feat : mixpanel 추가

* feat : mixpanel 설정 추가

* feat : mixpanel 구현(연동 확인 완료)

* feat : 믹스패널 이벤트 Enum 추가

* feat : 믹스패널 이벤트 추가

* remove : 믹스패널 확인용 controller 제거

* refactor : 믹스패널 패키지 구조 리팩토링
  • Loading branch information
wjdwnsdnjs13 authored Sep 1, 2024
1 parent 4643b3a commit eeca5ac
Show file tree
Hide file tree
Showing 19 changed files with 136 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ application-jwt.yml
application-oauth.yml
application-sentry.yml
application-aws.yaml
application-mixpanel.yaml

# 민성 레디스 바이너리 파일
redis-server-7.2.3-mac-arm64
3 changes: 3 additions & 0 deletions application/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ dependencies {
// aop
implementation("org.springframework.boot:spring-boot-starter-aop")

// Mixpanel
implementation("com.mixpanel:mixpanel-java:_")

// test container
testImplementation("org.testcontainers:testcontainers:_")
testImplementation("org.testcontainers:junit-jupiter:_")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public class SecurityConfig {
"/api/v1/members/**",
"/actuator/**",
"/login/oauth2/code/google/**",
"/google/**"
"/google/**",
"/trackEvent"
};

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
"/api/v1/levels/info",
"/kakao",
"/api/v1/jwts",
"/google/callback"
"/google/callback",
"/trackEvent",
};

private static final Map<String, Set<String>> AUTH_METHOD_WHITELIST =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public BaseReviewResponse findReviewByReviewId(
@Parameter(hidden = true) Long memberId,
@PathVariable("reviewId") @NotNull @Parameter(description = "리뷰 PK", required = true)
Long reviewId) {
ReadReviewResult readReviewResult = readReviewUsecase.findReviewById(reviewId);
ReadReviewResult readReviewResult = readReviewUsecase.findReviewById(reviewId, memberId);
return BaseReviewResponse.from(readReviewResult.review());
}
}
5 changes: 4 additions & 1 deletion application/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,29 @@ server:
spring:
# 서브모듈 profile
profiles:
active: local
active: dev
group:
local:
- jpa
- aws
- jwt
- oauth
- mixpanel
dev:
- jpa
- aws
- jwt
- oauth
- monitoring
- mixpanel
prod:
- jpa
- aws
- jwt
- oauth
- sentry
- monitoring
- mixpanel
servlet:
multipart:
max-file-size: 10MB
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.depromeet.spot.domain.mixpanel;

import lombok.Getter;

@Getter
public enum MixpanelEvent {
REVIEW_REGISTER("review_register"),
REVIEW_REGISTER_MAX("review_register"),
REVIEW_OPEN_COUNT("review_open_count"),
REVIEW_LIKE_COUNT("review_like_count"),
REVIEW_SCRAP_COUNT("review_scrap_count"),
;

String value;

MixpanelEvent(String value) {
this.value = value;
}
}
3 changes: 3 additions & 0 deletions infrastructure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ dependencies {

// caffeine cache
implementation("com.github.ben-manes.caffeine:caffeine:_")

// Mixpanel
implementation("com.mixpanel:mixpanel-java:_")
}

tasks.bootJar { enabled = false }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.depromeet.spot.infrastructure.mixpanel.property;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "mixpanel")
public record MixpanelProperties(String token) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.depromeet.spot.infrastructure.mixpanel.repository;

import java.io.IOException;

import org.depromeet.spot.domain.mixpanel.MixpanelEvent;
import org.depromeet.spot.infrastructure.mixpanel.property.MixpanelProperties;
import org.depromeet.spot.usecase.port.out.mixpanel.MixpanelRepository;
import org.json.JSONObject;
import org.springframework.stereotype.Component;

import com.mixpanel.mixpanelapi.ClientDelivery;
import com.mixpanel.mixpanelapi.MessageBuilder;
import com.mixpanel.mixpanelapi.MixpanelAPI;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
public class MixpanelRepositoryImpl implements MixpanelRepository {

private final MixpanelProperties mixpanelProperties;

// mixpanelEvent는 eventName(이 단위로 이벤트가 묶임)
// distinctId는 사용자를 구분하는 데 사용됨.
@Override
public void eventTrack(MixpanelEvent mixpanelEvent, String distinctId) {
try {

// 믹스패널 이벤트 메시지 생성
MessageBuilder messageBuilder = new MessageBuilder(mixpanelProperties.token());

// 이벤트 생성
JSONObject sentEvent = messageBuilder.event(distinctId, mixpanelEvent.getValue(), null);

// 만든 여러 이벤트를 delivery
ClientDelivery delivery = new ClientDelivery();
delivery.addMessage(sentEvent);

// Mixpanel로 데이터 전송
MixpanelAPI mixpanel = new MixpanelAPI();
mixpanel.deliver(delivery);
} catch (IOException e) {
e.printStackTrace();
}
}
}
4 changes: 4 additions & 0 deletions usecase/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa:_") {
because("@Transactional을 위해 추가")
}

// Mixpanel
implementation("com.mixpanel:mixpanel-java:_")

}

tasks.bootJar { enabled = false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ MyReviewListResult findMyReviewsByUserId(

MyRecentReviewResult findLastReviewByMemberId(Long memberId);

ReadReviewResult findReviewById(Long reviewId);
ReadReviewResult findReviewById(Long reviewId, Long memberId);

long countByIdByMemberId(Long memberId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.depromeet.spot.usecase.port.out.mixpanel;

import org.depromeet.spot.domain.mixpanel.MixpanelEvent;

public interface MixpanelRepository {
void eventTrack(MixpanelEvent mixpanelEvent, String distinctId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import java.util.Map;

import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.domain.mixpanel.MixpanelEvent;
import org.depromeet.spot.domain.review.Review;
import org.depromeet.spot.domain.review.keyword.Keyword;
import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase;
import org.depromeet.spot.usecase.port.out.member.MemberRepository;
import org.depromeet.spot.usecase.port.out.mixpanel.MixpanelRepository;
import org.depromeet.spot.usecase.port.out.review.ReviewRepository;
import org.depromeet.spot.usecase.service.member.processor.MemberLevelProcessor;
import org.depromeet.spot.usecase.service.review.processor.ReviewCreationProcessor;
Expand All @@ -30,6 +32,7 @@ public class CreateReviewService implements CreateReviewUsecase {
private final ReviewImageProcessor reviewImageProcessor;
private final ReviewKeywordProcessor reviewKeywordProcessor;
private final MemberLevelProcessor memberLevelProcessor;
private final MixpanelRepository mixpanelRepository;

@Override
@Transactional
Expand All @@ -46,6 +49,9 @@ public CreateReviewResult create(Long blockId, Long memberId, CreateReviewComman

Member levelUpdateMember = memberLevelProcessor.calculateAndUpdateMemberLevel(member);

// 믹스패널 이벤트(후기 등록 완료) 호출
mixpanelRepository.eventTrack(MixpanelEvent.REVIEW_REGISTER, String.valueOf(memberId));

return new CreateReviewResult(savedReview, levelUpdateMember, review.getSeat());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.stream.Collectors;

import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.domain.mixpanel.MixpanelEvent;
import org.depromeet.spot.domain.review.Review;
import org.depromeet.spot.domain.review.Review.ReviewType;
import org.depromeet.spot.domain.review.Review.SortCriteria;
Expand All @@ -15,6 +16,7 @@
import org.depromeet.spot.domain.team.BaseballTeam;
import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase;
import org.depromeet.spot.usecase.port.out.member.MemberRepository;
import org.depromeet.spot.usecase.port.out.mixpanel.MixpanelRepository;
import org.depromeet.spot.usecase.port.out.review.BlockTopKeywordRepository;
import org.depromeet.spot.usecase.port.out.review.KeywordRepository;
import org.depromeet.spot.usecase.port.out.review.ReviewImageRepository;
Expand Down Expand Up @@ -46,6 +48,7 @@ public class ReadReviewService implements ReadReviewUsecase {
private final ReviewScrapRepository reviewScrapRepository;
private final ReadReviewProcessor readReviewProcessor;
private final PaginationProcessor paginationProcessor;
private final MixpanelRepository mixpanelRepository;

private static final int TOP_KEYWORDS_LIMIT = 5;
private static final int TOP_IMAGES_LIMIT = 5;
Expand Down Expand Up @@ -185,10 +188,13 @@ public List<ReviewYearMonth> findReviewMonths(Long memberId, ReviewType reviewTy
}

@Override
public ReadReviewResult findReviewById(Long reviewId) {
public ReadReviewResult findReviewById(Long reviewId, Long memberId) {
Review review = reviewRepository.findById(reviewId);
Review reviewWithKeywords = mapKeywordsToSingleReview(review);

// 믹스패널 이벤트(조회수) 발생
mixpanelRepository.eventTrack(MixpanelEvent.REVIEW_OPEN_COUNT, String.valueOf(memberId));

return ReadReviewResult.builder().review(reviewWithKeywords).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public class ReviewLikeService implements ReviewLikeUsecase {
private final UpdateReviewUsecase updateReviewUsecase;
private final ReviewLikeRepository reviewLikeRepository;

// TODO : Service 코드와 분리하기
// private final MixpanelRepository mixpanelRepository;

@Override
@DistributedLock(key = "#reviewId")
public void toggleLike(final Long memberId, final long reviewId) {
Expand All @@ -34,6 +37,11 @@ public void toggleLike(final Long memberId, final long reviewId) {
}

addLike(memberId, reviewId, review);

// TODO : 테스트 시에도 이벤트 발생함.
// 믹스패널 이벤트(좋아요 수) 발생
// mixpanelRepository.eventTrack(MixpanelEvent.REVIEW_LIKE_COUNT,
// String.valueOf(memberId));
}

public void cancelLike(final long memberId, final long reviewId, Review review) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import java.util.List;

import org.depromeet.spot.domain.mixpanel.MixpanelEvent;
import org.depromeet.spot.domain.review.Review;
import org.depromeet.spot.domain.review.scrap.ReviewScrap;
import org.depromeet.spot.usecase.port.in.review.ReadReviewUsecase;
import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase;
import org.depromeet.spot.usecase.port.in.review.page.PageCommand;
import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase;
import org.depromeet.spot.usecase.port.out.mixpanel.MixpanelRepository;
import org.depromeet.spot.usecase.port.out.review.ReviewScrapRepository;
import org.depromeet.spot.usecase.service.review.ReadReviewService;
import org.depromeet.spot.usecase.service.review.processor.PaginationProcessor;
Expand All @@ -29,6 +31,8 @@ public class ReviewScrapService implements ReviewScrapUsecase {
private final ReadReviewProcessor readReviewProcessor;
private final PaginationProcessor paginationProcessor;

private final MixpanelRepository mixpanelRepository;

@Override
public MyScrapListResult findMyScrappedReviews(
Long memberId, MyScrapCommand command, PageCommand pageCommand) {
Expand Down Expand Up @@ -86,6 +90,10 @@ public boolean toggleScrap(final long memberId, final long reviewId) {
}

addScrap(memberId, reviewId, review);

// 믹스패널 이벤트(스크랩 수) 발생
mixpanelRepository.eventTrack(MixpanelEvent.REVIEW_SCRAP_COUNT, String.valueOf(memberId));

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.depromeet.spot.usecase.port.in.review.page.PageCommand;
import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase.MyScrapCommand;
import org.depromeet.spot.usecase.port.in.review.scrap.ReviewScrapUsecase.MyScrapListResult;
import org.depromeet.spot.usecase.port.out.mixpanel.MixpanelRepository;
import org.depromeet.spot.usecase.service.fake.FakeReviewScrapRepository;
import org.depromeet.spot.usecase.service.review.processor.PaginationProcessor;
import org.depromeet.spot.usecase.service.review.processor.ReadReviewProcessor;
Expand All @@ -37,6 +38,7 @@ class ReviewScrapServiceTest {
@Mock private ReadReviewService readReviewService;
@Mock private ReadReviewProcessor readReviewProcessor;
@Mock private PaginationProcessor paginationProcessor;
@Mock private MixpanelRepository mixpanelRepository;

@BeforeEach
void init() {
Expand All @@ -49,7 +51,8 @@ void init() {
fakeReviewScrapRepository,
readReviewService,
readReviewProcessor,
paginationProcessor);
paginationProcessor,
mixpanelRepository);
}

@Test
Expand Down
2 changes: 2 additions & 0 deletions versions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ plugin.io.spring.dependency-management=1.0.11.RELEASE

plugin.com.diffplug.spotless=6.21.0

version.com.mixpanel..mixpanel-java=1.5.3

version.io.jsonwebtoken..jjwt=0.12.6

version.junit=5.9.1
Expand Down

0 comments on commit eeca5ac

Please sign in to comment.