Skip to content

feat: add patch quiz progress#47

Merged
sezeme merged 1 commit intodevelopfrom
feat/32-put-quiz-results
Feb 9, 2026
Merged

feat: add patch quiz progress#47
sezeme merged 1 commit intodevelopfrom
feat/32-put-quiz-results

Conversation

@sezeme
Copy link
Copy Markdown
Collaborator

@sezeme sezeme commented Feb 9, 2026

Close #32

@sezeme sezeme merged commit dff7ef0 into develop Feb 9, 2026
@sezeme sezeme deleted the feat/32-put-quiz-results branch February 9, 2026 15:15
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @sezeme, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a feature to synchronize quiz progress, allowing users to persist their progress as they complete quizzes within a scene. It includes a new API endpoint, data transfer object, error handling, and service layer implementation to support this functionality. Additionally, it corrects the delimiter used for multiple choice answers.

Highlights

  • Quiz Progress Synchronization: Introduces a new PATCH endpoint /progress in QuizController to synchronize quiz progress for a given scene. This allows the client to update the user's progress, including the last quiz ID, total questions, success/failure counts, solve time, and completion status.
  • Data Transfer Object (DTO): Adds a SyncProgressRequest record in QuizDto to encapsulate the data required for synchronizing quiz progress. This record includes fields for lastQuizId, totalQuestions, success, failure, solveTime, and isComplete.
  • Error Handling: Introduces a new QUIZ_PROGRESS_NOT_FOUND error code in CommonErrorCode to handle cases where the quiz progress is not found for a user and scene.
  • Service Layer Implementation: Implements the syncProgress method in QuizService to update the QuizUserProgress entity in the database. This method retrieves the existing progress, updates it with the data from the SyncProgressRequest, and saves the updated entity.
  • Answer Formatting: Changes the delimiter for multiple choice answers from | to , in initial_quiz_data.json and updates the answer processing logic in QuizGradingService to use the new delimiter.
Changelog
  • src/main/java/com/blaybus/backend/controller/QuizController.java
    • Added a new PATCH endpoint /progress to synchronize quiz progress.
  • src/main/java/com/blaybus/backend/dto/QuizDto.java
    • Added a SyncProgressRequest record to encapsulate quiz progress data.
  • src/main/java/com/blaybus/backend/exception/CommonErrorCode.java
    • Added a QUIZ_PROGRESS_NOT_FOUND error code.
  • src/main/java/com/blaybus/backend/service/QuizGradingService.java
    • Modified answer processing logic to use , as the delimiter for multiple choice answers and return the correct answer in the GradeResponse.
  • src/main/java/com/blaybus/backend/service/QuizService.java
    • Implemented the syncProgress method to update quiz progress in the database.
  • src/main/resources/data/initial_quiz_data.json
    • Changed the delimiter for multiple choice answers from | to ,.
  • src/test/java/com/blaybus/backend/service/QuizServiceTest.java
    • Added unit tests for the QuizService, specifically for the syncProgress method, covering both successful synchronization and the case where progress is not found.
Activity
  • Implements the synchronization of quiz progress.
  • Adds necessary DTOs and error handling.
  • Updates service layer to persist quiz progress.
  • Fixes answer delimiter in initial data.
  • Adds unit tests for the new functionality.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

퀴즈 진행 상황을 동기화하는 기능을 추가한 PR이네요. 전반적으로 기능 구현에 필요한 컨트롤러, DTO, 서비스 로직 및 테스트 코드까지 잘 구성되어 있습니다. 리뷰 과정에서 몇 가지 개선점을 발견했습니다. 주로 DTO의 데이터 유효성 검증, 서비스 레이어의 엔티티 업데이트 전략, 그리고 컨트롤러의 중복 코드에 대한 내용입니다. 아래에 자세한 피드백을 남겼으니 확인 부탁드립니다.

