TIL(Today I Learned)/프로젝트

[TIL] Trello(칸반보드) 프로젝트

jiyoon0000 2025. 2. 20. 23:18
  • 프로젝트 명 : 판 떼기
  • 소개
    • 한 줄 정리 : 트렐로를 모티브한 일정관리 서비스
    • 내용 : 트렐로를 모티브한 일정관리 서비스
  • 진행 날짜 : 2024.12.23 ~ 2024.12.31

 

프로젝트 요약

1. 프로젝트 목적

:신입 2년차 백엔드 개발자 채용 공고에서 요구하는 핵심 기술 역량을 실전 프로젝트를 통해 학습하고, 이를 기반으로 개발 역량을 검증하는 것이 목표

    • 백엔드 개발 기술 습득
      • Java & Spring Boot 기반의 REST API 개발
      • JPA & MySQL을 활용한 데이터 모델링 및 트랜잭션 관리
      • Spring Security & JWT 기반 인증/인가 구현
    • AWS 클라우드 환경에서의 배포 경험
      • EC2 + Docker + Docker Compose로 컨테이너화된 애플리케이션 배포
      • RDS(MySQL) 분리를 통한 데이터 관리 효율성 향상
      • CI/CD 자동화 학습(GitHub Actions 연동)
      • S3를 활용한 파일 업로드 스토리지 구축
    • 협업 및 코드 품질 향상
      • AOP(Aspect Oriented Programming) 및 Interceptor를 활용하여 중복 코드 제거
      • Redis를 활용한 동시성 문제 해결 및 성능 개선
      • 코드 리뷰 및 기능 설계

2. 프로젝트 구현 (가이드)

<필수 구현>

  • 회원가입/로그인
    • 이메일 형식 ID와 Bcrypt 암호화된 비밀번호 사용
    • JWT 인증 및 권한(일반 유저/관리자) 설정
    • 예외처리 : 중복 가입, 유효성 검사 실패 시 오류 반환
  • 멤버 및 역할 관리
    • 워크스페이스 내 멤버 초대 및 역할 부여
    • 권한에 따라 기능 접근 제한 적용
  • 워크스페이스 : CRUD / 초대된 멤버만 접근 가능
  • 보드 : CRUD / 보드 내부에서 리스트 및 카드 관리
  • 리스트 : CRUD / 리스트 순서 변경 기능 지원
  • 카드 : CRUD
    • 검색 : 카드 제목, 내용, 담당자 기반 검색 / 특정 보드에 속한 모든 카드 검색
  • 댓글 : CRUD / 댓글 작성자만 수정, 삭제 가능
  • 첨부파일 : AWS S3 파일 업로드(jpg, png, pdf, csv) / 파일 크기 제한(5MB) 및 삭제 기능 제공
  • 알림 : 카드 변경, 멤버 추가, 댓글 작성 시 실시간 알림 기능 / 슬랙 혹은 디스코드
  • 배포
    • 코드 변경 시, 자동으로 빌드 및 테스트를 수행하는 CI 파이프라인을 구성
    • 테스트가 성공적으로 완료되면 프로덕션에 자동 배포되도록 CD 파이프라인을 설정
    • CI/CD를 활용해 애플리케이션의 빌드, 테스트, 배포 과정을 자동화해 개발 효율성과 안정성을 높임

<도전 구현>

  • 최적화(Indexing)
    • 카드 검색 속도 향상을 위한 인덱스 적용
    • 쿼리 속도 분석 및 성능 개선
  • 동시성 제어(Concurrency Control)
    • 카드 이동 시 동시성 충돌 방지
    • 낙관적 락, 비관적 락, 분산 락을 활용하여 데이터의 일관성과 무결성 유지
  • 캐싱(Caching)
    • Redis를 활용한 조회수 캐싱
    • 조회수는 매일 자정에 자동 초기화

사용한 기술 및 개념
& 맡은 역할

