Skip to content

fix: 주관식 답안 정규화 처리 개선#294

Merged
xunxxoie merged 2 commits intodevfrom
fix/293-update-answer-return-logic
Jan 12, 2026
Merged

fix: 주관식 답안 정규화 처리 개선#294
xunxxoie merged 2 commits intodevfrom
fix/293-update-answer-return-logic

Conversation

@xunxxoie
Copy link
Member

@xunxxoie xunxxoie commented Jan 12, 2026

📋 이슈 번호

🛠 구현 사항

🤔 추가 고려 사항

Summary by CodeRabbit

릴리스 노트

  • 개선사항

    • 주관식 문제의 정답 표시 형식을 개선하여 복수의 정답 표현을 명확하게 표시
  • 데이터 정규화

    • 전체 데이터베이스 키워드 및 용어를 소문자로 통일
    • 답안 선택지의 띄어쓰기 및 구분 형식을 표준화
    • 용어 정합성을 개선하여 일관된 데이터 표현 제공

✏️ Tip: You can customize this high-level summary in your review settings.

@xunxxoie xunxxoie self-assigned this Jan 12, 2026
@xunxxoie xunxxoie linked an issue Jan 12, 2026 that may be closed by this pull request
@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Walkthrough

주관식 문제의 정답 처리를 개선하기 위해 저장소 계층에서 AnswerResponse DTO를 Answer 엔티티로 변경하고, AnswerResponseList<String> contents 필드로 업데이트하여 쉼표로 구분된 정답을 배열 형태로 반환하도록 수정했습니다. SQL 시드 데이터의 정답 내용도 정규화했습니다.

Changes

코호트 / 파일(들) 변경 요약
Answer DTO 구조 변경
src/main/java/gravit/code/answer/dto/response/AnswerResponse.java
content: Stringcontents: List<String> 필드 변경; 쉼표로 구분된 Answer 엔티티 내용을 배열로 분할하는 from(Answer) 팩토리 메서드 추가
저장소 메서드 반환 타입 변경
src/main/java/gravit/code/answer/repository/AnswerRepository.java
findByProblemId() 메서드 반환 타입 Optional<AnswerResponse>Optional<Answer>로 변경; 커스텀 @Query 제거
서비스 계층 타입 변경
src/main/java/gravit/code/admin/service/AdminProblemService.java, src/main/java/gravit/code/problem/service/ProblemQueryService.java
AnswerResponse 대신 Answer 엔티티 사용; 해당 import 업데이트
응답 DTO 팩토리 메서드 업데이트
src/main/java/gravit/code/problem/dto/response/ProblemResponse.java
createSubjectiveProblem(ProblemDetail, Answer), createSubjectiveProblemForAdmin(Problem, Answer) 메서드 시그니처 변경; 내부적으로 AnswerResponse.from(answer) 사용하여 변환
SQL 데이터 정규화
src/main/resources/sql/problem/database/unit*.sql (13개 파일)
정답 내용의 공백 제거, 키워드 소문자 통일, 쉼표 구분 형식 정규화
테스트 코드 업데이트
src/test/java/gravit/code/learning/repository/OptionJpaRepositoryTest.java
findByProblemId() 호출을 findAnswerResponseByProblemId() 호출로 변경

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

🧹 Refactor

Suggested reviewers

  • sukangpunch

Poem

🐰 주관식 정답을 배열로 쪼개니,
정규화된 답변이 반짝반짝,
엔티티에서 DTO로 변신하고,
쉼표 공백은 정갈하게 치우고,
더 깔끔한 정답 처리의 완성! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경사항의 핵심을 명확하게 반영하고 있습니다: 주관식 답안의 정규화 처리 개선이라는 목표와 일치합니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 이슈 #293의 요구사항을 충족합니다: (1) 답안 저장소에서 AnswerResponse 대신 Answer 반환 [#293], (2) AnswerResponse의 content 필드를 List으로 변경 [#293], (3) Answer.content를 쉼표로 분리하여 배열로 변환 [#293], (4) SQL 데이터 정규화 작업 [#293].
Out of Scope Changes check ✅ Passed 모든 변경사항이 이슈 #293의 범위 내에 있습니다. SQL 데이터 정규화(공백 제거, 소문자화)는 주관식 답안 처리 개선을 위한 필수 데이터 정제 작업으로 범위 내입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

