- MattermostClient에 게시글 조회(getRecentPosts), 채널 파일 수집(collectChannelFiles),
파일 다운로드/정보 조회(downloadFile, fileInfo)를 추가하고 사용자 이름을 캐시해서 반복
조회를 줄인다
- ChannelFeedService/Controller로 기관별 문정원/법률검토 채널의 게시글·자료 목록과
파일 다운로드 프록시(GET /api/orgs/{id}/posts|files, GET /api/files/{fileId})를 제공
- 채널 미생성/잘못된 channel 파라미터는 ChannelNotReadyException(409)으로 구분한다
- findChannelIdByDisplayName이 /users/me/teams/{id}/channels(토큰 사용자가 가입한
채널만) 대신 /teams/{id}/channels를 페이지네이션(page/per_page=200, 상한 100페이지)
하며 표시명을 찾도록 변경. 레거시 채널에 토큰 사용자가 가입하지 않은 경우 생기던
중복 채널 생성 위험을 제거한다(system-admin PAT 필요, README에 명시).
- 존재하지 않는 기관 id에 대한 404를 폭넓은 IllegalArgumentException 대신 전용
OrgNotFoundException으로 좁혀서 매핑.
- 검증 실패(@Valid) 응답을 원시 필드명이 담긴 JSON 대신 한글 라벨 메시지로 변환.
- SeedController 업로드 스트림 읽기 실패를 SeedParseException(400)으로 통일.
Co-Authored-By: Claude Opus 4.8 (1M context)
- GlobalExceptionHandler(@RestControllerAdvice) 추가: IllegalArgumentException은
404, SeedParseException은 400으로 매핑하고 예외 메시지를 ApiError로 그대로
돌려준다. Exception 전체를 잡는 catch-all은 두지 않아 예상 밖의 진짜 버그는
여전히 500으로 드러나게 한다.
- SeedController 업로드에 확장자(.xlsx/.xlsm) 검사를 추가해 임의의 바이트가
Apache POI로 그대로 전달되기 전에 SeedParseException으로 걸러낸다.
- POST /api/orgs/{id}/channels의 실제 혼합 성공/실패 결과가 200으로 내려가는
경로를 컨트롤러 경계에서 검증하는 테스트를 추가하고, 담당자 정보 누락
테스트의 law 단정을 보강했다.
- CookieCsrfTokenRepository.saveToken()이 한 번도 호출되지 않아 브라우저가
XSRF-TOKEN 쿠키를 영영 못 받던 문제를 Spring Security 레퍼런스가 SPA용으로
제시하는 방식대로 고쳤다. BasicAuthenticationFilter 뒤에 지연 토큰을 강제
resolve하는 필터를 추가하고, 기본 XorCsrfTokenRequestAttributeHandler가
BREACH 마스킹 때문에 쿠키 원문과 헤더 값을 불일치시키던 문제를
SpaCsrfTokenRequestHandler로 해결했다(헤더 존재 시 마스킹 해제 없이 신뢰,
파라미터 기반 검증은 기존 Xor 위임 유지).
- "로그인 엔드포인트는 인증없이 접근할 수 있다" 테스트가 permitAll() 삭제와
무관하게 항상 같은 401을 반환해 아무것도 증명하지 못하던 문제를, 인증 실패와
인가 차단이 세션 생성 여부에서 실제로 다르다는 점(ExceptionTranslationFilter의
RequestCache)으로 구분하도록 재작성했다.
- AdminProperties record의 toString()이 비밀번호를 그대로 노출하지 않도록
마스킹했다.
- formLogin에 커스텀 loginPage를 지정해 DefaultLoginPageGeneratingFilter가
"/login"을 가로채지 않도록(3단계 SPA 클라이언트 라우트 확보) 했다.
- CSRF 쿠키 왕복 회귀 테스트, 토큰 누락 시 응답 코드, 로그인 페이지 미노출을
검증하는 테스트 3건을 추가했다. with(csrf())가 캐시된 컨텍스트의 CsrfFilter
빈을 영구히 세션 기반으로 바꿔치기하는 부작용이 있어 @TestMethodOrder로 실행
순서를 고정했다.
Co-Authored-By: Claude Opus 4.8 (1M context)