1. 백엔드

  • Spring Boot : RESTful API 개발 및 비즈니스 로직 구현
  • Spring Security + JWT : 인증 및 권한 관리(Bcrypt 비밀번호 암호화)
  • JPA & Hibernate : ORM 기반 데이터 관리(Cascade 활용)
  • MySQL(RDS) : 데이터 모델링 및 성능 최적화(Indexing)

2. 인프라 & 배포

  • AWS EC2 : 애플리케이션 배포
  • AWS S3 : 첨부파일 저장소
  • AWS RDS(MySQL) : 데이터베이스 호스팅 및 성능 최적화
    • 데이터베이스 호스팅 : AWS RDS에서 제공하는 DB를 사용
  • Docker & Docker-Compose : 컨테이너화 및 로컬 개발 환경 통합
  • CI/CD (GitHub Actions + EC2 배포) : 자동 빌드 및 배포 파이프라인 구축

3. 데이터 관리 & 최적화

  • Redis : 조회수 캐싱, 동시성 제어(Locking), 리프레시 토큰 관리
  • 트랜잭션 관리 : @Transactional을 적용하여 데이터 일관성 유지

4. Tool

  • GitHub & GitHub Actions : 코드 버전 관리 및 CI/CD 자동화
  • Postman : API 테스트 및 문서화
  • IntelliJ IDEA : 개발 환경 설정 및 코드 작성
  • Lombok : @Getter, @NoArgsConstructor 등 코드 간결화

5. 팀 내에서 맡은 역할

  • 워크스페이스(Workspace)
    • 워크스페이스 생성, 수정, 삭제, 조회 기능 구현
    • 워크스페이스 멤버 초대 및 역할 관리 기능 추가
  • 리스트(List)
    • 리스트 생성, 수정(순서 변경 포함), 삭제, 조회 기능 구현
    • GreenHopper 알고리즘을 활용한 리스트 정렬 및 순서 변경 기능 구현
  • 첨부파일(File)
    • AWS S3를 활용한 파일 업로드 및 삭제 기능 구현
    • MultipartFile 처리 및 파일 형식 검증 로직 추가
    • 파일 조회 API 구현

팀에서 구현한 내용
& 내가 구현한 내용

1. 프로젝트 설계

-와이어 프레임

-ERD 작성

-API 명세서 작성

https://documenter.getpostman.com/view/18429295/2sAYJ4gzPD

 

트렐로

The Postman Documenter generates and maintains beautiful, live documentation for your collections. Never worry about maintaining API documentation again.

documenter.getpostman.com

-코드 컨벤션

  • 코드 스타일 및 네이밍 규칙
    • 클래스 및 메서드 네이밍
      • 클래스명 : PascalCase 사용
      • 메서드명 : camelCase 사용
    • 패키지 구조 : 도메인별 패키지 구조, 공통 기능은 common 패키지에 정리
  • DTO 및 Entity 변환 방식
    • Entity -> ResponseDto 변환 : Entity를 ResponseDto로 변환할 때는 생성자를 활용
    • RequestDto -> Entity 변환 : RequestDto를 Entity로 변환할 때는 spread 방식 사용
  • Controller - Service 간 데이터 전달 방식
    • RequestDto 직접 전달 금지 : Controller에서 RequestDto를 바로 Service로 넘기지 않음 -> 개별 필드로 전환 후 전달
    • Service -> Controller 데이터 반환 방식 : Service는 ResponseDto를 반환하고, Controller에서 CommonResponseDto로 감싸서 반환
  • 공통 응답 DTO 사용
    • 단일 응답(CommonResponseDto)
    • 리스트 응답(CommonListResponseDto)
    • Service -> Controller 데이터 반환 시 항상 DTO 사용
    • Controller에서는 CommonResponseDto 또는 CommonListRepsonseDto로 감싸서 반환
//단일 응답
public class CommonResponseDto<T> {
    private final String message;
    private final T data;

    public CommonResponseDto(String message, T data) {
        this.message = message;
        this.data = data;
    }
}


//리스트 응답
public class CommonListResponseDto<T> {
    private final String message;
    private final List<T> data;