Unit Test Results

0 tests   0 ✔️  0s ⏱️
0 suites  0 💤
0 files    0

Results for commit f4e88c2.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/test/java/gravit/code/learning/repository/OptionJpaRepositoryTest.java (1)

1-116: 전체 테스트 파일이 주석 처리되어 있으며, 테스트 중인 메서드들이 실제 저장소에 존재하지 않습니다

이 테스트 파일이 주석 처리되어 있을 뿐 아니라, 호출하는 메서드들이 OptionRepository에 없습니다:

  • findAnswerResponseByProblemId() - 존재하지 않음
  • findAllByProblemIdInIds() - 존재하지 않음

현재 OptionRepository에는 findByProblemId(long problemId)만 있습니다. 주석 처리된 코드는 유지보수 부담이 되므로 다음 중 하나를 권장합니다:

  1. 파일 삭제 (테스트가 더 이상 필요 없는 경우)
  2. 현재 API에 맞게 테스트 수정 및 활성화
  3. 임시로 비활성화해야 한다면 @Disabled 어노테이션 사용
🤖 Fix all issues with AI agents
In @src/main/java/gravit/code/answer/dto/response/AnswerResponse.java:
- Around line 23-30: AnswerResponse.from can NPE when answer.getContent() is
null; update the method to defensively handle null by using a safe fallback
(e.g., treat null as an empty string or directly produce an empty list) before
calling split(), for example replace
Arrays.stream(answer.getContent().split(",")) with
Arrays.stream(Optional.ofNullable(answer.getContent()).orElse("").split(",")) or
branch to Collections.emptyList() when getContent() == null so the mapped list
and the call to getExplanation() still produce a valid AnswerResponse.

In @src/main/resources/sql/problem/database/unit05_외래키와제약조건.sql:
- Around line 102-103: The VALUES tuple currently contains a typographical error
in the second element of the first entry: change the string 'set null,nULL' to
'set null,null' so the pair is consistently lowercased; update the literal in
the VALUES list (the tuple starting with (269, 937, ...)) to use 'set null,null'
to match other entries and maintain consistency.

In @src/main/resources/sql/problem/database/unit09_조인.sql:
- Around line 149-150: The inserted answer for problem 1031 uses a non-existent
column d.department_id; update the VALUES row so the WHERE clause condition
matches the actual schema: replace d.department_id is null with s.department_id
is null if the intent is to find students without a department, or remove the
d.department_id is null alternative entirely; ensure the stored answer
corresponds to the query SELECT * FROM students s LEFT JOIN departments d ON
s.department_id = d.id WHERE ___; and reference the correct alias/column names
(s.department_id or d.id) when editing the VALUES entry containing
d.department_id is null.

In @src/main/resources/sql/problem/database/unit12_정규화.sql:
- Around line 149-150: Update the lowercase "2nf" token in the INSERT VALUES
tuple (the string '제2정규형,2nf,2정규형' in the VALUES(...) list) to use the
consistent uppercase form "2NF" so it matches other entries like '1NF' and
'3NF'; ensure the tuple becomes '제2정규형,2NF,2정규형' to maintain consistency across
the file.

In @src/main/resources/sql/problem/database/unit13_트랜잭션.sql:
- Around line 149-150: Fix the typographical error in the VALUES tuple where the
string "nonrepatable read" appears (the second record in the VALUES list);
change "nonrepatable read" to "nonrepeatable read" so the tuple reads
'non-repeatable read,반복 불가능한 읽기,nonrepeatable read' to correct the spelling in
that INSERT entry.

In @src/test/java/gravit/code/learning/repository/OptionJpaRepositoryTest.java:
- Line 92: In OptionJpaRepositoryTest the commented call uses a non-existent
repository method findAnswerResponseByProblemId; update the test to call the
actual repository method findByProblemId on OptionRepository (replace
findAnswerResponseByProblemId with findByProblemId) so the test compiles and
exercises the correct repository behavior.
🧹 Nitpick comments (2)
src/main/resources/sql/problem/database/unit01_데이터모델링.sql (1)

53-54: 대소문자 정규화 일관성 확인 필요

EntityInstance가 대문자로 시작하는 반면, 다른 파일들에서는 영문 키워드가 소문자로 정규화되어 있습니다 (예: cardinality, conceptual modeling).

