fix: 운영 DB에 실제로 저장된 공공누리 값을 코드로 등록
배포 전 정합성 점검을 실제 DB에 돌려보니 코드테이블에 없는 값이 1,926건 있었다. review_item.kogl_type = 유형 확인 필요 1,858건 review_item.kogl_type = 제4유형 68건 둘 다 기관 조사표에서 온 값이라 prior(기존 부착 유형) 자리에만 넣고, 변호사가 고르는 판정값(review/process)에는 넣지 않는다. surveyOnly 속성으로 구분하고 그 구분이 새는지를 테스트로 막는다. 등록하지 않았다면 Phase 2에서 이 1,926건이 상세 화면에 선택 안 됨으로 보였을 것이다. Co-Authored-By: Claude Opus 5 (1M context)
@60fd607ef427509323ff5e819b1dd207fdfd87ef
+++ src/main/resources/db/migration/V14__common_code_orphans.sql
... | ... | @@ -0,0 +1,19 @@ |
| 1 | +-- V13 시드를 넣은 뒤 운영 DB에 이미 저장된 값을 훑어보니, 코드테이블에 없는 값이 있었다. | |
| 2 | +-- 화면이 코드테이블만 보게 되는 Phase 2 전에 이 값들을 코드로 등록해 둔다. | |
| 3 | +-- 등록하지 않으면 아래 1,926건이 상세 화면에서 "선택 안 됨"으로 보인다. | |
| 4 | +-- | |
| 5 | +-- 조사 시점(2026-07-28) 운영 DB 실측: | |
| 6 | +-- review_item.kogl_type = '유형 확인 필요' 1,858건 | |
| 7 | +-- review_item.kogl_type = '제4유형' 68건 | |
| 8 | +-- | |
| 9 | +-- 둘 다 기관이 제출한 조사표에서 온 값이라 prior(기존 부착 유형) 자리에만 넣는다. | |
| 10 | +-- 변호사가 고르는 판정값(review/process)에는 넣지 않는다. | |
| 11 | +-- | |
| 12 | +-- '제4유형'은 '4유형'과 같은 뜻의 다른 표기다. 값을 통일하는 것은 데이터 변경이라 | |
| 13 | +-- 여기서 하지 않는다 - 표기 통일 여부는 별도로 확인받는다. | |
| 14 | + | |
| 15 | +insert into code (group_id, code, label, sort_order, active, attrs) values | |
| 16 | + ('KOGL_TYPE','유형 확인 필요','유형 확인 필요', 8, true, | |
| 17 | + '{"scopes":["prior"],"firstRow":[],"surveyOnly":true}'::jsonb), | |
| 18 | + ('KOGL_TYPE','제4유형', '제4유형', 9, true, | |
| 19 | + '{"scopes":["prior"],"firstRow":[],"surveyOnly":true,"sameAs":"4유형"}'::jsonb); |
--- src/test/java/kr/itn/itnhub/code/CodeControllerTest.java
+++ src/test/java/kr/itn/itnhub/code/CodeControllerTest.java
... | ... | @@ -31,7 +31,8 @@ |
| 31 | 31 |
.andExpect(jsonPath("$.STAGE[12].code").value("13"))
|
| 32 | 32 |
.andExpect(jsonPath("$.STAGE[12].label").value("보고서 제출 완료"))
|
| 33 | 33 |
.andExpect(jsonPath("$.STAGE[12].attrs.progress").value("done"))
|
| 34 |
- .andExpect(jsonPath("$.KOGL_TYPE.length()").value(7))
|
|
| 34 |
+ // 0~4유형 + 개방불가 + 보류 + 조사표에서 온 2개(유형 확인 필요, 제4유형) |
|
| 35 |
+ .andExpect(jsonPath("$.KOGL_TYPE.length()").value(9))
|
|
| 35 | 36 |
.andExpect(jsonPath("$.CONTACT_CATEGORY[0].code").value("APPLICANT"))
|
| 36 | 37 |
.andExpect(jsonPath("$.CONTACT_CATEGORY[0].label").value("신청기관"));
|
| 37 | 38 |
} |
--- src/test/java/kr/itn/itnhub/code/CodeSeedTest.java
+++ src/test/java/kr/itn/itnhub/code/CodeSeedTest.java
... | ... | @@ -74,9 +74,29 @@ |
| 74 | 74 |
@Test |
| 75 | 75 |
void 공공누리_유형은_사용처별로_다르게_노출된다() {
|
| 76 | 76 |
// 세 화면의 목록이 7개/5개/6개로 달랐던 이유는 쓰이는 자리가 달라서다. |
| 77 |
- assertThat(koglScope("review")).hasSize(7);
|
|
| 77 |
+ assertThat(koglScope("review")).hasSize(7).doesNotContain("유형 확인 필요");
|
|
| 78 | 78 |
assertThat(koglScope("process")).hasSize(6).doesNotContain("보류");
|
| 79 |
- assertThat(koglScope("prior")).containsExactly("0유형", "1유형", "2유형", "3유형", "4유형");
|
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 81 |
+ @Test |
|
| 82 |
+ void 기존_부착유형에는_조사표에서_온_값도_들어간다() {
|
|
| 83 |
+ // 운영 DB 실측(2026-07-28): kogl_type에 '유형 확인 필요' 1,858건, '제4유형' 68건이 |
|
| 84 |
+ // 저장돼 있었다. 코드로 등록해 두지 않으면 상세 화면에서 선택 안 됨으로 보인다. |
|
| 85 |
+ assertThat(koglScope("prior")).containsExactly(
|
|
| 86 |
+ "0유형", "1유형", "2유형", "3유형", "4유형", "유형 확인 필요", "제4유형"); |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 89 |
+ @Test |
|
| 90 |
+ void 조사표에서_온_값은_변호사_판정_선택지가_아니다() {
|
|
| 91 |
+ Integer leaked = jdbc.queryForObject( |
|
| 92 |
+ "select count(*) from code c " |
|
| 93 |
+ + "where c.group_id = 'KOGL_TYPE' " |
|
| 94 |
+ + " and (c.attrs->>'surveyOnly')::boolean is true " |
|
| 95 |
+ + " and exists (select 1 from jsonb_array_elements_text(c.attrs->'scopes') s(v) " |
|
| 96 |
+ + " where s.v in ('review', 'process'))",
|
|
| 97 |
+ Integer.class); |
|
| 98 |
+ |
|
| 99 |
+ assertThat(leaked).isZero(); |
|
| 80 | 100 |
} |
| 81 | 101 |
|
| 82 | 102 |
private List<String> koglScope(String scope) {
|
--- src/test/java/kr/itn/itnhub/code/CodeServiceTest.java
+++ src/test/java/kr/itn/itnhub/code/CodeServiceTest.java
... | ... | @@ -58,9 +58,12 @@ |
| 58 | 58 |
assertThat(service.scoped(Codes.KOGL_TYPE, Codes.SCOPE_PROCESS)) |
| 59 | 59 |
.hasSize(6) |
| 60 | 60 |
.noneMatch(c -> c.code().equals("보류"));
|
| 61 |
+ // prior에는 기관 조사표에서 온 값('유형 확인 필요', '제4유형')까지 들어간다.
|
|
| 62 |
+ // 운영 DB에 실제로 저장돼 있는 값이라 등록해 두지 않으면 화면에서 선택 안 됨으로 보인다. |
|
| 61 | 63 |
assertThat(service.scoped(Codes.KOGL_TYPE, Codes.SCOPE_PRIOR)) |
| 62 | 64 |
.extracting(Code::code) |
| 63 |
- .containsExactly("0유형", "1유형", "2유형", "3유형", "4유형");
|
|
| 65 |
+ .containsExactly("0유형", "1유형", "2유형", "3유형", "4유형",
|
|
| 66 |
+ "유형 확인 필요", "제4유형"); |
|
| 64 | 67 |
} |
| 65 | 68 |
|
| 66 | 69 |
@Test |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?