    public CommonListResponseDto(String message, List<T> data) {
        this.message = message;
        this.data = data;
    }
}

 

  • Enum 사용 규칙
    • 대문자로만 작성하고, value 값 없이 사용
    • 모든 상태 값은 Enum으로 관리
  • 서비스 인터페이스 사용 금지
    • Service interface 생성하지 않고, 바로 구현 클래스를 사용
  • Lombok 사용 규칙
    • @AllArgsConstructor, @Setter 사용 금지
    • Getter 및 RequiredArgsConstructor 사용
  • 예외 처리 및 에러 메시지 관리
    • @ControllerAdvice + @ExceptionHandler를 활용하여 전역 예외 처리
    • 예외 메시지는 Enum으로 관리
  • 코드 스타일
    • Formatter 사용하여 일관된 띄어쓰기 적용
    • import * 규칙 -> 7개 이상은 *

2. 구현 기능 - 내가 맡은 부분

-워크스페이스

  • 워크스페이스 생성, 수정, 삭제, 조회 기능
    • 관리자가 새로운 워크스페이스를 생성할 수 있음
    • 워크스페이스 정보(이름, 설명) 수정 가능
    • 워크스페이스 삭제 가능(관련 데이터 일괄 삭제)
    • 워크스페이스 조회 최적화
  • 워크스페이스 멤버 초대 기능(이메일 기반 초대)
    • 특정 이메일을 입력하여 해당 유저를 초대할 수 있음
    • 초대 가능한 역할(관리자, 멤버, 읽기 전용) 설정 가능
  • 워크스페이스 내 권한 관리
    • 관리자는 모든 기능 수행 가능
    • 멤버는 보드 생성 가능, 일부 기능 제한
    • 읽기 전용 사용자는 조회만 가능
  • 적용 기술 및 개념
    • JPA 쿼리 최적화
      • JOIN FETCH를 활용하여 N+1 문제 해결
      • @Query("SELECT m FROM Member m JOIN FETCH m.workspace WHERE m.user = :user")

-리스트

  • 리스트 생성, 수정, 삭제 기능
    • 보드 내에서 새로운 리스트를 추가할 수 있음
    • 리스트의 제목을 수정할 수 있음
    • 리스트 삭제 시, 해당 리스트 내 카드도 함께 삭제됨
  • 리스트 순서 정렬(GreenHopper 알고리즘 적용)
    • 리스트의 순서는 BigDecimal을 활용한 GreenHopper 알고리즘으로 정렬
    • 리스트 이동 시 기존 리스트의 순서값을 기준으로 새로운 중간값을 자동 생성하여 정렬
  • 적용 기술 및 개념
    • GreenHopper 알고리즘 적용
      • BigDecimal 기반의 리스트 정렬 방식
      • 리스트를 특정 위치로 이동할 때 기존 값과 새로운 값의 중간값을 자동 생성하여 정렬
      • 기존 정수 기반 정렬 방식의 한계를 해결하고, 리스트 간격 유지 및 정렬 충돌 방지
    • 트랜잭션 관리 적용
      • 리스트 생성, 수정, 삭제 시 데이터 정합성 유지를 위해 트랜잭션 적용

-첨부파일

  • 파일 업로드 및 삭제 기능(AWS S3 사용)
    • 카드에 파일 업로드 가능
    • 사용자는 자신이 업로드한 파일만 삭제할 수 있음
  • 파일 검증(크기 및 확장자 제한)
    • 허용 확장자 : jpg, png, pdf, csv
    • 최대 5MB 파일만 업로드 가능
  • 적용 기술 및 개념
    • MultipartFile : 업로드된 파일의 유효성 검사(getSize(), getOriginalFilename())
    • AWS S3 SDK(software.amazon.awssdk.services.s3.S3Client)
      • S3Client.putObject()를 활용한 파일 업로드 처리
      • S3Client.deleteObject()를 통한 파일 삭제 구현
    • 파일 검증 로직
      • 5MB 이상의 파일 업로드 시 BAD_REQUEST 예외 발생
      • 지원되지 않는 확장자(jpg, png, pdf, csv 외) 업로드 시 BAD_REQUEST 예외 발생
    • Spring Security 기반 권한 제어
      • authentication.getName() 을 활용하여 사용자가 자신의 파일만 삭제할 수 있도록 제한