대소문자 구분 없는 답안 검증을 위해 일관성 있게 소문자로 변경하는 것이 좋을 수 있습니다:

♻️ 선택적 수정 제안
-VALUES (243, 847, '엔티티,Entity,개체', ...),
-       (244, 850, '인스턴스,Instance', ...);
+VALUES (243, 847, '엔티티,entity,개체', ...),
+       (244, 850, '인스턴스,instance', ...);
src/main/java/gravit/code/answer/dto/response/AnswerResponse.java (1)

11-15: Schema 예시를 List 형태로 업데이트 권장

contents 필드가 List<String>으로 변경되었으므로 Swagger 문서의 예시도 배열 형태로 업데이트하는 것이 좋습니다.

📝 예시 업데이트 제안
         @Schema(
                 description = "정답 내용",
-                example = "2"
+                example = "[\"A\", \"B\", \"C\"]"
         )
         List<String> contents,
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e08a55 and f4e88c2.

📒 Files selected for processing (20)
  • src/main/java/gravit/code/admin/service/AdminProblemService.java
  • src/main/java/gravit/code/answer/dto/response/AnswerResponse.java
  • src/main/java/gravit/code/answer/repository/AnswerRepository.java
  • src/main/java/gravit/code/problem/dto/response/ProblemResponse.java
  • src/main/java/gravit/code/problem/service/ProblemQueryService.java
  • src/main/resources/sql/problem/database/unit01_데이터모델링.sql
  • src/main/resources/sql/problem/database/unit02_식별관계와비식별관계.sql
  • src/main/resources/sql/problem/database/unit03_관계형모델.sql
  • src/main/resources/sql/problem/database/unit04_키.sql
  • src/main/resources/sql/problem/database/unit05_외래키와제약조건.sql
  • src/main/resources/sql/problem/database/unit06_DDL.sql
  • src/main/resources/sql/problem/database/unit07_DML.sql
  • src/main/resources/sql/problem/database/unit08_서브쿼리.sql
  • src/main/resources/sql/problem/database/unit09_조인.sql
  • src/main/resources/sql/problem/database/unit10_페이징.sql
  • src/main/resources/sql/problem/database/unit11_뷰.sql
  • src/main/resources/sql/problem/database/unit12_정규화.sql
  • src/main/resources/sql/problem/database/unit13_트랜잭션.sql
  • src/main/resources/sql/problem/database/unit14_인덱스.sql
  • src/test/java/gravit/code/learning/repository/OptionJpaRepositoryTest.java
🔇 Additional comments (28)
src/main/resources/sql/problem/database/unit08_서브쿼리.sql (3)

49-50: LGTM! 다양한 정답 변형을 쉼표로 구분하여 포함

한국어와 영어 변형을 모두 포함하여 정답 검증 로직이 개선되었습니다. 이 형식은 PR 목표에 따라 배열로 분리되어 각 정답을 독립적으로 처리할 수 있게 합니다.


100-100: LGTM! SQL 키워드를 소문자로 정규화

정답을 소문자(all)로 저장하여 대소문자 구분 없이 사용자 입력을 검증할 수 있습니다. 설명에서는 SQL 표준 표기법인 대문자(ALL 연산자)를 유지하여 문서화 목적에 적합합니다.


149-150: LGTM! 일관된 소문자 정규화 적용

asexists 키워드도 동일한 소문자 정규화 패턴을 따릅니다. 코드 레벨에서 strip 함수가 적용되므로 사용자가 공백을 포함하여 입력해도 올바르게 매칭됩니다.

src/main/resources/sql/problem/database/unit03_관계형모델.sql (3)

51-55: 대소문자 정규화 적용 확인

영문 용어들이 소문자로 일관되게 정규화되었습니다 (Relationrelation, Tabletable, Domaindomain). 쉼표 구분자 형식도 공백 없이 일관되게 유지되어 코드 레벨의 strip 처리와 호환됩니다.


102-104: NULL 표기 소문자 정규화 적용

NULLnull로 정규화되어 대소문자 무관 정답 검증이 가능해졌습니다. 한글 '널'도 함께 포함되어 있어 사용자 편의성이 향상되었습니다.

참고: option 테이블의 설명문(lines 75, 80 등)에서는 여전히 'NULL'을 사용하고 있으나, 설명문은 표시 목적이고 answer는 검증 목적이므로 현재 구조가 적절합니다.