Comment on lines +16 to 23
public record SyncProgressRequest(
Long lastQuizId,
Integer totalQuestions,
Integer success,
Integer failure,
Integer solveTime,
boolean isComplete) {
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

SyncProgressRequest DTO의 필드에 대한 유효성 검증이 누락되었습니다. 컨트롤러에서 @Valid 어노테이션을 사용하고 있으므로, DTO 필드에 제약 조건을 추가하여 예상치 못한 값(예: 음수)이 서비스 레이어로 전달되는 것을 막아야 합니다. 이는 데이터 정합성을 보장하고 잠재적인 버그를 예방하는 데 중요합니다. null 값을 허용하지 않으려면 @NotNull도 함께 사용하는 것이 좋습니다.

Suggested change
public record SyncProgressRequest(
Long lastQuizId,
Integer totalQuestions,
Integer success,
Integer failure,
Integer solveTime,
boolean isComplete) {
}
public record SyncProgressRequest(
Long lastQuizId,
@jakarta.validation.constraints.PositiveOrZero Integer totalQuestions,
@jakarta.validation.constraints.PositiveOrZero Integer success,
@jakarta.validation.constraints.PositiveOrZero Integer failure,
@jakarta.validation.constraints.PositiveOrZero Integer solveTime,
boolean isComplete) {
}
References
  1. 코드 변경 시 발생할 수 있는 보안 위협(XSS, SQL Injection, IDOR, 민감 정보 노출 등)을 반드시 검토하십시오. 입력 값 검증 및 인가 로직의 누락 여부를 확인하십시오. (link)
  2. 이 프로젝트는 CAP 이론 중 Consistency인 데이터 정합성을 우선시합니다. (link)

Comment on lines +57 to +74
public void syncProgress(Long sceneId, QuizDto.SyncProgressRequest request, User user) {
QuizUserProgress progress = progressRepository.findByUserIdAndSceneId(user.getId(), sceneId)
.orElseThrow(() -> new BusinessException(CommonErrorCode.QUIZ_PROGRESS_NOT_FOUND));

QuizUserProgress updated = QuizUserProgress.builder()
.id(progress.getId())
.user(progress.getUser())
.scene(progress.getScene())
.lastQuizId(request.lastQuizId())
.totalQuestions(request.totalQuestions())
.success(request.success())
.failure(request.failure())
.solveTime(request.solveTime())
.isComplete(request.isComplete())
.build();

progressRepository.save(updated);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

JPA 엔티티를 업데이트하는 현재 방식은 비효율적이며, 더 나은 대안이 있습니다.

현재 방식의 문제점 (Cons):

  • builder()를 사용해 새 인스턴스를 생성하고 save()를 호출하는 것은 JPA의 merge 동작을 유발합니다.
  • merge는 영속성 컨텍스트에 해당 엔티티가 없는 경우 데이터베이스에서 다시 조회하는 추가적인 SELECT 쿼리를 발생시킬 수 있어 비효율적입니다.
  • 코드를 읽는 개발자에게 새로운 엔티티를 생성하는 것처럼 보여 혼란을 줄 수 있습니다.

개선 방안 (Pros):
JPA의 변경 감지(dirty checking) 기능을 활용하는 것이 좋습니다. @Transactional 메소드 내에서 영속 상태의 엔티티를 수정한 후 명시적으로 save()를 호출하지 않아도 트랜잭션이 커밋될 때 변경 사항이 자동으로 데이터베이스에 반영됩니다. 이를 통해 성능을 개선하고 코드를 더 명확하게 만들 수 있습니다.

대안 1: 엔티티에 업데이트 메소드 추가 (권장)
QuizUserProgress.java에 업데이트 로직을 캡슐화하는 메소드를 추가합니다.

// QuizUserProgress.java
public void syncProgress(QuizDto.SyncProgressRequest request) {
    this.lastQuizId = request.lastQuizId();
    this.totalQuestions = request.totalQuestions();
    this.success = request.success();
    this.failure = request.failure();
    this.solveTime = request.solveTime();
    this.isComplete = request.isComplete();
}

그 후 QuizServicesyncProgress 메소드를 다음과 같이 수정합니다.

// QuizService.java
@Transactional
public void syncProgress(Long sceneId, QuizDto.SyncProgressRequest request, User user) {
    QuizUserProgress progress = progressRepository.findByUserIdAndSceneId(user.getId(), sceneId)
            .orElseThrow(() -> new BusinessException(CommonErrorCode.QUIZ_PROGRESS_NOT_FOUND));

    progress.syncProgress(request);
    // progressRepository.save() 호출이 더 이상 필요하지 않습니다.
}

대안 2: Setter 사용
엔티티에 Setter를 열어두고 서비스 레이어에서 직접 값을 변경할 수도 있지만, 도메인 객체의 캡슐화를 해칠 수 있어 첫 번째 방안을 더 권장합니다.

References
  1. 단순한 코드 수정 요청을 넘어, 개발자의 성장을 돕는 통찰을 제공하십시오. 코드 패턴을 분석하여 유지보수성 및 성능 측면에서의 잘한 점(Pros)과 개선할 점(Cons)을 명확히 구분해 설명하십시오. (link)
  2. 단일 해법만 제시하지 말고, 트레이드오프(Trade-off)를 고려한 여러 대안을 제안하십시오. 각 대안의 장단점(성능, 가독성, 유지보수성 등)을 비교 분석하여 설명하십시오. (link)

Comment on lines +66 to +67
User user = userRepository.findByUsername(userDetails.getUsername())
.orElseThrow(() -> new BusinessException(CommonErrorCode.USER_NOT_FOUND));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

컨트롤러 내 여러 메소드에서 사용자 정보를 조회하는 로직이 중복되고 있습니다.

User user = userRepository.findByUsername(userDetails.getUsername())
        .orElseThrow(() -> new BusinessException(CommonErrorCode.USER_NOT_FOUND));

이러한 중복은 코드 유지보수성을 저하시킬 수 있습니다.

개선 방안:
HandlerMethodArgumentResolver를 구현하여 사용자 조회 로직을 중앙에서 관리하고, 컨트롤러 메소드에서는 @AuthUser User user 와 같이 어노테이션을 통해 바로 User 객체를 주입받는 방식을 고려해볼 수 있습니다. 이렇게 하면 코드 중복을 제거하고 컨트롤러를 더 깔끔하게 유지할 수 있습니다. 이는 장기적인 관점에서 프로젝트의 유지보수성을 높이는 데 도움이 될 것입니다.

References
  1. 단순한 코드 수정 요청을 넘어, 개발자의 성장을 돕는 통찰을 제공하십시오. 코드 패턴을 분석하여 유지보수성 및 성능 측면에서의 잘한 점(Pros)과 개선할 점(Cons)을 명확히 구분해 설명하십시오. 장기적으로 나아가야 할 기술적 방향성을 제시하여 자기계발에 도움을 주십시오. (link)

sezeme added a commit that referenced this pull request Feb 9, 2026
* Feat/add mock data (#44)

* refactor(security): update permitted endpoints and remove ChatController

- Updated SecurityConfig to restrict access by removing the chat endpoint from the permitted list.
- Deleted ChatController as it is no longer needed in the application.

* refactor(quiz): rename quiz class and delete quiz choice

* feat: add & fix mock data

* feat: rebase 마무리

* feat(data loader): add scene rank data

* fix: accept review

---------

Co-authored-by: DaehyeonKim <qwertypotter@gachon.ac.kr>

* Feat/31 get quiz list (#46)

* refactor(security): update permitted endpoints and remove ChatController

- Updated SecurityConfig to restrict access by removing the chat endpoint from the permitted list.
- Deleted ChatController as it is no longer needed in the application.

* feat(quiz): get quiz list

* fix: order by quiz id

* fix(quiz): 정답을 프론트로 내려주지 않도록 수정, 객관식 채점 시 정답
올바르게 파싱하도록 수정

---------

Co-authored-by: DaehyeonKim <qwertypotter@gachon.ac.kr>

* fix: 정답 리턴값 수정 (#47)

---------

Co-authored-by: DaehyeonKim <qwertypotter@gachon.ac.kr>
joonamin added a commit that referenced this pull request Feb 10, 2026
* Feat/add mock data (#44)

* refactor(security): update permitted endpoints and remove ChatController

- Updated SecurityConfig to restrict access by removing the chat endpoint from the permitted list.
- Deleted ChatController as it is no longer needed in the application.

* refactor(quiz): rename quiz class and delete quiz choice

* feat: add & fix mock data

* feat: rebase 마무리

* feat(data loader): add scene rank data

* fix: accept review

---------

Co-authored-by: DaehyeonKim <qwertypotter@gachon.ac.kr>

* Feat/31 get quiz list (#46)

* refactor(security): update permitted endpoints and remove ChatController

- Updated SecurityConfig to restrict access by removing the chat endpoint from the permitted list.
- Deleted ChatController as it is no longer needed in the application.

* feat(quiz): get quiz list

* fix: order by quiz id

* fix(quiz): 정답을 프론트로 내려주지 않도록 수정, 객관식 채점 시 정답
올바르게 파싱하도록 수정

---------

Co-authored-by: DaehyeonKim <qwertypotter@gachon.ac.kr>

* fix: 정답 리턴값 수정 (#47)

* fix(quiz): prevent totalQuestions from incrementing during grading

* fix: ci error 해결

---------

Co-authored-by: Chewon Kim <stellaa223@gmail.com>
Co-authored-by: DaehyeonKim <qwertypotter@gachon.ac.kr>
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.

feat: put quiz results

1 participant