CodeService가 기동 후 첫 조회에 코드를 한 번 읽어 메모리에 들고 있는다. 지연 로딩인
이유는 Flyway 마이그레이션보다 빈 초기화가 먼저 돌 수 있기 때문이다.
활성 목록과 전체 목록을 나눠 들고 있는다. 화면 선택지에는 활성만 나가지만, 이미
저장된 과거 값의 라벨을 그리려면 비활성도 조회돼야 한다.
GET /api/meta/codes는 아직 소비자가 없다. 화면 전환은 Phase 2다.
Co-Authored-By: Claude Opus 5 (1M context)
요청자 피드백 PPT 2건(기능확인 24쪽, 문정원 검토내용 17쪽)에서 확인된
요구를 다음과 같이 반영한다.
- 대시보드: KPI 7타일 + "단계 미지정" 포함 13컬럼 칸반(카드 드래그로 단계 이동)
+ 최근 진행 기관. 집계는 /api/dashboard 한 번으로 끝낸다 - 기관별로 건수를
반복 조회하면 화면 한 번에 150회 조회가 되기 때문이다.
- 사업관리: 3단계 대상 기관 현황, 신청 확인 연락 이력, 기관별 최종 보고서.
기관 현황 숫자는 대시보드와 같은 집계를 재사용해 두 화면이 어긋나지 않게 한다.
- 시스템관리: 채널 초기화(대상 미리보기 → 확인문구 입력 → 서버 재검사).
삭제가 아니라 보관(아카이브)이며 DB가 아는 채널만 대상으로 한다.
- 권리확인: 제3자 권리처리 정책변경 반영. "권리처리 추진 미희망"과 공공누리
"보류"를 신설하고, 처리결과에 따라 공공누리 유형·비고를 규칙대로 자동 채운다.
- 권리확인/권리처리: 일괄 등록·선택 삭제와 열별 조건 복합검색(AND).
- 업무메모: 작성자를 화면에서 고르지 않고 로그인 사용자를 서버가 기록하며,
수정 기능을 추가한다(작성자·작성시각은 유지).
- 기관관리: 채널에 고정된 최초 안내글을 확인하는 [최초 게시글 보기].
- 도움말: 주요 버튼 옆 (?) 모달 15개 항목. 실제 화면 캡처를 함께 담는다.
마이그레이션 두 건:
- V11 "채널 있음 <=> 단계 있음" 불변식을 맞추는 1회성 백필. 단계 기능(V8)
이전에 채널을 만든 기관이 칸반에서 사라지는 것을 막는다.
- V12 사업관리용 contact_log / org_report.
테스트: 백엔드 221건, 프런트 191건 전부 통과.
Co-Authored-By: Claude Opus 5 (1M context)
권리확인 모듈을 참고해 권리처리 탭 전용 process_item 테이블과 CRUD API를 구성한다.
조사원+권리확인 영역은 재업로드마다 항상 최신 파일값으로 갱신하고, 계약서 유무와
권리처리 판정(공공누리유형/최종의견/판단근거/처리상태)은 웹에서 한 번이라도 수정하면
재업로드가 덮어쓰지 않는다. 처리완료 최초 도달 시각은 processed_at에 남기고 이후
재저장에도 값이 바뀌지 않는다.
기관별 권리확인 엑셀(Sheet0, ~1000행)을 업로드해 review_item 테이블에 반영하고,
조사원 항목은 항상 최신화하되 변호사 판정은 웹에서 한번 수정되면(web_edited_at)
재업로드가 덮어쓰지 않는 병합 정책을 적용한다. 목록/단건조회/판정저장/삭제/원본
서식 그대로의 엑셀 다운로드까지 REST로 제공한다.
- V8 마이그레이션으로 organization.stage와 stage_history 테이블 도입
- PUT /api/orgs/{id}/stage: 1..12 범위 검증 후 단계 변경 + 이력 적재
- 채널 2개가 처음 모두 갖춰지면 진행단계 1(신청)을 자동 시작(재실행 안전)
- GET /api/orgs/{id}/timeline: 단계 이력·업무메모·채널 첨부파일을 최신순으로 합쳐 제공
(Mattermost 조회 실패는 채널별로 흡수하고 200 유지)
시드와 회원명단 업로드가 같은 사람을 여러 기관 행에서 반복해 만나도(예: 경찰청
계열 27곳이 담당자 1명을 공유) 중복 생성하지 않도록 (구분,성명,전화,이메일) 기준
조회(ContactMapper.findMatching)를 추가하고 SeedService가 이를 쓰도록 바꿨다.
담당자 구분에 수행기관(OPERATOR)을 추가하고, 회원명단의 신청기관 자동배정을 위해
기관명 단독 조회(OrganizationMapper.findByOrgName)를 추가했다.
기관에 박혀 있던 담당자 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()로 교체
신청기관 담당자 1종만 저장하던 기관 테이블에 문정원 담당자(부서/담당자/연락처/이메일)와
담당 변호사(성명/연락처/이메일/배정일) 정보를 추가해, 채널관리 화면에서 세 담당자를
한 번에 저장하고 다른 화면(기관관리·업무메모)에서도 쓸 수 있게 한다.
- V3 마이그레이션으로 organization에 컬럼 8개 추가 (upsertBySeed는 그대로 둬서
엑셀 재시드가 새 컬럼을 건드리지 않는다)
- ContactRequest/OrgResponse/updateContact에 8개 필드를 선택값으로 반영
- 컨트롤러 테스트 2건(신규 필드 왕복, 신규 필드 없는 기존 페이로드) +
매퍼 테스트 2건(영속화 왕복, 재시드 시 보존) 추가
기관관리 상세의 업무메모 탭이 쓸 CRUD 엔드포인트를 추가한다. 통화 등
담당자와의 연락 내용을 기관별로 남기는 단순 기능이라 Mattermost 연동
없이 순수 DB로만 처리한다.
- V2__work_memo.sql: work_memo 테이블, org_id+created_at 인덱스
- WorkMemoMapper/xml: 최신순 조회, 등록, (orgId, id) 동시 조건 삭제
- WorkMemoService/Controller: GET/POST /api/orgs/{id}/memos,
DELETE /api/orgs/{id}/memos/{memoId}
- GlobalExceptionHandler: contactName/body 검증 메시지 한글 라벨 추가
- WorkMemoControllerTest: 등록/조회/최신순/검증/404/삭제/인증 검증
Co-Authored-By: Claude Opus 4.8 (1M context)
updateChannelId(id, kind, channelId)는 kind가 "mj"가 아니면 무조건
로 빠져 channel_id_law에 잘못 기록됐다. 오타·null·새 kind가
들어와도 예외 없이 조용히 엉뚱한 컬럼을 덮어써 검증이 불가능했다.
분기를 없애고 updateChannelIdMj/updateChannelIdLaw로 나눠
컬럼을 컴파일 타임에 고정한다. 폴백 경로 자체가 사라져 다음 단계인
Mattermost 채널 프로비저닝에서 한쪽씩 기록해도 안전하다.