3. 팀원 구현 기능 분석

-회원가입/로그인

  • 회원가입 : Bcrypt를 사용하여 비밀번호를 해싱하여 저장
  • 로그인 : 로그인 성공 시 JWT AccessToken, RefreshToken 발급
  • JWT 인증 관리
    • 모든 API 요청에 대해 JWT AccessToken 검증 후 인증 처리
    • AccessToken이 만료되면 RefreshToken을 이용해 재발급
    • RefreshToken을 Redis에 저장하여 인증 상태 유지
  • 적용 기술 및 개념
    • Spring Security & JWT 인증
      • JwtProvider 클래스를 이용해 JWT 생성 및 검증
      • Authentication 객체를 활용하여 인증 정보 관리
    • Bcrypt 비밀번호 암호화 : PasswordEncoder를 사용하여 암호화 후 저장
    • Redis 기반 토큰 관리
      • RefreshToken을 Redis에 저장하여 인증 유지
      • StringRedisTemplate을 활용하여 Redis에서 RefreshToken 조회 및 삭제

-카드(LexoRank 적용)

  • 카드 정렬(LexoRank 적용)
    • 리스트 내에서 카드의 순서를 변경할 수 있음
    • LexoRank 알고리즘을 활용하여 정렬 유지
    • 중간 삽입 시 기존 순서값을 고려하여 새로운 순서값 계산
  • 적용 기술 및 개념
    • LexoRank 기반 카드 정렬
      • 리스트 내에서 카드 위치를 정밀한 순서 값으로 정렬 유지
      • LexoRank.getMiddleRank(before, after)를 이용해 카드 정렬

-알림(Slack 연동)

  • 멤버 추가, 카드 변경, 댓글 작성 등 주요 이벤트에 대한 실시간 알림 제공
  • 알림 저장 로직
    • Notify 엔티티를 생성하여 데이터베이스에 알림 내역 저장
    • created_at 필드를 활용하여 알림 발생 시간을 기록
    • 특정 워크스페이스와 연관된 알림을 관리
  • AOP(Aspect-Oriented Programmin) 활용
    • @AfterReturning 어노테이션을 사용하여 특정 컨트롤러의 메서드가 실행된 후 알림을 자동으로 전송
    • WorkspaceController, BoardController, CardController, ListController, CommentController의 모든 메서드에 적용
  • Slack API 연동
    • callSlackApi() 메서드를 사용하여 Slack의 chat.postMessage API 호출
    • 요청 시 워크스페이스의 notifyToken과 notifyChannel을 활용하여 알림 전송
    • 각 엔티티의 변경 사항을 감지하여 Slack 메시지 자동 전송
  • 적용 기술 및 개념
    • AOP 기반 이벤트 감지(@Aspect, @AfterReturning)
      • 특정 컨트롤러의 실행 결과를 감지하여 알림을 자동 실행
    • Slack API 호출(RestTemplate)
      • HttpHeaders를 사용하여 Authorization 헤더 설정
      • restTemplate.exchange()를 활용하여 POST 요청 전송

