기관에 박혀 있던 담당자 3종(신청기관/문정원/변호사) 컬럼을 contact 테이블로 옮기고,
기관은 담당자 id만 배정으로 참조하게 했다. 신청기관 담당자 배정 여부가 채널 생성
가능(READY) 판정 기준이 되도록 상태 로직도 함께 바꿨다.
- V4 마이그레이션: contact 테이블 생성 + 기존 임베디드 컬럼 백필 후 제거
- kr.itn.itnhub.contact 패키지: 담당자 CRUD API (GET/POST/PUT/DELETE /api/contacts)
- PUT /api/orgs/{id}/assignments가 기존 /contact 엔드포인트를 대체 (구분 불일치 400)
- SeedService: 시트의 담당자명은 신청기관 담당자가 아직 없을 때만 새로 만들어 연결
- ChannelProvisionService 게이트를 hasApplicantAssigned()로 교체
같은 시트에 동일 기관이 두 번 들어오면 DB는 upsert로 한 행에 합치지만
집계는 둘 다 created로 세어 report가 실제 결과와 어긋났다. 처리 완료된
키를 그 자리에서 seen 집합에 반영해 두 번째 등장부터는 updated로 잡히게
했다.
또한 seed()가 엑셀 파싱까지 @Transactional 안에서 수행해 파싱 중에도
DB 커넥션을 점유하고 있었다. 파싱은 트랜잭션 밖으로 빼고, DB 조회+upsert
구간만 TransactionTemplate으로 감싸 커넥션 점유 구간을 최소화했다.
(같은 빈 self-invocation으로 @Transactional을 추가하면 프록시를 우회해
트랜잭션이 걸리지 않으므로 이 방식을 택함.)
중복 기관 업로드 시나리오에 대한 테스트를 추가했다.