Conversation
- ChatRoomMemberResponse: 개별 멤버 정보 (userId, name, imageUrl, isOwner, joinedAt) - ChatRoomMembersResponse: 멤버 목록 래퍼 클라이언트가 채팅방 참여자 정보를 확인할 수 있도록 응답 객체 정의
- findActiveMembersByChatRoomId: 채팅방 ID로 활성 멤버 조회 - JOIN FETCH로 User 정보를 한 번에 로딩 (N+1 방지) - leftAt IS NULL 조건으로 나간 멤버 필터링
- getChatRoomMembers: 멤버 목록 조회 비즈니스 로직 - validateMembership: existsByChatRoomIdAndUserId로 권한 검증 - toMemberResponse: Entity → DTO 변환 (createdAt을 joinedAt으로 매핑) 비멤버 접근 시 FORBIDDEN_CHAT_ROOM_ACCESS 예외 발생
- GET /chats/rooms/{chatRoomId}/members 엔드포인트 추가
- ChatApi 인터페이스: Swagger 문서화 (설명, 에러 코드)
- ChatController 구현체: @userid로 사용자 ID 주입
채팅방 접속 시 해당 방의 멤버 목록을 조회할 수 있는 API 제공
- 멤버 조회 성공 케이스 검증 - 비멤버 접근 시 FORBIDDEN 예외 발생 검증 - 나간 멤버는 조회되지 않음 검증 Mockito를 사용하여 Repository 의존성 모킹
- Service: WHAT 설명 주석 제거 (메서드명이 충분히 표현) - Service: 코드 변경 이력 주석 제거 - Test: 사용되지 않는 any import 제거 코드 리뷰 피드백 반영하여 가독성 개선
- getChatRoomMembers: 탈퇴한 유저(deletedAt != null) 제외 - Stream filter로 deletedAt == null인 멤버만 변환 탈퇴한 사용자는 채팅방 멤버 목록에 노출되지 않음
- getChatRoomMembers: 현재 사용자 정보를 UserRepository에서 조회 - validateMembership: 어드민이 시스템 어드민 방 조회 시 권한 검증 스킵 - NOT_FOUND_USER import 추가 - 테스트: UserRepository mock 설정 추가 어드민은 시스템 어드민 방의 멤버 목록을 조회할 수 있음
- getChatRoomMembers: 채팅방 존재 여부를 멤버십 검증 전에 확인 - 존재하지 않는 채팅방: NOT_FOUND_CHAT_ROOM (404) - 비멤버 접근: FORBIDDEN_CHAT_ROOM_ACCESS (403) - validateMembership 파라미터를 ChatRoom으로 변경 - 테스트: ChatRoomRepository mock 설정 추가 잘못된 순서로 인해 존재하지 않는 방도 403이 뜨던 문제 해결
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 52 minutes and 12 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthrough채팅방의 활성 멤버 목록을 조회하는 새로운 기능이 추가되었습니다. API 인터페이스, 컨트롤러 구현, 데이터 전송 객체(DTO), 저장소 쿼리, 비즈니스 로직 서비스 및 단위 테스트가 포함되었습니다. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
🧪 JaCoCo Coverage Report (Changed Files)Summary
Coverage by File
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@src/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.java`:
- Around line 70-71: Replace the membership check in ChatRoomMembershipService
that uses chatRoomMemberRepository.existsByChatRoomIdAndUserId(...) with a new
repository method that only counts active members (e.g.
existsActiveByChatRoomIdAndUserId or a query including "AND crm.leftAt IS NULL")
so users who previously left are not treated as members; update the conditional
that currently throws CustomException.of(FORBIDDEN_CHAT_ROOM_ACCESS) to use this
active-membership check, and add a test case asserting a 403 response when a
user with crm.leftAt != null calls GET /chats/rooms/{chatRoomId}/members to
ensure the rejected-members scenario is covered.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: df78a80b-59e0-4b5d-b0a3-e65ae172d8e2
📒 Files selected for processing (7)
src/main/java/gg/agit/konect/domain/chat/controller/ChatApi.javasrc/main/java/gg/agit/konect/domain/chat/controller/ChatController.javasrc/main/java/gg/agit/konect/domain/chat/dto/ChatRoomMemberResponse.javasrc/main/java/gg/agit/konect/domain/chat/dto/ChatRoomMembersResponse.javasrc/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.javasrc/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.javasrc/test/java/gg/agit/konect/unit/domain/chat/service/ChatRoomMembershipServiceTest.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: coverage
- GitHub Check: Analyze (java-kotlin)
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java
⚙️ CodeRabbit configuration file
src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.
- 코멘트는 반드시 한국어로 작성한다.
- 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
- 각 코멘트 첫 줄에 심각도를
[LEVEL: high|medium|low]형식으로 반드시 표기한다.- 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
- 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
- 가능하면 재현 조건 및 실패 시나리오도 포함한다.
- 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
- 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
- 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
- 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
- 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.
Files:
src/main/java/gg/agit/konect/domain/chat/dto/ChatRoomMembersResponse.javasrc/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.javasrc/main/java/gg/agit/konect/domain/chat/controller/ChatController.javasrc/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.javasrc/main/java/gg/agit/konect/domain/chat/dto/ChatRoomMemberResponse.javasrc/main/java/gg/agit/konect/domain/chat/controller/ChatApi.java
**/*
⚙️ CodeRabbit configuration file
**/*: 공통 리뷰 톤 가이드:
- 모든 코멘트는 첫 줄에
[LEVEL: ...]태그를 포함한다.- 과장된 표현 없이 사실 기반으로 작성한다.
- 한 코멘트에는 하나의 이슈만 다룬다.
- 코드 예시가 필요하면 최소 수정 예시를 제시한다.
- 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.
Files:
src/main/java/gg/agit/konect/domain/chat/dto/ChatRoomMembersResponse.javasrc/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.javasrc/main/java/gg/agit/konect/domain/chat/controller/ChatController.javasrc/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.javasrc/test/java/gg/agit/konect/unit/domain/chat/service/ChatRoomMembershipServiceTest.javasrc/main/java/gg/agit/konect/domain/chat/dto/ChatRoomMemberResponse.javasrc/main/java/gg/agit/konect/domain/chat/controller/ChatApi.java
🧠 Learnings (1)
📚 Learning: 2026-04-13T00:26:23.225Z
Learnt from: dh2906
Repo: BCSDLab/KONECT_BACK_END PR: 533
File: src/main/java/gg/agit/konect/domain/chat/service/ChatService.java:1511-1516
Timestamp: 2026-04-13T00:26:23.225Z
Learning: In ChatService.java (Spring Boot + JPA, MySQL InnoDB), within a `Transactional(readOnly = true)` method, retrying a repository count query (e.g., `countNewerMessagesByChatRoomId`) to handle concurrent inserts is ineffective under REPEATABLE READ isolation: the same DB snapshot is used throughout the transaction, so the retry always returns the same result. A new transaction (`Propagation.REQUIRES_NEW`) would be required for a true retry, but accepting a 1-page offset as a UX tradeoff is preferred for search navigation in this codebase.
Applied to files:
src/main/java/gg/agit/konect/domain/chat/repository/ChatRoomMemberRepository.javasrc/main/java/gg/agit/konect/domain/chat/service/ChatRoomMembershipService.java
- existsActiveByChatRoomIdAndUserId 메서드 추가 (leftAt IS NULL 조건) - validateMembership에서 활성 멤버만 조회 가능하도록 변경 - 나간 멤버 접근 시 FORBIDDEN 예외 발생 테스트 추가 나간 멤버가 여전히 멤버로 인식되는 문제 해결
* feat: 채팅방 멤버 목록 조회 API 추가 (#549) * feat: 채팅방 멤버 조회 응답 DTO 추가 - ChatRoomMemberResponse: 개별 멤버 정보 (userId, name, imageUrl, isOwner, joinedAt) - ChatRoomMembersResponse: 멤버 목록 래퍼 클라이언트가 채팅방 참여자 정보를 확인할 수 있도록 응답 객체 정의 * feat: 활성 멤버 조회 Repository 메서드 추가 - findActiveMembersByChatRoomId: 채팅방 ID로 활성 멤버 조회 - JOIN FETCH로 User 정보를 한 번에 로딩 (N+1 방지) - leftAt IS NULL 조건으로 나간 멤버 필터링 * feat: 채팅방 멤버 조회 Service 로직 구현 - getChatRoomMembers: 멤버 목록 조회 비즈니스 로직 - validateMembership: existsByChatRoomIdAndUserId로 권한 검증 - toMemberResponse: Entity → DTO 변환 (createdAt을 joinedAt으로 매핑) 비멤버 접근 시 FORBIDDEN_CHAT_ROOM_ACCESS 예외 발생 * feat: 채팅방 멤버 조회 API 엔드포인트 추가 - GET /chats/rooms/{chatRoomId}/members 엔드포인트 추가 - ChatApi 인터페이스: Swagger 문서화 (설명, 에러 코드) - ChatController 구현체: @userid로 사용자 ID 주입 채팅방 접속 시 해당 방의 멤버 목록을 조회할 수 있는 API 제공 * test: 채팅방 멤버 조회 Service 단위 테스트 추가 - 멤버 조회 성공 케이스 검증 - 비멤버 접근 시 FORBIDDEN 예외 발생 검증 - 나간 멤버는 조회되지 않음 검증 Mockito를 사용하여 Repository 의존성 모킹 * refactor: 불필요한 주석과 import 제거 - Service: WHAT 설명 주석 제거 (메서드명이 충분히 표현) - Service: 코드 변경 이력 주석 제거 - Test: 사용되지 않는 any import 제거 코드 리뷰 피드백 반영하여 가독성 개선 * feat: 탈퇴한 유저 필터링 추가 - getChatRoomMembers: 탈퇴한 유저(deletedAt != null) 제외 - Stream filter로 deletedAt == null인 멤버만 변환 탈퇴한 사용자는 채팅방 멤버 목록에 노출되지 않음 * feat: 어드민 시스템 어드민 방 멤버 조회 권한 추가 - getChatRoomMembers: 현재 사용자 정보를 UserRepository에서 조회 - validateMembership: 어드민이 시스템 어드민 방 조회 시 권한 검증 스킵 - NOT_FOUND_USER import 추가 - 테스트: UserRepository mock 설정 추가 어드민은 시스템 어드민 방의 멤버 목록을 조회할 수 있음 * fix: 존재하지 않는 채팅방 조회 시 404 반환 - getChatRoomMembers: 채팅방 존재 여부를 멤버십 검증 전에 확인 - 존재하지 않는 채팅방: NOT_FOUND_CHAT_ROOM (404) - 비멤버 접근: FORBIDDEN_CHAT_ROOM_ACCESS (403) - validateMembership 파라미터를 ChatRoom으로 변경 - 테스트: ChatRoomRepository mock 설정 추가 잘못된 순서로 인해 존재하지 않는 방도 403이 뜨던 문제 해결 * chore: 코드 포맷팅 * fix: 나간 멤버 권한 검증 로직 수정 - existsActiveByChatRoomIdAndUserId 메서드 추가 (leftAt IS NULL 조건) - validateMembership에서 활성 멤버만 조회 가능하도록 변경 - 나간 멤버 접근 시 FORBIDDEN 예외 발생 테스트 추가 나간 멤버가 여전히 멤버로 인식되는 문제 해결 * test: ChatRoomMembershipService 테스트 커버리지 보강 (#551) * test: ChatRoomMembershipService 테스트 커버리지 보강 - 멤버십 서비스의 public 메서드별 정상·예외 분기를 테스트로 고정해 회귀를 막는다 - 중복 생성과 접근 권한 같은 비정상 흐름도 함께 검증해 실제 서비스 로직의 의도를 드러낸다 - lastReadAt 갱신 기준과 system-admin 예외 경로를 명시적으로 확인해 경계 조건 누락을 방지한다 * chore: 코드 포맷팅 * chore: 코드 포맷팅 * test: 리뷰 코멘트의 primitive 타입 제안을 반영 - null 가능성이 없는 테스트 지역 변수는 primitive 타입으로 정리해 불필요한 boxing 경고를 없앤다 - roomId 선언을 int로 통일해 정적 분석 코멘트를 반영하면서 기존 테스트 동작은 그대로 유지한다 - 대상 테스트를 다시 실행해 리뷰 반영 이후에도 병합된 테스트 파일이 정상 동작함을 확인한다 * chore: 롤링 로그 gzip 압축 적용 (#552) - Logback 롤링 설정이 새로 생성되는 일별 로그를 즉시 gzip으로 압축하도록 조정 - 운영 중 특정 날짜 로그를 파일 단위로 확인하기 쉬운 구조는 유지하면서 디스크 사용량을 줄이도록 선택 - 별도 배치 압축 작업 없이도 backend 로그와 scheduler 로그가 동일한 방식으로 보관되도록 맞춤 * fix: ClaudeClient 시스템 프롬프트 study_time 테이블 힌트 구체화 * fix: ClaudeClient 시스템 프롬프트 study_time 테이블 힌트 구체화 * fix: show tables 선행 조회 원칙 추가 및 줄 길이 120자 제한 준수 * fix: show tables 선행 조회 원칙 추가 및 줄 길이 120자 제한 준수 * fix: JaCoCo 제외 목록에 claude, mcp 인프라 클라이언트 추가 * fix: JaCoCo 제외 목록에 claude, mcp 인프라 클라이언트 추가 * fix: 메시지 검색 결과에 unreadCount, isMuted 필드 추가 (#555) roomMatches와 동일하게 messageMatches 응답에도 읽지 않은 메시지 수와 알림 뮤트 여부를 포함하도록 수정 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: 완료된 SSE emitter 전송 예외를 정리하도록 처리 (#556) * fix: 완료된 SSE emitter 전송 예외를 정리하도록 처리 - 이미 complete된 emitter에 send를 시도하면 IllegalStateException이 발생할 수 있어 알림 전송 자체보다 끊어진 연결 정리를 우선하도록 변경 - IOException만 completeWithError로 마무리하고 IllegalStateException은 emitter 제거로만 끝내 이미 종료된 emitter를 다시 종료하면서 예외가 전파되는 상황을 막음 - 완료된 emitter가 맵에 남아 있어도 예외 없이 정리되는 단위 테스트를 추가해 재연 경로를 고정하고 회귀를 방지 * fix: SSE emitter 종료 경합 예외를 추가로 흡수 - send 실패 후 completeWithError 호출도 이미 종료된 emitter와 경합할 수 있어 정리 단계의 예외가 다시 상위로 전파되지 않도록 별도 보호 구문을 추가 - 알림 전송 실패 처리의 목적은 끊어진 emitter를 제거하는 것이므로 종료 경쟁에서 생기는 IllegalStateException은 로그만 남기고 삼키도록 선택 - 기존 단위 테스트를 다시 실행해 알림 inbox SSE 경로가 회귀 없이 유지되는지 확인 * test: 완료된 SSE emitter 테스트를 결정적으로 고정 - subscribe 경로의 completion callback 타이밍에 따라 테스트가 false positive가 될 수 있어 완료된 emitter를 직접 주입하는 방식으로 재현 조건을 고정 - 이번 테스트의 목적은 IllegalStateException 정리 분기를 안정적으로 검증하는 것이므로 구독 로직 부수효과보다 완료된 emitter 상태 자체를 최소 셋업으로 구성 - 수정 후 NotificationInboxSseService 단위 테스트를 다시 실행해 회귀 없이 통과함을 확인 * chore: 모니터링 스택 제거 (#557) * chore: OpenTelemetry Java agent 배선을 제거해 배포 이미지를 단순화 - Docker 이미지와 stage/prod 배포 워크플로우에서 OTel Java agent 의존성을 함께 제거해 런타임 추적 구성을 저장소 밖으로 정리한다. - CI 빌드가 더 이상 agent 캐시, checksum, 런타임 전용 환경변수 해제 흐름에 기대지 않도록 바꿔 이미지 빌드 경로를 단순하게 유지한다. * chore: Prometheus 노출 설정을 제거해 백엔드 모니터링 의존성을 정리 - Prometheus registry 의존성과 별도 monitoring 설정 파일을 제거해 애플리케이션이 더 이상 메트릭 수집 구성을 내장하지 않도록 정리한다. - Docker healthcheck가 여전히 /actuator/health 를 사용하므로 actuator 는 유지하고, 배포 안정성에 직접 영향이 큰 health 경로만 남긴다. * chore: 저장소에서 monitoring 스택 배포 자산을 제거 - Prometheus, Grafana, Loki, Promtail 배포 워크플로우와 compose 자산을 함께 제거해 저장소가 더 이상 별도 모니터링 스택을 관리하지 않도록 정리한다. - monitoring 전용 env 예외와 타깃 갱신 스크립트까지 함께 삭제해 남은 운영 진입점을 줄이고 제거 범위를 한 커밋 안에 묶는다. * [codex] 로그 추적 상관관계를 정리하고 OTel 흔적을 제거 (#558) * chore: 로그 추적 상관관계를 정리하고 OTel 흔적을 제거 - 요청 단위 추적이 로그와 비동기 작업 경계에서 끊기지 않도록 requestId 응답 헤더와 MDC 전파를 추가했다 - Datadog과 기존 MDC 키를 함께 읽는 로그 패턴으로 맞춰 배포 환경 차이 때문에 trace 상관관계가 깨지는 상황을 줄였다 - Dockerfile, 예시 환경변수, 배포 워크플로우에서 OpenTelemetry agent 관련 설정을 제거해 현재 운영 기준과 맞지 않는 추적 흔적이 남지 않게 했다 - 관련 단위 테스트를 추가하고 실행해 로깅 상관관계와 설정 회귀를 방지했다 * fix: CORS에서 request id 응답 헤더를 노출 - 응답에 내려주는 X-Request-ID를 브라우저가 읽지 못하면 프론트와 서버 로그를 같은 요청으로 묶기 어려워진다 - WebConfig의 exposedHeaders에 X-Request-ID를 추가해 cross-origin 환경에서도 요청 상관관계 헤더를 읽을 수 있게 했다 - 설정 회귀를 막기 위해 CORS 등록값을 직접 검증하는 단위 테스트를 추가했다 * fix: request id 헤더를 검증 후 로그에 반영 - 클라이언트가 보낸 X-Request-ID를 그대로 신뢰하면 로그 포맷 손상과 추적 품질 저하가 생길 수 있다 - request id를 trim한 뒤 허용 문자와 길이를 검증하고 실패하면 새 값을 발급하도록 바꿔 응답 헤더, 로그, MDC가 같은 정제된 값을 쓰게 했다 - 유효한 값, 공백 포함 값, 잘못된 값을 각각 검증하는 단위 테스트를 추가해 입력 검증 회귀를 막았다 * fix: Datadog 로그 패턴을 canonical key로 정리 - 여러 MDC 키를 이어붙이면 trace와 span 값이 하나의 문자열처럼 보일 수 있어 로그 파싱과 추적 연결이 불안정해진다 - 운영 로그 패턴을 dd.trace_id와 dd.span_id 기준으로 단순화해 한 종류의 canonical key만 출력하도록 정리했다 - 설정 파일 문자열 포함 여부가 아니라 실제 패턴 렌더링 결과를 검증하는 테스트로 바꿔 로그 포맷 회귀를 막았다 * chore: 코드 포맷팅 * fix: 채팅방 마지막 메시지 메타데이터 동기화 (#559) * fix: 채팅방 마지막 메시지 메타데이터를 DB에 즉시 동기화 - chat_room.last_message_*가 null로 남아 채팅방 목록과 실제 메시지 상태가 어긋나는 문제를 막는다 - 메시지 저장 직후 chat_room 메타데이터를 명시적으로 업데이트해 영속성 컨텍스트 clear 경로에 의존하지 않도록 정리한다 - 회원가입 환영 메시지처럼 같은 패턴을 쓰는 경로도 함께 맞춰 신규 방의 초기 메타데이터 누락을 방지한다 - 기존 운영 데이터는 Flyway 백필 마이그레이션과 회귀 테스트로 함께 보강해 재발을 막는다 * chore: 코드 포맷팅 * refactor: 마지막 메시지 동기화 코드를 읽기 쉽게 정리 - sendMessage의 명시적 readOnly=false 표기를 기본 @transactional로 단순화해 클래스 레벨 설정과의 관계만 남긴다 - ChatRoomRepository updateLastMessage 시그니처 타입 표기를 정리해 읽는 부담을 줄인다 - UserService의 환영 메시지 경로도 syncLastMessage 헬퍼를 사용하도록 맞춰 채팅 메타데이터 갱신 책임을 일관되게 유지한다 * fix: 리뷰 지적 반영해 마지막 메시지 갱신 조건을 보강 - last_message 메타데이터 갱신 쿼리에서 clearAutomatically를 제거해 direct room 복구 흐름의 엔티티 변경이 detach로 유실되지 않게 한다 - 최신 메시지보다 오래된 트랜잭션이 chat_room 마지막 메시지 요약을 덮어쓰지 못하도록 messageId tie-breaker 조건을 추가한다 - direct room 재노출과 조건부 메타데이터 갱신을 테스트로 고정해 리뷰에서 지적된 회귀를 막는다 * fix: 마지막 메시지 동기화의 자기 자신 비교를 제외 - 마지막 메시지 갱신 조건에서 현재 저장한 메시지 자신은 비교 대상에서 제외해 DB timestamp 정밀도 차이로 인한 오판을 막는다 - direct 채팅방 목록과 재입장 시나리오가 chat_room.last_message_* 컬럼에 의존하므로 간헐적으로 이전 메시지가 남는 상태를 방지한다 - CI에서 흔들리던 채팅방 나가기/마지막 메시지 메타데이터 테스트와 jacoco 경로를 로컬에서 다시 검증했다 * chore: .gitignore 항목 추가 * docs: 채팅 도메인 가이드 추가 및 회귀 테스트 보강 (#562) * docs: 채팅 도메인 정책 가이드를 추가 - 채팅 도메인 작업 전에 AI가 먼저 읽어야 할 정책 중심 가이드를 chat 하위 AGENTS.md로 정리했다. - direct, group, club group, SYSTEM_ADMIN 문의방의 차이와 목록 요약, 읽음, 멤버십, 검색, 초대 정책을 한 문서에 모아 회귀 포인트를 드러냈다. - 마지막 메시지, unreadCount, visibleMessageFrom, 문의방 재사용처럼 수정 시 쉽게 놓치는 연쇄 영향을 명시해 안전한 변경 기준을 만들었다. * test: 채팅 정책 회귀 테스트를 보강 - 문의방 멤버 목록 조회, 문의방 admin 뮤트, 일반 group 검색 제외를 통합 테스트로 추가해 문서화한 정책을 직접 잠갔다. - 테스트 작성 과정에서 문의방 senderId 표현 정책이 문서처럼 단정적이지 않다는 점을 확인해 AGENTS 문구를 실제 동작 기준의 주의사항으로 낮췄다. - 문서와 테스트를 함께 조정해 채팅 도메인 가이드가 현재 구현과 어긋난 전제를 주입하지 않도록 정리했다. - 검증은 ChatApiTest 단위로 실행해 새 케이스와 기존 채팅 API 시나리오가 함께 통과하는지 확인했다. * docs: 문의방 senderId 문구 실제 동작 기준으로 조정 * test: ChatApiTest 타입 참조를 import로 정리 - parseChatRoomId와 extractRoomIds에서 fully-qualified 타입 참조를 제거해 테스트 가독성을 높였다. - MvcResult, JsonNode, ArrayList import를 추가하고 시그니처와 지역 변수 선언을 단순 타입으로 맞췄다. - 로직은 바꾸지 않고 표현만 정리해 리뷰 지적을 반영했다. * docs: 동아리 도메인 가이드 문서 작성 (#563) * docs(club): add club domain guide * test(club): add unit coverage for domain policies * chore: 코드 포맷팅 * test: 리뷰 코멘트 반영을 위해 club 권한 검증 근거를 보강 - 동아리 도메인 가이드에서 회원 제거 권한과 club_group 접근 검증 기준을 실제 구현 흐름에 맞춰 명확히 정리했다. - 어드민 비회원 사용자가 leader 권한 검증을 우회하는 정책은 서비스 테스트 목 대신 검증기 단위 테스트로 고정해 책임 경계를 분리했다. - removeMember 서비스 테스트에는 validateLeaderAccess 위임 검증을 추가해 서비스가 권한 판단을 자체 구현으로 우회하지 않도록 막았다. * chore: 코드 포맷팅 * fix: 운영 환경에서 Swagger를 비활성화 (#565) * fix: 운영 환경에서 Swagger를 비활성화 - 운영 서버에서 API 명세와 Swagger UI가 외부에 노출되지 않도록 prod 프로필에서 springdoc을 끈다 - Swagger 관련 Bean과 커스텀 initializer 컨트롤러도 prod에서는 생성되지 않게 막아 우회 노출 가능성을 줄인다 - stage/local 개발 편의성은 유지하고, 운영 환경에만 최소 범위로 적용한다 * chore: 코드 포맷팅 * fix: cache ai database schema context * fix: DB 스키마 캐시 생명주기 및 테이블 설명 정리 * fix: DB 스키마 캐시 실패 처리 및 도구 우선순위 정리 --------- Co-authored-by: 이동훈 <64298482+dh2906@users.noreply.github.com> Co-authored-by: 신관규 <soundbar91@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: 이동훈 <2dh2@naver.com>
🔍 개요
채팅방에 접속했을 때 해당 채팅방에 속한 유저의 목록을 조회할 수 있는 API를 추가합니다.
🚀 주요 변경 내용
DTO 추가:
ChatRoomMemberResponse,ChatRoomMembersResponseRepository:
findActiveMembersByChatRoomId메서드 추가leftAt IS NULL조건으로 나간 멤버 필터링Service:
getChatRoomMembers메서드 구현Controller:
GET /chats/rooms/{chatRoomId}/members엔드포인트 추가테스트:
ChatRoomMembershipServiceTest단위 테스트 추가💬 참고 사항
joinedAt은ChatRoomMember.createdAt을 사용✅ Checklist (완료 조건)