-최적화

  • 카드 검색 성능 최적화
    • title, description 컬럼에 인덱스 추가
    • 검색 쿼리(JPQL) 최적화를 통해 N+1 문제 해결
  • 대량 데이터 성능 테스트
    • PostConstruct를 활용하여 10만개의 카드 데이터 삽입 및 검색 쿼리 실행시간 측정 및 성능 비교
  • 인덱싱 vs 쿼리 최적화 테스트
    • Test1 : 인덱싱 적용 전/후 조회 속도 비교
    • Test2 : JOIN FETCH를 활용한 쿼리 최적화 적용
    • Test3 : 인덱싱 + 쿼리 최적화 적용
  • 최적화 적용 우선순위 결정
    • 쿼리가 무거운 경우 -> 인덱싱 효과가 크다
    • 쿼리가 상대적으로 가벼운 경우 -> 쿼리 최적화가 더 중요
    • 최적화 순서 : 쿼리 최적화를 우선 적용 후, 필요하면 인덱싱으로 보완

  • 적용 기술 및 개념
    • 데이터베이스 인덱싱
      • 단일 인덱스 : idx_title, idx_description
      • 복합 인덱스 : idx_title_description
      • 검색 시 불필요한 Full Table Scan 방지
    • JPQL 최적화 : JOIN FETCH를 활용해 연관 테이블을 한 번의 쿼리로 가져와 N+1 문제 해결
    • 성능 테스트 : PostConstruct로 대량 데이터 삽입, 랜덤 데이터 생성 후 실제 환경과 유사한 조건에서 검색 테스트 수행
    • 쿼리 실행시간 로깅(AOP 활용)
      • 검색 실행 시간을 자동으로 측정하여 성능 분석
      • 실행 시간을 자동으로 측정하여 느린 쿼리를 분석하고 최적화 가능

-동시성 제어

  • 리스트 및 카드의 동시 수정 방지
    • 여러 사용자가 동시에 리스트 순서를 변경할 경우 충돌 방지
    • Redis 기반 분산 락을 활용하여 순서 재정렬 시 충돌 방지
  • 리스트 정렬 시 락 적용
    • updateList() 메서드에 Redis SETNX(분산 락) 사용
    • LOCK_EXPIRATION_TIME을 설정하여 일정 시간 이후 락 자동 해제
  • 적용 기술 및 개념
    • Redis 기반 분산 락 활용(SETNX)
      • StringRedisTemplate을 활용하여 특정 리스트 ID에 대한 락 설정
      • setIfAbsent()을 활용하여 동시 수정 방지
    • 트랜잭션 관리(@Transactional)
      • 리스트 업데이트 시 트랜잭션을 활용하여 정합성 유지

-캐싱

  • 카드 상세 조회 시, 조회수를 Redis에 캐싱하여 데이터베이스 부하 감소
  • Redis Sorted Set(ZSet)을 활용하여 조회수 기반 카드 랭킹 시스템 구축
  • 조회수 중복 방지 : 동일 유저가 하루에 한 번만 증가하도록 TTL 설정
  • 매일 자정 Redis 캐시 초기화(Spring Scheduler 적용)
  • 적용 기술 및 개념
    • Redis(String, ZSet 활용)
      • String -> 카드별 조회수 저장
      • ZSet -> 조회수 기반으로 인기 카드 순위 저장 및 조회
    • Spring Scheduler(@Scheduled)
      • 매일 자정 조회수 캐시 자동 초기화
    • 동시성 제어
      • StringRedisTemplate을 이용해 조회수 중복 증가 방지
      • TTL(1일) 설정을 통해 특정 유저가 조회수를 무한 증가시키지 못하도록 제한

-배포(Docker + AWS 기반 CI/CD 파이프라인)

  • GitHub Actions를 이용하여 CI/CD 자동화 파이프라인 구축
  • Docker를 활용한 컨테이너화 및 배포 자동화
  • AWS EC2에 Docker Compose를 사용하여 애플리케이션 배포
  • AWS RDS(MySQL) 분리 운영 : 데이터베이스와 애플리케이션 서버 분리
  • 적용 기술 및 개념
    • CI/CD 파이프라인 구축
      • GitHub에 코드를 push 하면 GitHub Actions가 동작하여 CI/CD 실행
      • CI : 코드 빌드 및 테스트 자동화
      • CD : Docker 이미지 빌드 -> Docker Hub에 push -> EC2에서 자동 배포
    • Docker 기반 컨테이너화
      • Docker를 활용하여 Spring Boot 애플리케이션 컨테이너화
      • Docker Compose를 사용하여 app, db, redis 컨테이너 관리
    • AWS EC2 배포
      • EC2에 접속하여 docker-compose를 실행하여 애플리케이션 배포
      • Docker Hub에서 최신 이미지를 pull 한 후 재시작
      • GitHub Actions에서 자동으로 최신 이미지를 배포하는 스크립트 실행
    • AWS RDS(MySQL) 분리 운영
      • 데이터베이스를 AWS RDS(MySQL)로 분리하여 EC2와 독립적으로 운영, 안정성 증가