151-153: 영문 용어 소문자 정규화 완료

Attributeattribute, Referentialreferential로 일관되게 정규화되었습니다. 전체 파일에서 동일한 패턴이 적용되어 정답 검증 로직과의 호환성이 확보되었습니다.

src/main/resources/sql/problem/database/unit14_인덱스.sql (3)

48-50: LGTM! 주관식 답안 정규화가 올바르게 적용되었습니다.

SQL 키워드 CREATE를 소문자로 변환하고, 쉼표로 구분된 답안에서 공백을 제거한 것이 PR 목적에 부합합니다. 이를 통해 배열로 분리 시 각 항목이 깔끔하게 처리됩니다.


98-100: LGTM! 정규화 패턴이 일관되게 적용되었습니다.

UNIQUEunique 소문자 변환과 '1,하나,한'의 공백 제거가 다른 답안들과 동일한 패턴으로 적용되었습니다.


148-150: LGTM! 내부 공백과 구분자 공백이 올바르게 처리되었습니다.

'풀 테이블 스캔', 'full table scan' 등 용어 내부의 공백은 유지하면서, 쉼표 뒤의 구분자 공백만 제거한 것이 정확합니다. SQL 키워드 DROP의 소문자 변환도 일관되게 적용되었습니다.

src/main/resources/sql/problem/database/unit10_페이징.sql (2)

48-49: LGTM! 주관식 답안 정규화 형식이 일관적입니다.

쉼표로 구분된 답안 변형들이 적절하게 구성되어 있습니다. order byorderby 두 가지 변형을 포함하여 사용자 입력 오류(띄어쓰기 누락)에 대응한 점이 좋습니다.


148-149: LGTM! 커서 기반 페이징 관련 답안 변형이 충분히 포함되어 있습니다.

'커서 기반 페이징', '커서', '키셋', '키셋 페이징', '커서 페이징' 등 다양한 표현을 허용하여 사용자 답변의 유연성을 높였습니다. PR 목표에 맞게 정규화된 형식으로 저장되어 있습니다.

src/main/resources/sql/problem/database/unit05_외래키와제약조건.sql (2)

53-54: 정규화 패턴 적용 확인됨.

쉼표 뒤 공백 제거 및 소문자 정규화가 올바르게 적용되었습니다. 배열 분리 후 개별 정답 비교에 적합한 형태입니다.


154-155: 정규화 패턴 적용 확인됨.

소문자 정규화 및 쉼표 구분자 적용이 일관되게 되어 있습니다.

src/main/resources/sql/problem/database/unit04_키.sql (2)

101-102: LGTM! 두 번째 답안 블록도 일관되게 정규화되었습니다.

대체키,alternate key대리키,surrogate key 형식으로 첫 번째 블록과 동일한 패턴을 유지하고 있습니다.


52-53: 답안 정규화 형식이 올바르게 적용되고 일관성 있게 유지되고 있습니다.

쉼표 뒤 공백 제거와 영문 소문자 변환이 unit04_키.sql의 모든 주관식 답안(lines 52-53, 101-102)에서 일관되게 적용되어 있으며, 다른 유닛 SQL 파일들(unit12_정규화, unit13_트랜잭션, unit14_인덱스 등)에서도 동일한 정규화 패턴이 유지되고 있습니다. 25개의 주관식 답안 모두가 정규화된 형식을 따르고 있어 배열 분리 시 일관된 요소 생성이 보장됩니다.

src/main/resources/sql/problem/database/unit07_DML.sql (1)

52-53: LGTM! 답안 정규화가 일관되게 적용되었습니다.

SQL 키워드들이 소문자로 정규화되어 대소문자 구분 없는 답안 검증이 가능합니다. 백엔드에서 쉼표로 분리 시 각 답안이 독립적으로 처리될 수 있도록 공백도 제거되었습니다.

Also applies to: 101-102, 150-151

src/main/resources/sql/problem/database/unit11_뷰.sql (1)

48-49: LGTM! 뷰 관련 답안 정규화가 올바르게 적용되었습니다.

키워드 소문자 변환(create, drop, or replace, with)과 쉼표 구분자 뒤 공백 제거가 일관되게 적용되었습니다. 다중 허용 답안(예: 가상 테이블,virtual table,논리 테이블)도 배열 분리 시 정상 처리됩니다.

