포트폴리오/Eighteen

뱃지 시스템 적용

do_hyuk 2025. 1. 15. 22:42

뱃지 종류

다양한 업적들이 추가되도 문제되지 않게 확장성을 고려해 만드려고 한다.

  • 첫 발자국
    앱에
    최초 가입 시 얻을 수 있는 뱃지이다.

  • 완벽한 첫 인상
    프로필 사진, 개인 정보, 자문자답 모두 입력 시 얻을 수 있는 뱃지이다.
  •  인사
    첫 채팅 메시지를 보내면 얻을 수 있는 뱃지이다.

  • 하트 전도사
    다른 사람의 프로필에 좋아요 50번 이상 누르면 얻을 수 있는 뱃지이다.

  • 첫 승리
    토너먼트에서 첫 승리 시 얻을 수 있는 뱃지이다.

  • 새싹(10개) - 유명인(100개)
    자신의 좋아요 수 10개 달성하면 얻을 수 있는 뱃지
    이다.

요구사항

  • 업적을 달성하면 뱃지를 받을 수 있다.
    - 달성하는 순간 받아진다.

  • 업적을 달성하면 보상을 받을 수도 있다.
    - 보상은 아직 미정

  • 마이페이지에서 나의 뱃지의 개수를 볼 수 있고, 클릭 시 최대 9개의 뱃지가 보여진다.
    - 최대 개수는 늘어날 수 있기 때문에 페이징 적용해야 할 수 있음

  • 뱃지를 누르면 아래 항목을 응답
    - 뱃지 이름
    - 획득 했다면 얻은 날짜
    - 달성률 (현재값 / 목표값): 미정
    - 업적 달성 조건 설명
    - 보상: 미정

기획

가장 핵심이 되는 부분은 확장 가능성이다. 

  • 업적 기능이 보상 시스템과 결합될 가능성
    - 업적의 보상으로 뱃지 뿐만 아니라 다양한 포인트나 선물을 주는 것도 생각해봐야 할 듯

  • 새로운 종류의 업적 추가 가능성 (기간 한정 업적 등)

설계 단계에서부터 다양한 방향으로 확장될 가능성을 염두해두기로 했다.

그리고 업적의 목표를 생각해보니 크게 2가지 분류로 나누어야 했다.

  • 누적형 업적: 달성 방법은 같은데 조건이 세분화 되어있음
    ex) 좋아요 10개 달성, 50개 달성, 100개 달성 등

  • 단발성 업적: 연관된 업적이 없고 한 번 달성하면 끝인 업적
    ex) 토너먼트 첫 우승 등

테이블 설계

 

  • 업적 테이블
    - 업적에 대한 정보가 저장되는 테이블
    - next_achievement_id : 누적형 업적을 위해 필요하다. 해당 업적의 다음에 진행되는 업적의 id를 저장해둔다.
    만약 누적형 업적의 마지막이거나 단발성 업적이라면 null 이 들어간다.
    - reward_type , reward_amount : 추후에 보상 기능이 추가될 경우 활용하기 위해 추가해두었다.
    - start_at , end_at : 기간 한정 업적이 필요할 경우를 대비 하여 추가해두었다.

  • 회원_업적 테이블
    - user 별로 진행 중인 업적에 대한 정보가 저장되는 테이블
    - current_value : 유저가 해당 업적에서 지금까지 달성한 값이 들어간다.
    - obtained_at : 업적의 목표를 달성하여 뱃지를 획득한 날짜가 들어간다.
    - is_reward_received : 추후 추가 될 수 있는 보상을 받았는지의 여부가 들어간다.

로직

로직은 크게 두 가지로 나뉘는데,

  1. 업적을 조회하는 로직
  2. 업적을 업데이트 하는 로직

이 모든 로직을 하나의 클래스에서 구현하기에는 무리가 있다고 판단했다.

두 가지 로직의 성격이 달랐고, 업적을 업데이트 하는 로직은 추후에 새로운 기능이 많이 추가될 가능성이 있었기 때문에 두 가지의 클래스로 분리하여 구현했다.

 

AchievementReader.Class: 업적을 조회하는 비즈니스 로직만을 담당

AchievementManager.Class: 업적을 업데이트하는 비즈니스 로직만을 담당


조회 로직

조회 로직은 특별히 복잡한 로직은 없기에 서비스 로직만 준비했다.

# 업적 상세 정보 조회[AchievementReaderService.Class]
public Achievement getDetailAchievement(Integer id) {
   return achievementRepository.findById(id).orElseThrow(
           () -> new NotFoundException(ErrorCode.NOT_FOUND_ACHIEVEMENT)
   );
}

# 내 업적 조회


# 내 업적 개수 조회

업데이트 로직