Skip to content

Commit e1004e3

Browse files
soonge2yunabyteYuna
authored
[Fix] 익명/기권 처리 로직 개선 및 adminVote 표시 제어 (#74)
* [Feat] 소셜 로그인 및 토큰 재발급 API 개발 (#24) * feat: DB 연결 및 Spring Security 기본 설정 완료 * feat: User 도메인 추가 (#16) * feat: Bast Entity 추가 (#16) * feat: 카카오 OAuth 로그인 기능 구현 (#16) - 인가 코드로 액세스 토큰 요청 - 카카오 사용자 정보 조회 후 회원가입 또는 로그인 - JWT 액세스/리프레시 토큰 발급 - 리프레시 토큰은 HttpOnly 쿠키에 저장 - 전략 패턴 기반 구조 설계 (OAuthLoginStrategy) * feat: 리프레시 토큰 저장 로직 구현 (#16) * feat: 토큰 재발급 api 구현 (#16) * feat: 리프레시 토큰 만료 시 DB에서 삭제하는 코드 추가 (#16) * feat: 리프레시 토큰 UUID 방식으로 변경 (#16) * refactor: 서비스 클래스 이름 통일 (JwtTokenProvider → JwtTokenService) (#16) * feat: 커스텀 예외 처리 도입 및 분기 적용 - 소셜 로그인, 토큰 재발급 (#16) - AuthException, UserException 등 도메인별 BaseException 상속 구조 설계 - AuthErrorCode, UserErrorCode enum 정의 및 상태 코드 분리 - JwtTokenService, RefreshTokenService, UserValidator 등에서 커스텀 예외로 전환 - 로그인, 토큰 재발급 등에서 NO_TOKEN, INVALID_TOKEN, USER_WITHDRAWN 등 세분화된 예외 분기 처리 * refactor: createAccessToken → issueAccessToken으로 이름 통일 및 만료 시간 상수화 (#16) * refactor: 리프레시 토큰 발급 시 기존 리프레시 토큰 삭제 후 새 토큰 발급 로직 추가 (#16) * [Chore] dev 배포 환경 준비 및 테스트용 기능 추가 (#26) * feat: 프론트엔드 연동 테스트용 GET /api/v1/test/ping API 구현 (#22) * feat: AI 서버 연동 테스트용 POST /api/v1/test/ai-votes API 추가 (#22) * feat: AI 서버 요청용 서비스 로직 구현 (#22) - POST /api/v1/moderation 요청을 위한 RestTemplate 기반 클라이언트 작성 - 요청 실패 시 예외 처리 포함 - ModerationRequest/Response DTO 정의 * test: Mock AI 컨트롤러 및 테스트 환경 구성 (#22) - POST /mock-ai/api/v1/moderation 엔드포인트 추가 - CSRF 비활성화된 테스트 전용 SecurityConfig 구성 - MockMvc 테스트 작성 (정상 요청/잘못된 요청) - @activeprofiles("test") 설정 적용 * chore: 환경별 application 설정 파일 분리 (local, dev, prod) (#22) * chore: 환경별 SecurityConfig 파일 분리 (local, dev, prod) (#22) * chore: 환경별 설정 파일 분리 및 환경변수 적용으로 설정 관리 개선 (#22) * feat: dev 환경에 프론트엔드 도메인 기반 CORS 설정 추가 (#22) * chore: AI 콜백 api 주소를 실제 주소로 변경하고 ai 도메인 하위로 이동 (#22) * [Feat] 프론트-백-AI 서버 간 연동 테스트를 위한 엔드포인트 추가 (#27) * feat: 프론트엔드 연동 테스트용 GET /api/v1/test/ping API 구현 (#22) * feat: AI 서버 연동 테스트용 POST /api/v1/test/ai-votes API 추가 (#22) * feat: AI 서버 요청용 서비스 로직 구현 (#22) - POST /api/v1/moderation 요청을 위한 RestTemplate 기반 클라이언트 작성 - 요청 실패 시 예외 처리 포함 - ModerationRequest/Response DTO 정의 * test: Mock AI 컨트롤러 및 테스트 환경 구성 (#22) - POST /mock-ai/api/v1/moderation 엔드포인트 추가 - CSRF 비활성화된 테스트 전용 SecurityConfig 구성 - MockMvc 테스트 작성 (정상 요청/잘못된 요청) - @activeprofiles("test") 설정 적용 * chore: 환경별 application 설정 파일 분리 (local, dev, prod) (#22) * chore: 환경별 SecurityConfig 파일 분리 (local, dev, prod) (#22) * chore: 환경별 설정 파일 분리 및 환경변수 적용으로 설정 관리 개선 (#22) * feat: dev 환경에 프론트엔드 도메인 기반 CORS 설정 추가 (#22) * chore: AI 콜백 api 주소를 실제 주소로 변경하고 ai 도메인 하위로 이동 (#22) * feat: AI 서버 연동 테스트용 엔드포인트 추가 (/test/ping-ai) (#22) * chore: MockAiControllerTest 삭제 및 local 프로필 추가 * chore: .gitignore에 .env 파일 및 로컬 실행 스크립트(.sh) 추가 * [Feat] JWT 인증 필터 구현 (#39) * [Feat] 로그아웃 API 구현 및 인증 실패 시 401 응답 처리 (#40) * feat: 리프레시 토큰 삭제 기반 로그아웃 API 구현 (#28) - JwtAuthenticationFilter: 요청 헤더에서 액세스 토큰 추출 및 인증 처리 - JwtTokenService: validateAccessToken → validateAndExtractUserId 통합 - SecurityConfig: 인증 필터 등록 및 세션 관리 정책 설정 - 로그아웃 API: 리프레시 토큰 삭제 처리, ALREADY_LOGGED_OUT 응답 분기 * fix: JWT 인증 실패 시 403 → 401 응답으로 수정 (#28) - JwtAuthenticationFilter에서 AuthException을 AuthenticationException으로 wrapping하여 Spring Security 흐름에 맞게 예외 전달 - CustomAuthenticationEntryPoint를 통해 401 응답 및 커스텀 메시지(JSON) 반환 - TOKEN_EXPIRED, INVALID_TOKEN 등의 JWT 오류를 JSON 응답으로 구분하여 전달 가능 - 기존 403 응답 문제 해결 (Http403ForbiddenEntryPoint → CustomAuthenticationEntryPoint로 정상 위임됨) * [Feat] 투표 도메인 엔티티 및 리포지토리 생성 (#41) * feat: Vote 엔티티 생성 (#31) * feat: VoteResponse 엔티티 생성 (#31) * feat: VoteResult 엔티티 생성 (#31) * feat: VoteModerationLog 엔티티 생성 (#31) * feat: VoteModerationLog 리포지토리 생성 (#31) * feat: Vote 리포지토리 생성 (#31) * feat: VoteResponse 리포지토리 생성 (#31) * feat: VoteResult 리포지토리 생성 (#31) * fix(auth): TokenRepository의 PK 타입 Long → String으로 수정 (#31) * feat: Vote 연관관계 설정을 위한 Group 엔티티, 리포지토리 생성 (#31) * fix(user): User 엔티티에서 'user' 백틱(`) 처리 (#31) * [Feat] 투표 등록 API 개발 (#42) * feat: 투표 등록 RequestDto, ResponseDto 생성 (#32) * feat: 투표 등록 API 컨트롤러 구현 및 서비스 골격 구현 (#32) * refactor: DTO 클래스명에서 'Dto' 접미사 제거 (#32) * feat: 투표 등록 서비스 구현 (#32) * feat: 사용자 투표 생성 팩토리 메서드 도입 (#32) * feat: 투표 등록 서비스에 유저 유효성 검사 추가 (`AuthUserValidator`) (#32) * feat: 투표 등록 시 그룹 멤버십 확인 기능 추가 (#32) * chore: 초기 시스템 유저 및 공개 그룹 데이터 삽입용 SQL 스크립트 추가 (#32) * feat: 초기 데이터(시스템 유저 및 공개 그룹) 존재 여부 검증 로직 추가 (#32) * feat: 공개 그룹인 경우 투표 등록 시 멤버 확인 생략 로직 추가 (#32) * feat: 투표 등록 커스텀 예외 처리 적용 (#32) * refactor: 도메인 공통 에러코드 인터페이스(BaseErrorCode) 도입 (#32) * [Feat] 투표 내용 조회 API 개발 (#43) * feat(global): 전역 예외 코드(FORBIDDEN, UNEXPECTED_ERROR) 및 GlobalException 정의 (#33) * feat: 투표 내용 조회 커스텀 예외 코드 추가 (#33) * feat: 투표 내용 조회 컨트롤러, 서비스, DTO 구현 (200 확인) (#33) * feat: 투표 참여 여부 검증 로직 추가 (#33) * [Feat] 투표 참여 API 개발 (#45) * feat: 투표 참여 API 컨트롤러 및 DTO 작성 (#34) * feat: 투표 참여 커스텀 예외 추가 (#34) - INVALID_OPTION, ALREADY_VOTED * feat: 정적 팩토리 메서드 (`create`) 추가 (#34) * feat: 투표 참여 서비스 로직 구현 (#34) * feat: 투표 상태(OPEN) 체크 로직 추가 (#34) * [Feat] 투표 결과 조회 API 개발 (#46) * feat: 투표 결과 응답 DTO 작성 (#35) * feat: 투표 결과 조회 컨트롤러 및 서비스 틀 작성 (#35) * feat: 그룹 조회 권한 검사 함수를 투표 상세 조회 권한 검사 함수로 변경 (공개그룹 권한 제거) (#35) * feat: 투표 결과 조회 서비스 로직 구현 (#35) * feat: 투표 상태 검사 추가 (#35) * fix: totalCount에서 기권 응답 제외, results에 모든 항목 포함 (#35) * feat: 기권으로 응답한 참여자는 조회 권한에서 제외 (#35) * [Feat] Dev 환경에 Jwt 인증 및 예외 처리 필터 적용 (#48) * feat: Jwt 인증 필터 및 커스텀 엔트리 포인트 추가 (#47) * feat: 디버그 모드 추가 (#47) * [CICD] Dev 서버용 배포 파이프라인 생성 (#49) Co-authored-by: Yuna <yuna@Yunaui-MacBookPro.local> * [Feat] 진행 중인 투표 목록 조회 API 개발 (#50) * feat: 진행 중인 카드 목록 조회 API 응답 DTO 생성 (#36) * refactor: 투표 응답 DTO를 기능별로 list/와 result/ 하위 패키지로 분리 (#36) * feat: 커스텀 에러 코드 추가 (#36) * feat: 진행 중 투표 목록용 커서 파서 추가(#36) * feat: QueryDSL 환경 설정 및 Q 클래스 생성 설정 추가 (#36) - querydsl-core, querydsl-jpa(jakarta) 의존성 추가 - annotationProcessor 설정을 통한 Q 클래스 자동 생성 설정 - generated/querydsl 디렉토리 설정 및 sourceSets 등록 - JPAQueryFactory 빈 등록을 위한 QuerydslConfig 생성 - QueryDSL 관련 캐시 및 빌드 이슈 해결 * refactor: config 패키지 구조를 기능별로 분리 (security, querydsl, jpa) (#36) * feat: 진행 중인 투표 목록 조회용 QueryDSL 리포지토리 구현 (#36) - 사용자가 접근 가능한 그룹(공개 그룹 + 참여 그룹)의 진행 중인 투표만 조회 - 커서 기반 페이지네이션 조건 (closedAt, createdAt) - 사용자 참여 여부 필터링 (응답하지 않은 투표만) * chore: Hibernate SQL 디버깅을 위한 trace 로그 레벨 설정 (#36) - org.hibernate.type.descriptor.sql 로그 레벨을 trace로 설정하여 바인딩 값 확인 가능 * feat: 진행 중인 투표 목록 조회 서비스 로직 구현 (#36) - getActiveVotes(): 비로그인/로그인 분기 처리 및 커서 기반 페이지네이션 지원 - getAccessibleGroups(): 공개 그룹 + 사용자 소속 그룹 권한 기반 접근 목록 반환 - VoteListResponse 구성 및 hasNext, nextCursor 처리 포함 * feat: 진행 중인 투표 목록 조회 API 컨트롤러 구현 및 비로그인 접근 허용 설정 (#36) * feat: 미래 시간 커서 사용 시 성공 응답 처리 및 INVALID_CURSOR 예외 삭제(#36) * [Feat] 내가 만든 투표 목록 조회 API 개발 (#57) * feat: 내가 만든 투표 목록용 커서 파서 추가 (#37) * refactor: 투표 리스트 응답 DTO를 기능별 패키지로 분리 (active, mine, participated) (#37) * feat: 내가 만든 투표 목록 조회 API 응답 DTO 생성 (#37) * feat: 내가 만든 투표 목록 조회용 QueryDSL 리포지토리 구현 (#37) * refactor: 공개 그룹 조회 로직 GroupService로 분리 (#37) * feat: VoteOptionResultWithId DTO 추가 (voteId 포함) (#37) * feat: 내가 만든 투표 목록 조회 서비스 로직 구현 (#37) - getMyVotes 서비스 구현 - VoteResultService.getResultsWithVoteId() 메서드 추가 및 사용 - 투표에 대해 결과 집계 포함한 응답 구성 * feat: 내가 만든 투표 목록 조회 API 컨트롤러 구현 (#37) * refactor: VoteResultService를 사용해 getVoteResult 결과 집계 로직 분리 (#37) * feat: 커서에 포함된 voteId 유효성 검증 추가 (#37) - MyVote 목록 조회 시 전달된 커서의 voteId가 실제로 존재하는지 확인 - 존재하지 않으면 404(VOTE_NOT_FOUND) 예외 발생시킴 - 불필요한 쿼리 실행 방지 및 에러 원인 명확화 * [Feat] 내가 참여한 투표 목록 조회 API 개발 (#58) * feat: 내가 참여한 투표 목록용 커서 파서 추가 (#38) * feat: 내가 참여한 투표 목록 조회 API 응답 DTO 생성 (#38) * feat: 내가 참여한 투표 목록 조회용 QueryDSL 리포지토리 구현 (#38) * feat: 내가 참여한 투표 목록 조회 서비스 로직 구현 (#38) * feat: 내가 참여한 투표 목록 조회 API 컨트롤러 구현 (#38) * fix: 참여한 투표 목록 조회 시 nextCursor 생성 오류 수정 (#38) - nextCursor 생성 시 잘못된 필드(createdAt)를 사용하던 문제 수정 - closedAt 기준 커서 정렬 원칙에 맞게 closedAt으로 nextCursor 생성하도록 수정 * [Feat] 가입한 그룹 라벨 조회 API 개발 (#59) * feat: 가입한 그룹 이름/목록 조회용 커서 파서 추가 (#56) * feat: 가입한 그룹 이름 조회 API 응답 DTO 구현 (#56) * feat: 가입한 그룹 이름 조회용 QueryDSL 리포지토리 구현 (#56) * feat: 가입한 그룹 이름 조회 서비스 로직 구현 (#56) * feat: 가입한 그룹 이름 조회 API 컨트롤러 구현 (#56) * [Feat] 가입한 그룹 목록 조회 API 개발 (#60) * feat: 가입한 그룹 목록 조회 API 응답 DTO 구현 (#55) * feat: 가입한 그룹 목록 조회용 QueryDSL 리포지토리 구현 (#55) * feat: 가입한 그룹 목록 조회 서비스 구현 (#55) * feat: 가입한 그룹 목록 조회 API 컨트롤러 구현 (#55) * [Feat] 그룹 가입 API 개발 (#61) * feat: 그룹 가입 커스텀 예외 추가 (#51) * feat: 초대 코드 유효성 검사 메서드 추가 (#51) * feat: 그룹 가입 요청 및 응답 DTO 구현 (#51) * feat: 그룹 가입 리포지토리 구현 (#51) * feat: 그룹 가입 서비스 구현 (#51) * feat: 그룹 가입 컨트롤러 구현 (#51) * feat: 공개 그룹 가입 불가 로직 추가 (#51) * fix: soft-deleted 멤버 조회 로직 개선 및 투표 권한 검증 수정 (#51) - findByGroupAndUserIncludingDeleted 메서드를 native query로 수정하여 @where(clause = "deleted_at IS NULL") 무시 - voteService 내부 그룹 권한 검증 로직에서 soft delete 멤버도 조회할 수 있도록 수정 * feat: 그룹 탈퇴 이력이 있는 유저는 기존 데이터 복구 방식으로 재가입 처리 (#51) - 소프트 딜리트된 GroupMember가 존재하면 복구하여 재가입 처리 - 중복 삽입 방지를 위해 기존 가입 여부 먼저 확인 * docs: Group 조회 시 @where에 대한 주석 추가 (#51) * [Feat] 새 그룹 생성 API 개발 (#62) * feat: 새그룹 생성 요청 및 응답 DTO 구현 (#52) * feat: 그룹 생성 입력값 유효성 검증 로직 및 커스텀 예외 추가 (#52) * fix: 그룹/투표 이미지 URL에 도메인 prefix 검증 로직 추가 (#52) - VoteValidator.validateUrl() 로직을 도메인 기반으로 변경 - application.yml에 file.upload-url-prefix 추가 * feat: 새그룹 생성 서비스 로직 구현 (#52) * feat: 초대 코드 생성 로직 추가 (#52) * feat: 새그룹 생성 컨트롤러 구현 (#52) * fix: 투표/그룹 이미지 URL prefix를 application 설정 대신 하드코딩으로 변경 (#52) * feat: 그룹 생성 시 이름 중복 방지 로직 추가 (#52) * [Feat] 회원정보 조회/수정 API 개발 (#63) * feat: 회원정보 조회 응답 DTO 구현 (#53) * feat: 회원정보 조회 서비스 구현 (#53) * feat: 회원정보 조회 컨트롤러 구현 (#53) * feat: 회원정보 수정 요청 및 응답 DTO 구현 (#54) * feat: 닉네임 유효성 검사 로직 구현 (#54) * feat: 회원정보 수정 서비스 구현 (#54) * fix: 닉네임이 기존과 동일한 경우 중복 검사 없이 바로 반환 (#54) * feat: 회원정보 수정 컨트롤러 구현 (#54) * [Feat] 회원 탈퇴 API 개발 (#64) * feat: 회원 탈퇴 서비스 로직 구현 및 관련 삭제 메서드 추가 (#29) * feat: 회원 탈퇴 컨트롤러 구현 (#29) * feat: 카카오 연동 해제 로직 추가 (#29) - 카카오 연동 해제 로직 추가 (OAuth 전략 패턴 내 구현) - RestTemplate Bean 전역 설정 (config 패키지 이동) - OAuth 연동 ID 기반 unlink 요청 및 응답 로깅 처리 - 관련 커스텀 예외 코드 추가 - 관련 리포지토리 코드 추가 * feat: 회원 탈퇴 시 그룹 소유자 승계 로직 추가 (#29) * fix: 회원 탈퇴 시 처리 순서 조정 및 유저 상태 변경 시점 수정 (#29) - 그룹 소유자 승계 후 그룹 멤버 삭제로 순서 변경 (유효한 멤버 기반 승계 보장) - 카카오 연동 해제, 토큰/OAuth 삭제 이후에 회원 상태 변경 수행 - user.withdraw()를 가장 마지막에 호출하여 도메인 정합성 유지 * fix: 회원 탈퇴 시 그룹 멤버 삭제 방식을 soft delete에서 hard delete로 수정 (#29) * [CICD] 환경변수 추가 주입 과정 추가 * [Feat] 랜덤 닉네임 생성 기능 구현 (#65) * [Chore] Dev CORS에 localhost 추가 * [Fix] 투표 결과 비율 계산에 double 타입 적용 * [Feat] 카카오 로그인 시 동적 redirect URI 허용 및 검증 추가 (#67) * [Refactor] OAuth ID 타입 Long → String으로 변경 * [Feat] 투표 등록 시 익명 기능 추가 (#70) * feat: 투표 등록 시 익명 정보 저장 (#69) * feat: 투표 조회 시 익명 투표일 경우 닉네임 대신 '익명' 반환 (#69) * [Feat] AI 기반 투표 내용 검열 기능 추가 (#71) * feat: 투표 등록 시 AI 서버로 검열 요청하는 로직 추가 (#68) * feat: feat: AI 검열 결과 수신 및 상태 반영 서비스/컨트롤러 구현 (#68) * [Fix] USER_NOT_FOUND 에러 상태 코드 변경 (404 → 401) * [Fix] 진행 중인 투표 조회 시 PENDING/REJECTED 필터링 추가 * [Chore] prod 환경의 JPA ddl-auto 옵션을 none → update로 변경 * fix: 익명 투표일 경우 adminVote 강제 비표시 처리, 투표 내용 조회 시 adminVote 응답 * fix: 투표 참여 목록에서 기권한 항목 제외 처리 --------- Co-authored-by: yunabyte <yunabyte@gmail.com> Co-authored-by: Yuna <yuna@Yunaui-MacBookPro.local>
1 parent 5693891 commit e1004e3

File tree

4 files changed

+6
-3
lines changed

4 files changed

+6
-3
lines changed

src/main/java/com/moa/moa_server/domain/vote/dto/response/VoteDetailResponse.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ public record VoteDetailResponse(
99
String content,
1010
String imageUrl,
1111
LocalDateTime createdAt,
12-
LocalDateTime closedAt
12+
LocalDateTime closedAt,
13+
int adminVote
1314
) {}

src/main/java/com/moa/moa_server/domain/vote/dto/response/active/ActiveVoteItem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static ActiveVoteItem from(Vote vote) {
2525
vote.getImageUrl(),
2626
vote.getCreatedAt(),
2727
vote.getClosedAt(),
28-
vote.isAdminVote() ? 1 : 0,
28+
vote.isAnonymous() ? 0 : (vote.isAdminVote() ? 1 : 0),
2929
vote.getVoteType().name()
3030
);
3131
}

src/main/java/com/moa/moa_server/domain/vote/repository/impl/VoteRepositoryImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public List<Vote> findSubmittedVotes(User user, List<Group> groups, @Nullable Cl
9797

9898
BooleanBuilder builder = new BooleanBuilder()
9999
.and(voteResponse.user.eq(user))
100+
.and(voteResponse.optionNumber.ne(0)) // 기권 제외
100101
.and(vote.group.in(groups));
101102

102103
if (cursor != null) {

src/main/java/com/moa/moa_server/domain/vote/service/VoteService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ public VoteDetailResponse getVoteDetail(Long userId, Long voteId) {
170170
vote.getContent(),
171171
vote.getImageUrl(),
172172
vote.getCreatedAt(),
173-
vote.getClosedAt()
173+
vote.getClosedAt(),
174+
vote.isAnonymous() ? 0 : (vote.isAdminVote() ? 1 : 0)
174175
);
175176
}
176177

0 commit comments

Comments
 (0)