Also applies to: 98-99, 148-149

src/main/resources/sql/problem/database/unit02_식별관계와비식별관계.sql (1)

52-53: LGTM! 식별/비식별 관계 답안 정규화가 적절합니다.

다양한 표기 변형을 포함하여 사용자 친화적입니다:

  • non-identifying, non identifying 모두 허용
  • fk, 외래키, 외래 키, foreign key 다중 허용

영문 키워드 소문자화와 쉼표 구분자 정규화가 일관되게 적용되었습니다.

Also applies to: 101-102, 151-152

src/main/resources/sql/problem/database/unit01_데이터모델링.sql (1)

103-104: LGTM! 정규화가 올바르게 적용되었습니다.

cardinality, m:n, conceptual modeling 등 영문 키워드가 소문자로 일관되게 정규화되었고, 다중 허용 답안들의 쉼표 구분자 뒤 공백이 제거되었습니다.

Also applies to: 153-155

src/main/resources/sql/problem/database/unit09_조인.sql (1)

49-50: LGTM! 조인 관련 답안 정규화가 적절합니다.

  • 공통열 변형 추가로 띄어쓰기 없는 표기도 허용
  • join, inner join, left, left outer, full, full outer 소문자 정규화 완료

Also applies to: 99-100

src/main/resources/sql/problem/database/unit13_트랜잭션.sql (1)

49-50: 정답 데이터 정규화 적용 확인

쉼표 구분자 주변 공백 제거 및 소문자 변환이 일관되게 적용되었습니다. AnswerResponse에서 split(",")으로 파싱할 때 strip() 처리가 적용된다면 공백 유무와 관계없이 동작하겠지만, 데이터 자체를 정규화하는 것이 더 안전한 접근입니다.

src/main/resources/sql/problem/database/unit06_DDL.sql (1)

52-53: LGTM!

DDL 키워드 정답이 소문자로 일관되게 정규화되었습니다. 다른 SQL 시드 파일들과 동일한 정규화 규칙이 적용되어 있습니다.

Also applies to: 101-102, 150-151

src/main/java/gravit/code/problem/service/ProblemQueryService.java (1)

39-43: LGTM! 도메인 엔티티 사용으로 개선되었습니다

AnswerResponse DTO 대신 Answer 도메인 엔티티를 사용하도록 변경되어 아키텍처가 개선되었습니다. Repository는 도메인 엔티티를 반환하고, DTO 변환은 ProblemResponse 팩토리 메서드에서 처리하는 구조가 적절합니다.

src/main/java/gravit/code/answer/repository/AnswerRepository.java (1)

8-12: LGTM! Repository 패턴이 올바르게 개선되었습니다

Repository에서 DTO 대신 도메인 엔티티(Answer)를 반환하도록 변경되었습니다. Spring Data JPA의 derived query method를 사용하여 커스텀 @Query가 불필요해졌고, 코드가 더 간결해졌습니다.

src/main/java/gravit/code/admin/service/AdminProblemService.java (1)

48-53: LGTM!

AnswerResponse 대신 Answer 엔티티를 직접 사용하고 ProblemResponse 팩토리 메서드에 전달하는 방식으로 깔끔하게 리팩토링되었습니다. 에러 처리도 적절히 유지되어 있습니다.

src/main/java/gravit/code/problem/dto/response/ProblemResponse.java (1)

66-79: LGTM!

Answer 엔티티를 받아서 내부에서 AnswerResponse.from(answer)로 변환하는 패턴이 두 팩토리 메서드에 일관되게 적용되었습니다. DTO 변환 책임이 적절히 캡슐화되어 있습니다.

Also applies to: 96-109

src/main/resources/sql/problem/database/unit12_정규화.sql (2)

49-50: 정답 데이터 정규화가 올바르게 적용되었습니다.

쉼표로 구분된 정답 문자열에서 공백을 제거하여 배열로 분리할 때 각 요소가 깨끗하게 추출되도록 개선되었습니다. PR 목표와 일치합니다.


99-100: 정답 데이터 정규화가 올바르게 적용되었습니다.

쉼표 구분자 뒤의 공백이 제거되어 정답 배열 변환 시 일관된 처리가 가능합니다.

@xunxxoie xunxxoie merged commit 6f8bf68 into dev Jan 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 주관식 답안 정규화 처리 개선

1 participant