진행 중 어려웠던 점과 해결방법
& 피드백

1. 진행 중 문제점과 해결방법은 트러블 슈팅을 작성해 정리

https://jy3574.tistory.com/130

 

[트러블 슈팅] Trello(칸반보드) 프로젝트

1. GreenHopper 알고리즘 정밀도 문제1)개요리스트 정렬을 위해 GreenHopper 알고리즘을 사용하여 position 값을 생성하였는데, 처음엔 int 자료형을 사용하여 중간값을 계산했지만, 정밀도 문제로 인해 예

jy3574.tistory.com

2. 설계에 관한 피드백

  • 카드 검색 API에서 boardId가 누락됨 -> 파라미터로 추가
  • 비밀번호 확인 API의 URL은 RESTful 규약을 따르기 위해 users/check-password로 변경
  • 알림 테이블은 따로 만들어서 관리(workspace 별로 알림을 발송하도록 workspaceID 를 외래키로 가지고 있는채로)

3. 코드 구현 후 최종 피드백

  • 리스트 생성 시 Position 최적화
    • findByBoardId() 대신 countByBoardId()를 활용하여 리스트 개수 +1을 position 값으로 설정하면 성능 최적화 가능
    • 불필요한 MAX 연산을 줄여 DB 성능 최적화
  • User 정보 조회 방식 개선
    • 현재 : findByEmail()을 사용하여 서비스 레이어에서 매번 DB를 조회하여 User 정보를 가져옴
    • Spring Security 적용 시 @AuthenticationPrincipal UserDetailsImpl userDetailsImpl을 사용하여 SecurityContextHolder에서 직접 User 정보를 가져오기
    • 서비스 레이어에서 추가적인 DB 조회 없이 유저 정보를 빠르게 활용 가능
  • 불필요한 API 제거
    • 카드, 유저, 보드 등에서 이미지를 조회할 때 해당 이미지의 URL만 응답하면 프론트엔드에서 자동으로 이미지가 로드됨
    • 파일을 조회하는 API를 제거하고, 각 엔티티의 응답 DTO에서 imageUrl을 포함하는 방식으로 개선
  • InterceptorUtils 내 getTokenFromRequest() 개선
    • Spring Security가 적용된 경우, SecurityContextHolder에서 직접 User 정보를 가져올 수 있음
  • S3 파일 정리 로직 추가
    • 카드 또는 유저 프로필 삭제 시, S3에서 해당 파일도 함께 삭제하도록 로직 추가
    • AWS SDK의 deleteObject()를 활용하여 S3에서 불필요한 파일 제거
  • 분산락 개선
    • 현재 : Redis를 사용한 분산락을 적용하여 동시성 제어를 하고 있지만, 락 해제와 트랜잭션 종료 사이의 짧은 시간 차이 동안 다른 쓰레드가 락을 점유할 가능성이 있음
    • 트랜잭션 종료 후에 락을 해제하는 방식으로 코드 수정

느낀점 및 개선해야할 점

작성 중...

 

 

 

 

 

 

 

 


적용한 알고리즘

https://jy3574.tistory.com/131

 

[알고리즘] LexoRank 알고리즘

LexoRank 알고리즘 개념LexoRank는 동적인 정렬을 효율적으로 유지하기 위해 설계된 알고리즘으로, 연속적인 데이터의 순서를 유지하면서도 중간 삽입이 가능하도록 설계된 정렬 방식 Trello와 같은

jy3574.tistory.com