# 공통코드 도입과 하드코딩 제거 설계 작성일 2026-07-28 근거 문서: `ITN-HUB 요구사항 확인요청_260727_영익 검토.pptx` (28항목 중 회신분) ## 1. 배경 요구사항 회신에서 "보고서 제출 완료" 13단계 신설이 확정됐다. 이 한 줄을 반영하려면 지금은 백엔드 4곳, 프론트 8곳, 테스트 6곳을 동시에 고쳐야 한다. 단계 번호와 선택지 문자열이 소스 곳곳에 리터럴로 흩어져 있기 때문이다. 회신 28항목 중 11항목이 아직 미정이다. 앞으로도 선택지 추가·이름 변경 요청이 계속 들어온다. 그때마다 같은 규모의 수정을 반복하지 않으려면 코드값을 데이터로 옮겨야 한다. 목표는 두 가지다. 1. 코드값을 DB 공통코드로 옮기고, 소스에서 코드값 리터럴을 없앤다. 2. 그 위에 확정된 요구사항 7건을 반영한다. ## 2. 현황 진단 전수 조사 결과 같은 코드체계가 여러 곳에 중복 정의되어 있다. | 코드체계 | 정의된 곳 | 실측 | |---|---|---| | `'처리완료'` | 프론트 6 + Java 2 + SQL 5 | **13곳** | | 공공누리 유형 | `ReviewBoard.tsx:50`(7개) / `:978`(5개) / `ProcessBoard.tsx:29`(6개) | **3중, 개수·순서 모두 다름** | | 담당자 구분 | `ContactsPage.tsx:15,33,128` + `MemberDirectoryParser.java:43` + `client.ts:3` | **5중** | | 진행단계 12 | `stages.ts:4` + `StageService.java:34` + `DashboardService.java:16-20` + `Dashboard.tsx:31,241,244` + `ProjectsPage.tsx:240` | **5중** | | 연락 방법 | `ProjectsPage.tsx:32` | 화면에만, **서버 검증 없음** | 구조적 사실: - DB에 코드테이블이 없다. 마이그레이션 V1~V12가 만드는 테이블은 8개뿐이고, 코드값 컬럼은 전부 자유 `varchar` + 주석이다. CHECK 제약도 FK도 없다. - 백엔드에 진행단계·처리결과·공공누리유형 enum이 없다. enum은 `OrgStatus`, `ChannelKind`, `ProvisionOutcome` 3개뿐이다. - 코드값의 정본이 프론트 컴포넌트 파일 안에 있다. 서버는 값을 저장만 하고, 검증은 `ProcessService.java:22`의 처리상태 화이트리스트 하나뿐이다. - 메타데이터 API가 없다(`/api/meta`, `/api/codes` 부재). - 화면 파일이 크다: `ReviewBoard.tsx` 1,279줄 / `ProcessBoard.tsx` 1,060줄 / `OrgOverview.tsx` 740줄 / `Dashboard.tsx` 697줄. ## 3. 저장값 정책 **기존 한글 문자열을 저장값으로 그대로 유지한다.** (승인 완료) `code.code` = 지금 DB에 들어 있는 값. `'처리완료'`, `'권리처리 추진'` 그대로다. 진행단계만 예외로 숫자 문자열(`'1'`~`'13'`)이며 `organization.stage`는 지금처럼 smallint다. 이유: 기존 데이터를 건드리지 않고, 엑셀 업로드·다운로드 양식도 그대로 둘 수 있다. 영문 코드키 전환은 데이터 변환과 파서 전면 수정을 동반해 위험 대비 실익이 없다. 코드에서 리터럴이 사라진다는 목적은 이 방식으로도 완전히 달성된다. ## 4. 범위 ### 포함 - 공통코드 테이블과 시드 - 백엔드 `code` 패키지, 코드 조회·관리 API - 프론트 `codes` 모듈, 화면의 하드코딩 배열 제거 - 코드 관리 화면 (승인 완료) - SQL·Java 리터럴 제거, 엑셀 양식 정의 통합, 메시지 상수 분리 - 손대는 화면 파일 분해 - 확정 요구사항 7건 반영 (§8) ### 제외 회신에서 미정이거나 결정 대기인 항목은 이번 범위에서 뺀다. - 미응답 10건: 1(서류제출 기준)·3(보고서작성 기준)·9(최근변경 범위)·13(초상권+개방불가)· 14(검색 AND/OR)·18(자동 단계전환)·19(되돌림)·22(작성자 표기)·24(연락방법)·26(자료실) - ~~재질문 1건: 12(권리처리필요 자동체크)~~ → **2026-07-30 회신으로 확정: 「지금처럼 자동으로 두기」. 현행 유지이므로 코드 변경 없음** - 결정 대기: 20·21·27 (Mattermost 존치 여부와 사용자 계정 체계) - 28(보고서 양식) — 양식 수령 후 별건 단, 1·3·24는 코드테이블로 옮겨두므로 답이 오면 **데이터만 바꾸면 된다**. ## 5. 데이터 설계 ### 5.1 스키마 ```sql create table code_group ( group_id varchar(50) primary key, group_name varchar(100) not null, description text, editable boolean not null default true -- 관리 화면에서 추가·삭제를 허용할지 ); create table code ( group_id varchar(50) not null references code_group(group_id), code varchar(300) not null, -- 저장값. review_minor가 varchar(300)이라 이에 맞춤 label varchar(200) not null, -- 화면 표시명 sort_order int not null, active boolean not null default true, attrs jsonb not null default '{}'::jsonb, primary key (group_id, code) ); create index idx_code_group_sort on code (group_id, sort_order); ``` `code`와 `label`을 나눈 이유: 권리확인 세부항목은 저장값이 `'2. 후천적 권리 전부 보유(계약서 확인 필요)'`인데 화면에는 `'2. 후천적 권리 전부 보유'` + 회색 부연설명으로 나뉘어 보인다 (`ReviewBoard.tsx:98-108`). 한 컬럼으로는 기존 데이터를 유지할 수 없다. `attrs`에는 코드마다 붙는 부가 속성을 넣는다. 값만 담고 동작은 담지 않는다(§5.4). ### 5.2 코드 그룹 11개 그룹, 60여 개 코드. 전체 시드는 `V13__common_code.sql`에 둔다. | group_id | 내용 | 개수 | 대체하는 하드코딩 | |---|---|---|---| | `STAGE` | 진행단계 | 13 | `stages.ts:4-17`, `DashboardService.java:16-20`, `StageService.java:34` | | `STAGE_GROUP` | 업무구간 | 5 | `stages.ts:28-34`, `Dashboard.tsx:34-40` | | `REVIEW_MAJOR` | 권리확인 대분류 | 4 | `ReviewBoard.tsx:18`, `suggestReviewResult():75-80` | | `REVIEW_MINOR` | 권리확인 세부 | 5 | `ReviewBoard.tsx:20-26, 59-63, 98-108` | | `REVIEW_RESULT` | 처리결과 | 5 | `ReviewBoard.tsx:32-42, 65-71` | | `KOGL_TYPE` | 공공누리 유형 | 7 | `ReviewBoard.tsx:50, 53, 978`, `ProcessBoard.tsx:29, 935, 948` | | `PROCESS_STATUS` | 권리처리 상태 | 2 | `ProcessBoard.tsx:20-24, 31`, `ProcessService.java:22` | | `CONTRACT_DOC` | 계약 서류 | 6 | `ProcessBoard.tsx:26, 28` | | `CONTACT_METHOD` | 연락 방법 | 4 | `ProjectsPage.tsx:32` | | `CONTACT_CATEGORY` | 담당자 구분 | 5 | `ContactsPage.tsx:15, 33, 128`, `MemberDirectoryParser.java:43-47` | | `ATTACHMENT_YN` / `KOGL_ATTACHED` | 첨부·부착 여부 | 2+2 | `ReviewBoard.tsx:939, 956` | ### 5.3 STAGE 설계 — 요구사항 [7][11][2] 반영 ``` code label attrs 1 신청 {"groupKey":"intake", "progress":"applied"} 2 목록접수 {"groupKey":"intake", "progress":"active", "kpiFrom":"docSubmitted"} 3 예비검토 {"groupKey":"intake", "progress":"active"} 4 변호사 배당 {"groupKey":"assign", "progress":"active"} 5 법률검토(권리확인) {"groupKey":"check", "progress":"active"} 6 RE:확인 {"groupKey":"check", "progress":"active"} 7 법률검토(권리확인) 완료 {"groupKey":"check", "progress":"active"} 8 법률검토(권리처리) {"groupKey":"process", "progress":"active"} 9 RE:처리 {"groupKey":"process", "progress":"active"} 10 법률검토(권리처리) 완료 {"groupKey":"process", "progress":"active"} 11 법률검토 최종완료 {"groupKey":"closing", "progress":"active"} 12 보고서 작성 {"groupKey":"closing", "progress":"active", "kpiFrom":"reportWriting"} 13 보고서 제출 완료 {"groupKey":"closing", "progress":"done", "kpiFrom":"completed"} ``` - `progress` — 요구사항 [7]. 신청은 ①만, 완료는 ⑬만, 나머지는 진행중. 단계가 `null`인 기관(채널 미생성)은 `progress` 대상이 아니며 화면에서 '단계 미지정'으로 따로 다룬다(승인 완료). 칸반 첫 컬럼이 이 자리다. - `kpiFrom` — "이 단계부터 해당 KPI에 집계"라는 임계값. `DashboardService`의 상수 `STAGE_DOC_SUBMITTED=2` / `STAGE_COMPLETED=11` / `STAGE_REPORT=12`를 대체한다. 요구사항 [2](보고서가 올라와야 최종완료)는 `completed`를 13에 두는 것으로 해결된다. 미응답인 [1]·[3]은 현행 값을 그대로 옮겨두고, 답이 오면 데이터만 바꾼다. - 원문자(①②③)는 저장하지 않는다. 단계 번호에서 계산한다(U+2460 + n − 1, 20 초과 시 숫자). `Dashboard.tsx:31`의 `CIRCLED` 배열은 삭제한다. ### 5.4 KOGL_TYPE 설계 — 검증에서 드러난 보완점 세 곳의 목록이 7개/5개/6개로 달랐던 것은 실수가 아니라 **쓰이는 자리가 다르기 때문**이다. | 자리(scope) | 내용 | 항목 | |---|---|---| | `review` | 변호사 판정값 | 0~4유형, 개방불가, 보류 | | `process` | 권리처리 판정값 | 0~4유형, 개방불가 (보류 없음) | | `prior` | 기존 부착된 유형 | 0~4유형 | `sort_order` 하나로는 이 차이를 담을 수 없다. `attrs.scopes`로 사용처를, `attrs.firstRow`로 라디오 첫 줄 배치를 표현한다. ``` 0유형 {"scopes":["review","process","prior"], "firstRow":["review","process"]} 1~4유형 {"scopes":["review","process","prior"], "firstRow":[]} 개방불가 {"scopes":["review","process"], "firstRow":["review","process"]} 보류 {"scopes":["review"], "firstRow":["review"]} ``` 이 구분 없이 단순 병합했다면 권리처리 화면에 `보류`가 잘못 노출된다. ### 5.5 색상 — DB에 CSS를 넣지 않는다 뱃지 색이 지금 Tailwind 클래스 문자열이다(`ReviewBoard.tsx:65-71`). DB에는 `attrs.tone`으로 의미 토큰(`emerald`, `amber`, `blue`, `red`, `slate`)만 저장하고, 토큰→클래스 매핑은 프론트가 갖는다. 화면 스타일 변경이 DB 수정을 부르지 않게 한다. ### 5.6 값과 동작의 경계 `applyResultDerivations`(`ReviewBoard.tsx:812-834`)를 실측한 결과, 처리결과 선택 시 동작은 단순 대입이 아니었다. | 처리결과 | 동작 | |---|---| | 권리처리 추진 | 공공누리 `보류` 대입, 권리처리필요 켬 | | 개방불가 | 공공누리 `개방불가` 대입, 권리처리필요 끔 | | 권리처리 추진 미희망 | 권리처리필요 끔, **기존 부착 유형을 복사**, **비고에 안내문구 덧붙임** | 마지막 행의 "복사"와 "덧붙임"까지 데이터로 옮기면 `attrs` 안에 규칙 언어를 새로 만드는 꼴이 된다. **값은 데이터로, 동작은 코드로** 나눈다. ``` 신유형 개방 {"tone":"emerald","openable":"Y"} 계약서 등 재확인 {"tone":"amber"} 권리처리 추진 {"tone":"blue", "needsProcessing":true, "koglSet":"보류"} 개방불가 {"tone":"red", "needsProcessing":false, "koglSet":"개방불가"} 권리처리 추진 미희망 {"tone":"slate", "needsProcessing":false, "koglCopiesPrior":true} ``` `koglCopiesPrior`가 참일 때 무엇을 복사하고 어떤 문구를 붙일지는 코드가 정한다. 문구 자체는 메시지 상수 모듈로 옮긴다. 코드에서 리터럴이 사라진다는 목적은 유지된다. `needsProcessing`을 데이터로 둔 이유는 이것이 요구사항 [12]의 대상이기 때문이다. 자동 처리를 끄기로 결정되면 코드 수정 없이 속성만 제거하면 된다. ### 5.7 기존 데이터 정합성 운영 DB에 시드와 일치하지 않는 값이 남아 있을 수 있다(정책 변경 전 값, 공백 차이, 오타). Phase 1에 정합성 점검을 넣는다. ```sql select 'review_result' as col, review_result as value, count(*) from review_item where review_result is not null and review_result <> '' and review_result not in (select code from code where group_id = 'REVIEW_RESULT') group by review_result; ``` `review_major`, `review_minor`, `judged_kogl_type`, `process_status`, `contact_log.method`에 같은 점검을 돌린다. 발견된 고아 값은 **삭제하지 않고** `active = false`로 코드테이블에 추가한다. 기존 화면에서 값이 사라지는 사고를 막는다. ## 6. 애플리케이션 설계 ### 6.1 백엔드 — `kr.itn.itnhub.code` | 클래스 | 역할 | |---|---| | `Code`, `CodeGroup` | record. `attrs`는 `Map` | | `CodeMapper` + `CodeMapper.xml` | 조회·저장 | | `CodeService` | 기동 시 전체 로드 후 메모리 캐시. 저장 시 캐시 갱신 | | `CodeController` | 조회·관리 API | | `Codes` | 그룹 ID 상수와 로직이 참조하는 코드 상수 | | `CodeValidator` | 저장 요청 값이 해당 그룹의 활성 코드인지 검증 | 코드값은 자주 바뀌지 않으므로 캐시는 `ConcurrentHashMap` 한 겹으로 충분하다. 분산 캐시는 넣지 않는다(단일 인스턴스 운영). API: ``` GET /api/meta/codes 전체 코드 (프론트 부팅 시 1회) GET /api/admin/codes/groups 관리 화면용 그룹 목록 GET /api/admin/codes/{groupId} 그룹별 코드 목록 + 사용 건수 POST /api/admin/codes/{groupId} 코드 추가 PUT /api/admin/codes/{groupId}/{code} 라벨·순서·사용여부·attrs 수정 DELETE /api/admin/codes/{groupId}/{code} 코드 삭제 (사용 중이면 거부) ``` ### 6.2 프론트 — `frontend/src/codes/` ``` codes/ types.ts Code, CodeMap 타입 CodeProvider.tsx 로그인 후 1회 조회, Context 제공 useCodes.ts useCodes('REVIEW_RESULT'), useCode(group, code) stage.ts 단계 전용 헬퍼 (label, symbol, groupKey, progress, kpiFrom) tone.ts tone 토큰 → Tailwind 클래스 매핑 ``` 기존 `frontend/src/stages.ts`는 삭제하고 `codes/stage.ts`로 대체한다. 로딩 시점은 인증 성공 직후다. 로그인 화면에서는 코드가 필요 없다. 조회 실패 시 화면을 그리지 않고 오류를 표시한다(빈 선택지로 저장되는 사고 방지). 각 화면 상단의 옵션 배열은 전부 삭제하고 `useCodes`로 대체한다. ### 6.3 코드 관리 화면 좌측 그룹 목록, 우측 코드 목록. 사이드바에 '공통코드' 메뉴를 추가한다. - 편집 가능: 표시명, 정렬순서, 사용여부, 코드 추가·삭제 - `attrs`는 접이식 JSON 편집기로 노출하고 경고 문구를 붙인다. 그룹별 전용 폼은 만들지 않는다. 실제 편집 수요는 표시명과 순서에 몰려 있고, 전용 폼은 그룹이 늘 때마다 화면을 늘려야 한다. - 삭제 안전장치: 해당 코드를 쓰는 데이터 건수를 먼저 조회하고, 1건 이상이면 삭제를 막고 사용여부 끄기를 안내한다. - `code_group.editable = false`인 그룹(`STAGE` 등 로직 결합이 강한 그룹)은 추가·삭제를 막고 표시명·순서만 허용한다. 단계 추가는 마이그레이션으로 한다. - 권한: 지금은 인증만으로 충분하다(관리자 1계정). 사용자 계정 도입 시 관리자 전용으로 제한한다. ### 6.4 코드테이블 밖에서 처리하는 것 **SQL 안의 `'처리완료'` 5곳** — 쿼리라서 코드테이블로 뺄 수 없다. MyBatis 파라미터로 주입한다. 대상: `ProcessItemMapper.xml:42, 45, 148, 176, 194`, `DashboardMapper.xml:78`. 매퍼 인터페이스 시그니처에 `doneStatus`를 추가하고 서비스가 `Codes`에서 읽어 넘긴다. **엑셀 양식 정의** — 코드값이 아니라 파일 포맷이다. 코드테이블에 넣지 않는다. 다만 지금 업로드 쪽(`ReviewParser.COL_*` 23개, `ProcessParser.COL_*` 25개)과 다운로드 쪽(`ReviewService.HEADERS` 25개, `ProcessService.HEADERS` 27개)이 서로 독립 정의라 **한쪽만 고치면 양식이 어긋나는 결함**이 있다. 열 순서·헤더명·필드를 한 곳에서 선언하는 스키마 모듈로 합치고, 업로드와 다운로드가 같은 정의를 참조하게 한다. 주의: `ProcessParser.java:66-68`에 "헤더는 T열인데 데이터는 U열" 예외 처리가 있다. 통합 시 이 예외를 놓치면 권리처리 업로드가 조용히 어긋난다. **안내 문구** — `NOTE_NO_PROCESSING` 등은 코드값이 아니라 메시지다. 메시지 상수 모듈로 분리한다. **Mattermost 채널 종류** — `ChannelKind` enum과 설정 프로퍼티로 이미 관리된다. 그대로 둔다. ### 6.5 화면 파일 분해 손대는 파일만 분해한다. 무관한 파일은 건드리지 않는다. | 현재 | 분해 | |---|---| | `ReviewBoard.tsx` 1,279 | `ReviewBoard` / `ReviewFilters` / `ReviewTable` / `ReviewDetail` / `ReviewBulkForm` | | `ProcessBoard.tsx` 1,060 | `ProcessBoard` / `ProcessFilters` / `ProcessTable` / `ProcessDetail` / `ProcessBulkForm` | | `Dashboard.tsx` 697 | `Dashboard` / `KpiTiles` / `KanbanBoard` / `RecentOrgTable` | | `OrgOverview.tsx` 740 | `OrgOverview` / `OrgStageStrip` / `OrgTabs` / `ReTab`(신규) | ## 7. 실행 순서 Phase 1~4는 **기존 동작이 바뀌지 않는다**. Phase 5는 화면을 새로 추가할 뿐 기존 동작을 건드리지 않는다. 기존 테스트 40개(백엔드 22 + 프론트 18)가 그대로 통과해야 한다는 것이 Phase 1~5 각 단계의 완료 조건이며, 이것이 이번 작업의 안전망이다. 실제 동작이 바뀌는 것은 Phase 6뿐이다. | Phase | 내용 | 동작 변화 | |---|---|---| | 1 | 코드테이블 + 시드 + `code` 패키지 + `/api/meta/codes` + 정합성 점검 | 없음 | | 2 | 프론트 `codes` 모듈, 화면이 코드테이블에서 옵션을 읽도록 전환, 하드코딩 배열 삭제 | 없음 | | 3 | Java·SQL 리터럴 제거, 엑셀 양식 정의 통합, 메시지 상수 분리 | 없음 | | 4 | 화면 파일 분해 | 없음 | | 5 | 코드 관리 화면 | 화면 추가 | | 6 | 요구사항 반영 (§8) | 있음 | ## 8. 요구사항 반영 (Phase 6) | 항목 | 내용 | 작업 | |---|---|---| | [7][11] | 13단계 "보고서 제출 완료" 신설, 진행상태 신청/진행중/완료 | 시드에 13 추가, `StageService` 상한을 코드 개수로, 칸반 컬럼 = 단계미지정 + 13 | | [2] | 완료 = 보고서 업로드 기준 | `kpiFrom:"completed"`를 13에 부여 | | [4][5] | RE 메모 기능 신설 | `re_memo` 테이블, `re` 패키지, 기관관리 RE 탭, 대시보드 미해결 RE 집계 | | [15] | 일괄등록에 비고 추가 | `BulkJudgmentRequest`에 `lawyerNote`, `BulkProcessingRequest`에 `reviewNote` | | [8] | 자료접수 = 권리확인·권리처리 통합 | `Dashboard`의 판정에 `processTotal` 포함 | | [6] | 업무구간 필터 삭제, 필터 순서 재배치 | 필터 UI만 제거. `STAGE_GROUP`은 칸반 색·카드 모양에 계속 쓰이므로 유지 | | [25] | 보고서 수정 | `PUT /api/orgs/{id}/reports/{reportId}` 신설 | | [16] | 표기 누락 점검 | 현행 2줄 표기 유지, 열 누락 여부만 확인 | | [17][21][10] | 현행 유지 | 작업 없음 | | [23] | 기관 100개 | 코드 변경 없음. 명부 엑셀 수령 후 업로드 | ### RE 메모 설계 회신 예시: `ooo 계약서 및 제안요청서 송부 요청, 장영익, 2026.07.08` ```sql create table re_memo ( id bigserial primary key, org_id bigint not null references organization(id), content text not null, author varchar(100) not null, memo_date date not null, resolved boolean not null default false, resolved_at timestamptz, created_at timestamptz not null default now(), updated_at timestamptz not null default now() ); ``` 메모 1건 = RE 1건. 기관관리 RE 탭에서 목록·등록·수정·삭제한다. 대시보드 '미해결 RE'는 `resolved = false` 건수 합계다. `DashboardMapper.xml:64`의 `0 as re_count`를 서브쿼리로 교체한다 (해당 파일 44-45행 주석이 이미 이 방식을 예고하고 있다). > **확정(2026-07-30 회신)**: `resolved` 플래그는 회신에 없던 항목이라 완료 체크박스로 설계하고 > 확인 요청했고, 「지금처럼 「해결」 버튼 두기」로 확정됐다. 현행 유지이므로 변경 없음. ## 9. 테스트 기존 테스트는 리팩터링의 회귀 안전망이다. Phase 1~5 동안 계속 통과해야 한다. 신규로 필요한 것: - `CodeServiceTest` — 캐시 적재·갱신, scope 필터, 활성 코드만 노출 - `CodeControllerTest` — 조회·수정·삭제, 사용 중 코드 삭제 거부 - `DashboardServiceTest` — **현재 없다**. `kpiFrom` 기반 집계로 바꾸기 전에 먼저 만들어 현행 동작을 고정한다 - `ReviewParserTest` / `ProcessParserTest` — **현재 없다**. 엑셀 양식 정의를 통합하기 전에 업로드→다운로드 왕복 테스트를 만들어 양식 호환을 고정한다. `ProcessParser`의 T/U열 예외를 반드시 포함한다 - `ReMemoControllerTest` — RE 메모 CRUD - 프론트: `codes` 모듈 테스트, 분해된 컴포넌트별 테스트 Phase 6에서 갱신이 필요한 기존 테스트: - `StageControllerTest:90,92` — "13은 400" 단언이 뒤집힌다 - `DashboardControllerTest:57,96,98` — 11/12 기준 단언 - `OrgOverview.test.tsx:254,466` — "업무단계 12개" ## 10. 리스크 | 리스크 | 대응 | |---|---| | 운영 DB에 시드와 다른 값이 남아 있음 | Phase 1 정합성 점검, 고아 값은 `active=false`로 보존 | | 엑셀 양식 통합 시 기존 파일 호환 깨짐 | 왕복 테스트를 먼저 작성, T/U열 예외 포함 | | `STAGE_GROUP`을 필터와 함께 지워 칸반이 깨짐 | 필터 UI만 제거, 색·카드 모양 용도는 유지 (§8) | | 코드 조회 실패 시 빈 선택지로 저장 | 조회 실패 시 화면을 그리지 않고 오류 표시 | | Phase 4 분해 중 회귀 | 각 Phase 완료 조건 = 기존 테스트 전량 통과 | ## 11. 미결 항목 ### 2026-07-30 회신으로 확정된 것 (모두 현행 유지 — 코드 변경 없음) - 12(권리처리필요 자동체크) — 「지금처럼 자동으로 두기」 - RE 메모의 `resolved` 플래그 (§8) — 「지금처럼 「해결」 버튼 두기」 - 기관 엑셀의 공공누리 유형 값 — 「기관 자료는 임의 변경 불가, 양식 그대로 업로드」. 현행이 이미 무검증 원문 저장이므로 변경 없음 - 저희 입력칸의 공공누리 유형 — 「0~4유형에서 선택만 가능하게」. 현행이 이미 코드표 기반 select/radio라 자유입력 불가. 변경 없음 ### 남은 것 - 요구사항 미응답 10건, 결정 대기 3건 — §4 제외 목록 - 기관 100개 명부 엑셀 — 수령 대기. 양식은 기존 `신유형 신청목록` 시트 그대로 사용 가능하고 `POST /api/seed` + `SeedUpload.tsx`로 요청자가 직접 올릴 수 있음을 회신함 - 주간·월간 보고 양식 — 수령 대기 (시점 확인 요청 중) - **2026-07-30 재질문 7건** — `ITN-HUB 요구사항 확인요청_재질문_260730.pptx` 회신 대기. 이 중 다음 3건은 답이 와야 코드를 손댈 수 있다: - 기관 연번(`org_no`) 체계 — 100곳 명부에서 재부여 시 기존 자료 마이그레이션 필요 - 코드표에 없는 값(`4`·`8`)의 통계 집계 방식 — 표시·집계 계층에서만 처리 예정 - 권리확인 화면의 「기존 공공누리 유형」 편집 허용 여부 — 현재 권리처리 화면과 불일치