[BE-12] 방목록 미리보기 확장 + 채팅 인증 JWT 통일
작업 내용 (설계 의도)
변경 사항
근거 TDD: 20260704-채팅시스템고도화-tdd.md (인증 계약·REST API 계약·응답 DTO 필드 스키마·방목록 미리보기 N+1 회피). FE 설계 역제안 1·4·5 반영.
방목록 미리보기 필드를 추가하고, 기존 /rooms REST 컨트롤러의 X-User-Id 임시 인증을 Bearer JWT로 전환한다. SecurityConfig 승격과 컨트롤러 전환을 한 티켓에서 원자적으로 수행해 과도기(경로는 authenticated인데 컨트롤러는 헤더 기대) 노출을 방지한다.
방목록 미리보기 (FR-9)
domain/message/vo/RoomListView.kt(신규 projection VO): roomId/type/name/contextType/lastMessageContent/lastMessageAt. QueryDSL@QueryProjection.domain/message/repository/RoomCustomRepository.kt+RoomCustomRepositoryImpl.kt:findMyRoomViews(userId, keyword): List<RoomListView>추가 — rooms + 마지막 메시지 1건을 단일 쿼리 조인(상관 서브쿼리MAX(m.id)또는 last_message_at 기준). 방마다 메시지 재조회하는 N+1 금지.presentation/message/dto/response/RoomResponse.kt(변경):contextType(nullable),lastMessagePreview(nullable,lastMessageContent를 최대 50자로 잘라 생성),lastMessageAt(nullable) 필드 추가.of(RoomListView)오버로드 추가(기존of(Room)유지).application/message/usecase/ListMyRoomsUseCase.kt(변경):findMyRoomViews사용하도록 전환.
인증 JWT 통일 (FR 공통, NFR)
SecurityConfig.kt(변경):/rooms/**permitAll →authenticated()승격./products/**는 기존 유지(goods 채팅 BE-11은 자체 경로). — wave3에서 본 티켓만 SecurityConfig 수정(BE-04는 wave2·/ws·/communities; BE-08은 SecurityConfig 미수정).presentation/message/controller/RoomApiController.kt+MessageApiController.kt(변경):@RequestHeader("X-User-Id")→@AuthenticationPrincipal principal: UserPrincipal(principal.id)로 전환.TODO(AUTH-03/04)주석 제거.- 롤백: SecurityConfig·컨트롤러 전환은 동시 배포라 원자적. 미리보기 필드는 additive(구 클라이언트는 새 필드 무시). 문제 시 직전 태그로 compose 롤백.
의존
- BE-03a (Room.contextType — RoomResponse.contextType, RoomCustomRepository findByContext와 같은 파일이므로 이후)
- BE-04 (SecurityConfig 선행 수정자 — wave2 이후 wave3에서 순차 수정)
다이어그램
처리 흐름
sequenceDiagram participant C as Client participant Ctl as RoomApiController participant UC as ListMyRoomsUseCase participant R as RoomCustomRepository C->>Ctl: GET /rooms/me (Bearer JWT) Ctl->>Ctl: @AuthenticationPrincipal → userId Ctl->>UC: execute(userId, keyword) UC->>R: findMyRoomViews(userId, keyword) 단일 조인 R-->>Ctl: List<RoomListView> Ctl-->>C: List<RoomResponse> (preview/lastMessageAt/contextType)
테스트 케이스
GET /rooms/me는 각 방의 lastMessagePreview(최대 50자)·lastMessageAt·contextType을 포함해 반환한다.- 메시지가 없는 방은 lastMessagePreview·lastMessageAt이 null이다.
- 기존 DIRECT/GROUP 방은 contextType이 null로 반환된다.
- 방목록 조회가 방 개수와 무관하게 단일 쿼리로 수행된다 (N+1 없음 — 쿼리 카운트 검증).
- Bearer JWT 없이
/rooms/me호출 시 401이 반환된다 (authenticated 승격). - 유효 JWT의 principal.id로 내 방만 조회된다 (X-User-Id 미사용).
POST /rooms·GET /rooms/{id}·DELETE /rooms/{id}도 principal.id 기반으로 정상 동작한다.