기관별 권리확인 엑셀(Sheet0, ~1000행)을 업로드해 review_item 테이블에 반영하고,
조사원 항목은 항상 최신화하되 변호사 판정은 웹에서 한번 수정되면(web_edited_at)
재업로드가 덮어쓰지 않는 병합 정책을 적용한다. 목록/단건조회/판정저장/삭제/원본
서식 그대로의 엑셀 다운로드까지 REST로 제공한다.
기관의 신청기관/문정원/아이티앤/변호사 담당자가 채널 생성(또는 재확인) 시
이메일 기준으로 Mattermost 계정을 찾거나 새로 만들고, 문정원/법률검토 채널에
알맞게 추가하도록 ChannelProvisionService.ensureMembers 훅을 추가했다.
계정 생성 실패(아이디 중복 등)와 채널 추가 실패는 담당자별로 격리되어
provision 결과를 뒤집지 않고 메시지에만 남는다.
Co-Authored-By: ITN Dev
- STEPS 배열을 src/stages.ts(STAGE_LABELS)로 분리해 OrgOverview와 Timeline이 공유
- 업무단계 스트립: 완료(체크)/진행중/미래 상태 표시, 현재 단계 클릭 시 확인 후 다음 단계로 진행
- [진행단계 변경] 버튼을 활성화해 12단계 중 하나를 바로 골라 변경하는 모달 추가
- Timeline 컴포넌트: 단계변경/업무메모/자료등록 이벤트를 날짜별로 묶어 시간순으로 표시
- 관련 컴포넌트 테스트 fixture에 stage 필드 추가
- V8 마이그레이션으로 organization.stage와 stage_history 테이블 도입
- PUT /api/orgs/{id}/stage: 1..12 범위 검증 후 단계 변경 + 이력 적재
- 채널 2개가 처음 모두 갖춰지면 진행단계 1(신청)을 자동 시작(재실행 안전)
- GET /api/orgs/{id}/timeline: 단계 이력·업무메모·채널 첨부파일을 최신순으로 합쳐 제공
(Mattermost 조회 실패는 채널별로 흡수하고 200 유지)
POST /api/contacts/import로 회원정보 시트(Sheet1)를 업로드하면 구분(주관기관/
변호사/신청기관/수행기관)에 따라 담당자를 등록·갱신하고, 신청기관 담당자는
기관명이 정확히 일치하는 기관에 자동 배정한다. 이미 등록된 사람은
findMatching으로 재사용하고 소속/부서/직급은 비어 있을 때만 채워 재업로드해도
안전하다. 확장자·빈 파일 검증은 SeedController와 동일한 방식을 따르고
SeedParseException을 재사용해 400으로 처리한다.
시드와 회원명단 업로드가 같은 사람을 여러 기관 행에서 반복해 만나도(예: 경찰청
계열 27곳이 담당자 1명을 공유) 중복 생성하지 않도록 (구분,성명,전화,이메일) 기준
조회(ContactMapper.findMatching)를 추가하고 SeedService가 이를 쓰도록 바꿨다.
담당자 구분에 수행기관(OPERATOR)을 추가하고, 회원명단의 신청기관 자동배정을 위해
기관명 단독 조회(OrganizationMapper.findByOrgName)를 추가했다.
경찰청 계열처럼 연번1(기관번호) 하나로 하위기관을 대표기관에 흡수하던 모델을
폐기하고, 시트의 모든 행(연번1_연번2)이 각자 독립된 기관·채널 쌍을 갖도록 바꿨다.
경찰청_치안정책연구소에 대한 -policy- 특례는 연번 자체가 하위기관까지 구분하므로
더 이상 필요 없어 제거했다. 기존 채널 ID는 V5 마이그레이션이 org_no만 변환해
그대로 보존한다.
담당자 정보를 직접 입력하던 채널관리 화면을 배정 전용(선택/해제)으로 바꾸고,
담당자 등록·수정은 새 담당자관리 화면에서만 하도록 입력 경로를 하나로 모았다.
- 담당자관리(신규): 구분 필터 + 목록 표 + 추가/수정 공용 모달 + 삭제 확인
- ContactPickerModal(신규): 채널관리에서 역할별로 등록된 담당자를 검색해 배정
- OrgDetail: 담당자 입력 표 제거 → 배정 행 3개(미지정/선택/해제) + 변호사 배정일
- client.ts: Org가 flat 필드 대신 applicant/mj/lawyer 중첩 Contact를 갖도록 변경,
updateAssignments/getContacts/createContact/updateContactInfo/deleteContact 추가
- OrgOverview·WorkMemos·OrgList 등 org 픽스처와 조회 로직을 새 중첩 구조에 맞춤
기관에 박혀 있던 담당자 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()로 교체
백엔드에 추가된 문정원 담당자·담당 변호사 필드를 화면에 반영한다.
- 사이드바 "채널생성"을 "채널관리"로 이름을 바꾸고 기관관리 위로 이동
- 채널관리(OrgDetail) 담당자 입력을 신청기관/문정원/변호사 3열 그리드로 확장,
저장 버튼 하나로 세 그룹을 함께 저장 (필수값 규칙은 신청기관 담당자만 그대로 유지)
- 기관관리(OrgOverview) 카드 3개(신청기관 카드 + 추후연동 2개)를 담당자 3종
가로 표 하나로 교체
- 업무메모 담당자 선택에 신청기관/문정원/변호사 중 이름이 채워진 사람을
모두 옵션으로 제공 (중복 제거, 기존 직접입력 유지)
- 관련 컴포넌트 테스트와 org() 픽스처에 신규 필드 반영, 신규 동작 테스트 추가
신청기관 담당자 1종만 저장하던 기관 테이블에 문정원 담당자(부서/담당자/연락처/이메일)와
담당 변호사(성명/연락처/이메일/배정일) 정보를 추가해, 채널관리 화면에서 세 담당자를
한 번에 저장하고 다른 화면(기관관리·업무메모)에서도 쓸 수 있게 한다.
- V3 마이그레이션으로 organization에 컬럼 8개 추가 (upsertBySeed는 그대로 둬서
엑셀 재시드가 새 컬럼을 건드리지 않는다)
- ContactRequest/OrgResponse/updateContact에 8개 필드를 선택값으로 반영
- 컨트롤러 테스트 2건(신규 필드 왕복, 신규 필드 없는 기존 페이로드) +
매퍼 테스트 2건(영속화 왕복, 재시드 시 보존) 추가