application.yml에 server.port가 없어 기본 8080으로 뜨고, 실행 스크립트마다 --server.port를
따로 넘기고 있어서 환경별로 포트가 달랐다. 앱 자체 기본값을 8877로 두어 어디서 띄우든
같은 포트가 되게 한다. SERVER_PORT 환경변수로는 여전히 덮어쓸 수 있다.
함께 맞춘 곳:
- Dockerfile EXPOSE / HEALTHCHECK, docker-compose 포트 매핑
- deploy/start.sh 기본값, itnhub.env.example (SERVER_PORT·TZ 항목 추가)
- vite 개발 프록시 대상(:8080 -> :8877). 이걸 안 바꾸면 npm run dev 에서 /api 가 죽는다
- run-local.ps1 은 --server.port 인자를 떼고 앱 기본값을 따르게 함
- README / deploy/README 의 포트 표기
로컬에서 재빌드 후 확인: 8877 /login 200, 8080 닫힘.
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로 제공한다.
기관의 신청기관/문정원/아이티앤/변호사 담당자가 채널 생성(또는 재확인) 시
이메일 기준으로 Mattermost 계정을 찾거나 새로 만들고, 문정원/법률검토 채널에
알맞게 추가하도록 ChannelProvisionService.ensureMembers 훅을 추가했다.
계정 생성 실패(아이디 중복 등)와 채널 추가 실패는 담당자별로 격리되어
provision 결과를 뒤집지 않고 메시지에만 남는다.
Co-Authored-By: ITN Dev
- 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)를 추가했다.
경찰청 계열처럼 연번1(기관번호) 하나로 하위기관을 대표기관에 흡수하던 모델을
폐기하고, 시트의 모든 행(연번1_연번2)이 각자 독립된 기관·채널 쌍을 갖도록 바꿨다.
경찰청_치안정책연구소에 대한 -policy- 특례는 연번 자체가 하위기관까지 구분하므로
더 이상 필요 없어 제거했다. 기존 채널 ID는 V5 마이그레이션이 org_no만 변환해
그대로 보존한다.
기관에 박혀 있던 담당자 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 채널 프로비저닝에서 한쪽씩 기록해도 안전하다.
연번+기관명 유니크 테스트가 단일 삽입 후 건수만 확인해 uq_organization_no_name
제약이 삭제돼도 통과하는 문제를 수정. 동일 조합 중복 삽입 시 예외 발생과,
동일 연번(008 경찰청/경찰청_치안정책연구소)의 다른 기관명은 정상 저장되는
두 경우를 모두 검증하도록 변경. application.yml의 hikari.schema 설정에는
Flyway 스키마 지정과 별개로 필요한 이유를 주석으로 명시.