같은 시트에 동일 기관이 두 번 들어오면 DB는 upsert로 한 행에 합치지만
집계는 둘 다 created로 세어 report가 실제 결과와 어긋났다. 처리 완료된
키를 그 자리에서 seen 집합에 반영해 두 번째 등장부터는 updated로 잡히게
했다.
또한 seed()가 엑셀 파싱까지 @Transactional 안에서 수행해 파싱 중에도
DB 커넥션을 점유하고 있었다. 파싱은 트랜잭션 밖으로 빼고, DB 조회+upsert
구간만 TransactionTemplate으로 감싸 커넥션 점유 구간을 최소화했다.
(같은 빈 self-invocation으로 @Transactional을 추가하면 프록시를 우회해
트랜잭션이 걸리지 않으므로 이 방식을 택함.)
중복 기관 업로드 시나리오에 대한 테스트를 추가했다.
- 연번1 등 NUMERIC 셀을 (long) 캐스팅해 절삭하던 것을 Math.round로 교체.
부동소수점 오차(예: 6.999999999999998)가 실제 값보다 한 자리 작은
기관번호("006")로 읽혀 채널명이 잘못 생성되는 문제를 막는다.
- FORMULA 셀은 default 분기로 빠져 항상 빈 문자열로 읽히던 것을 고쳐,
캐시된 수식 결과 타입(getCachedFormulaResultType)에 따라 STRING/NUMERIC
처리 로직을 재사용하도록 cellValue(Cell, CellType) 재귀 구조로 정리.
- 두 결함을 각각 재현하는 테스트 추가(부동소수점 절삭, 수식 셀 캐시값 읽기).
Co-Authored-By: Claude Opus 4.8 (1M context)
updateChannelId(id, kind, channelId)는 kind가 "mj"가 아니면 무조건
로 빠져 channel_id_law에 잘못 기록됐다. 오타·null·새 kind가
들어와도 예외 없이 조용히 엉뚱한 컬럼을 덮어써 검증이 불가능했다.
분기를 없애고 updateChannelIdMj/updateChannelIdLaw로 나눠
컬럼을 컴파일 타임에 고정한다. 폴백 경로 자체가 사라져 다음 단계인
Mattermost 채널 프로비저닝에서 한쪽씩 기록해도 안전하다.
생성자가 2개(공개 1-인자, 패키지 전용 2-인자)로 늘어나며 Spring의
단일 생성자 자동 선택 규칙이 더 이상 적용되지 않아, 기본 생성자를
찾지 못해 컨텍스트 리프레시 단계에서 BeanCreationException으로
애플리케이션 기동이 실패하고 있었다. 공개 1-인자 생성자에
@Autowired를 명시해 Spring이 이를 명확히 선택하도록 고쳤다.
Spring 컨텍스트를 실제로 로딩해 MattermostClient 빈을 검증하는
테스트가 없어 이 회귀를 잡지 못했으므로, AbstractDbTest(신규
공통 베이스)와 이를 상속하는 MattermostRestClientSpringWiringTest를
추가해 재발을 방지한다.
WireMock(Jetty)의 h2c 업그레이드 협상 문제를 회피하려던 HTTP/1.1 고정이
운영 코드(RestClient)에 들어가 있어 실제로는 HTTPS/ALPN으로 협상하는
운영 전송 계층까지 불필요하게 좁히고 있었다. 전송 설정을 주입 가능한
생성자로 분리해 운영 생성자는 프레임워크 기본값을 쓰고, 테스트만
HTTP/1.1을 고정하도록 수정했다.