Skip to content

Conversation

@ekgns33
Copy link
Contributor

@ekgns33 ekgns33 commented Jul 9, 2025

작업내역

  • 앱 내 피드백 저장 API 추가
  • 테스트코드 작성

Summary by CodeRabbit

  • New Features

    • Introduced a feedback submission endpoint, allowing users to provide ratings and comments.
    • Added validation for feedback input, including rating range and comment length.
    • Implemented storage and management of user feedback in the system.
  • Bug Fixes

    • None.
  • Tests

    • Added acceptance tests to verify successful feedback submission.
    • Updated test utilities and data setup to support feedback-related tests.
  • Chores

    • Added database migrations for feedback storage.
    • Updated cleanup utilities to handle feedback data in tests.

@coderabbitai
Copy link

coderabbitai bot commented Jul 9, 2025

Warning

Rate limit exceeded

@ekgns33 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b539a81 and 70b7ee8.

📒 Files selected for processing (3)
  • src/main/java/org/runimo/runimo/user/controller/request/FeedbackRequest.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/domain/Feedback.java (1 hunks)
  • src/test/java/org/runimo/runimo/user/api/FeedbackAcceptanceTest.java (1 hunks)

Walkthrough

A complete feedback feature was added, including REST API endpoints, domain model, service and repository layers, database migrations, and acceptance testing. The implementation includes DTOs, command objects, a JPA entity, repository, use case interface and implementation, controller, response codes, and supporting test data and cleanup utilities.

Changes

File(s) / Group Change Summary
.../controller/FeedbackController.java Added REST controller for feedback creation endpoint.
.../controller/request/FeedbackRequest.java Added DTO record for feedback requests with validation and conversion to command object.
.../domain/Feedback.java Added JPA entity for feedback, mapping to user_feedback table.
.../repository/FeedbackRepository.java Added Spring Data JPA repository interface for feedback entity.
.../service/dto/command/FeedbackCommand.java Added immutable command record for feedback creation.
.../service/usecases/FeedbackUsecase.java Added use case interface for feedback creation.
.../service/usecases/FeedbackUsecaseImpl.java Added service implementation for feedback creation, persisting to database.
.../enums/UserHttpResponseCode.java Added new enum constant for feedback creation success response.
.../db/migration/V20250710__add_feedback_table.sql Added migration script to create user_feedback table in production database.
.../h2/V20250710__add_feedback_table.sql Added migration script to create user_feedback table in H2 test database.
.../api/FeedbackAcceptanceTest.java Added acceptance test for feedback API endpoint.
.../CleanUpUtil.java Added user_feedback table to cleanup utility for test isolation.
.../sql/user_default_data.sql Added SQL script to insert default user and related data for tests.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FeedbackController
    participant FeedbackUsecase
    participant FeedbackRepository
    participant Database

    Client->>FeedbackController: POST /api/v1/feedback (FeedbackRequest, userId)
    FeedbackController->>FeedbackUsecase: createFeedback(FeedbackCommand)
    FeedbackUsecase->>FeedbackRepository: save(Feedback)
    FeedbackRepository->>Database: Insert Feedback row
    FeedbackRepository-->>FeedbackUsecase: Saved Feedback
    FeedbackUsecase-->>FeedbackController: (void)
    FeedbackController-->>Client: 201 Created (SuccessResponse)
Loading

Suggested labels

size/M

Suggested reviewers

  • jeeheaG

Poem

The feedback’s in, hooray, hooray!
A bunny hops to code today.
Tables built and tests now run,
A RESTful job that’s neatly done.
With every POST, a tale is told—
Of users’ thoughts, both brave and bold!
🐇✨

✨ 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 9

🔭 Outside diff range comments (1)
src/test/java/org/runimo/runimo/CleanUpUtil.java (1)

27-28: Reorder deletes to satisfy foreign-key constraints

The hard-coded USER_TABLES list already serves as a whitelist (so SQL-injection isn’t a concern), but deleting users before its child tables (e.g. user_token, oauth_account) will violate FK rules. Either move "users" to the end of the array or switch to a CASCADE truncate.

• File: src/test/java/org/runimo/runimo/CleanUpUtil.java
• Lines 10–20: update USER_TABLES order
• Lines 27–28: (optional) replace DELETE … ALTER TABLE with
jdbcTemplate.execute("TRUNCATE TABLE " + table + " RESTART IDENTITY CASCADE");

Suggested diff:

@@ private static final String[] USER_TABLES = {
-    "user_item",
-    "oauth_account",
-    "users",
-    "running_record",
-    "user_love_point",
-    "incubating_egg",
-    "runimo",
-    "user_token",
-    "user_feedback"
+    "user_item",
+    "oauth_account",
+    "user_token",
+    "running_record",
+    "user_love_point",
+    "incubating_egg",
+    "runimo",
+    "user_feedback",
+    "users"   // parent table last to avoid FK violations
 }
🧹 Nitpick comments (7)
src/test/resources/sql/user_default_data.sql (2)

7-8: Hard-coded test data may cause brittleness in tests.

Consider using more flexible approaches like test data builders or factories to generate test data, especially for values like public_id and img_url that might need to be unique across different test scenarios.


29-32: Remove unnecessary trailing empty lines.

Clean up the file by removing the trailing empty lines to improve code quality.

-

-

-
src/main/java/org/runimo/runimo/user/service/usecases/FeedbackUsecase.java (1)

7-7: Consider returning a result object instead of void.

While the current void return type works for fire-and-forget operations, consider returning a result object (e.g., FeedbackResult or CreatedFeedback) to provide better error handling and allow callers to access the created feedback's ID or other metadata.

-    void createFeedback(FeedbackCommand command);
+    FeedbackResult createFeedback(FeedbackCommand command);

This would align with more robust error handling patterns and provide better integration testing capabilities.

src/test/java/org/runimo/runimo/user/api/FeedbackAcceptanceTest.java (1)

65-69: Clean up trailing whitespace and empty lines.

Remove unnecessary empty lines at the end of the file for better code cleanliness.

        .statusCode(HttpStatus.CREATED.value());

-

}

-
src/main/java/org/runimo/runimo/user/controller/FeedbackController.java (2)

28-28: Consider refactoring the static toCommand method design.

Using a static method on the request DTO for conversion might not be the best design. Consider moving this logic to a dedicated mapper class or making it an instance method for better separation of concerns.

Alternative approach:

-feedbackUsecase.createFeedback(FeedbackRequest.toCommand(userId, request));
+feedbackUsecase.createFeedback(new FeedbackCommand(userId, request.rate(), request.feedback()));

Or create a dedicated mapper class:

@Component
public class FeedbackMapper {
    public FeedbackCommand toCommand(Long userId, FeedbackRequest request) {
        return new FeedbackCommand(userId, request.rate(), request.feedback());
    }
}

24-31: Consider adding input validation for userId.

While the request body is validated with @Valid, there's no explicit validation for the userId parameter. Consider adding validation to ensure the user ID is not null or invalid.

public ResponseEntity<SuccessResponse<Void>> createFeedback(
-   @UserId Long userId,
+   @UserId @NotNull Long userId,
    @Valid @RequestBody FeedbackRequest request
) {
src/main/java/org/runimo/runimo/user/controller/request/FeedbackRequest.java (1)

20-22: Consider improving the toCommand method design.

The static method approach for conversion might not be the best design pattern. Consider using a dedicated mapper class or making this an instance method for better maintainability and testability.

Alternative approach as an instance method:

-public static FeedbackCommand toCommand(Long userId, FeedbackRequest request) {
-    return new FeedbackCommand(userId, request.rate(), request.feedback());
-}
+public FeedbackCommand toCommand(Long userId) {
+    return new FeedbackCommand(userId, this.rate, this.feedback);
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23fea0e and cf2dbea.

📒 Files selected for processing (13)
  • src/main/java/org/runimo/runimo/user/controller/FeedbackController.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/controller/request/FeedbackRequest.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/domain/Feedback.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/repository/FeedbackRepository.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/dto/command/FeedbackCommand.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/usecases/FeedbackUsecase.java (1 hunks)
  • src/main/java/org/runimo/runimo/user/service/usecases/FeedbackUsecaseImpl.java (1 hunks)
  • src/main/resources/db/migration/V20250710__add_feedback_table.sql (1 hunks)
  • src/test/java/org/runimo/runimo/CleanUpUtil.java (1 hunks)
  • src/test/java/org/runimo/runimo/user/api/FeedbackAcceptanceTest.java (1 hunks)
  • src/test/resources/db/migration/h2/V20250710__add_feedback_table.sql (1 hunks)
  • src/test/resources/sql/user_default_data.sql (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/test/java/org/runimo/runimo/user/api/FeedbackAcceptanceTest.java (1)
src/test/java/org/runimo/runimo/TestConsts.java (1)
  • TestConsts (3-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and analyze
🔇 Additional comments (5)
src/test/resources/sql/user_default_data.sql (1)

2-2: Consider the security implications of disabling foreign key checks.

While disabling foreign key checks is common in test environments, ensure this script is never used in production environments where data integrity is critical.

src/test/java/org/runimo/runimo/CleanUpUtil.java (1)

18-20: LGTM! Proper addition of user_feedback table to cleanup routine.

The addition of the user_feedback table to the cleanup routine ensures test isolation and aligns with the new feedback feature.

src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java (1)

19-19: LGTM! Appropriate HTTP status code and message for feedback creation.

The addition of FEEDBACK_CREATED with HttpStatus.CREATED (201) is semantically correct for resource creation, and the Korean messages are consistent with the existing codebase patterns.

src/main/java/org/runimo/runimo/user/repository/FeedbackRepository.java (1)

6-8: LGTM! Clean and standard Spring Data JPA repository interface.

The interface follows Spring Data JPA conventions correctly, extending JpaRepository<Feedback, Long> to provide standard CRUD operations for the Feedback entity.

src/test/resources/db/migration/h2/V20250710__add_feedback_table.sql (1)

1-9: Add foreign key, rate check, and indexes to user_feedback (verify users table name)

The user_feedback table needs data-integrity and performance improvements:

  • Confirm the actual users table name and its schema—no CREATE TABLE user or users entry was found in src/main/resources/db/migration.
  • Add a rate constraint:
    ALTER TABLE user_feedback
      MODIFY COLUMN rate INT
      CHECK (rate BETWEEN 1 AND 5);
  • Add indexes for common lookups:
    CREATE INDEX idx_user_feedback_user_id   ON user_feedback(user_id);
    CREATE INDEX idx_user_feedback_created_at ON user_feedback(created_at);
  • Once you’ve confirmed the target users table, add the FK:
    ALTER TABLE user_feedback
      ADD CONSTRAINT fk_user_feedback_user_id
      FOREIGN KEY (user_id)
      REFERENCES <users_table_name>(id);

Comment on lines +3 to +7
public record FeedbackCommand(
Long userId,
Integer rate,
String content
) {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation annotations to ensure data integrity.

The record lacks validation constraints which could allow invalid data to propagate through the system. Consider adding validation annotations:

+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;

public record FeedbackCommand(
-    Long userId,
-    Integer rate,
-    String content
+    @NotNull Long userId,
+    @NotNull @Min(1) @Max(5) Integer rate,
+    @NotBlank @Size(max = 128) String content
) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public record FeedbackCommand(
Long userId,
Integer rate,
String content
) {
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
public record FeedbackCommand(
@NotNull Long userId,
@NotNull @Min(1) @Max(5) Integer rate,
@NotBlank @Size(max = 128) String content
) {
// other methods or logic, if any
}
🤖 Prompt for AI Agents
In src/main/java/org/runimo/runimo/user/service/dto/command/FeedbackCommand.java
around lines 3 to 7, the FeedbackCommand record lacks validation annotations.
Add appropriate validation annotations such as @NotNull for userId and rate,
@Min and @Max for rate to restrict its range, and @NotBlank for content to
ensure it is not empty. This will enforce data integrity and prevent invalid
data from being processed.

Comment on lines +16 to +25
@Override
@Transactional
public void createFeedback(FeedbackCommand command) {
Feedback feedback = Feedback.builder()
.userId(command.userId())
.rate(command.rate())
.content(command.content())
.build();
feedbackRepository.save(feedback);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation and error handling.

The method lacks validation and error handling which could lead to persistence of invalid data or unclear error messages:

@Override
@Transactional
public void createFeedback(FeedbackCommand command) {
+    // Validate command (or use @Valid parameter)
+    if (command.userId() == null || command.rate() == null || command.content() == null) {
+        throw new IllegalArgumentException("All feedback fields are required");
+    }
+    
+    if (command.rate() < 1 || command.rate() > 5) {
+        throw new IllegalArgumentException("Rate must be between 1 and 5");
+    }
+    
+    if (command.content().trim().isEmpty() || command.content().length() > 128) {
+        throw new IllegalArgumentException("Content must not be empty and max 128 characters");
+    }
+
    Feedback feedback = Feedback.builder()
        .userId(command.userId())
        .rate(command.rate())
-        .content(command.content())
+        .content(command.content().trim())
        .build();
        
+    try {
        feedbackRepository.save(feedback);
+    } catch (Exception e) {
+        throw new RuntimeException("Failed to save feedback", e);
+    }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Override
@Transactional
public void createFeedback(FeedbackCommand command) {
Feedback feedback = Feedback.builder()
.userId(command.userId())
.rate(command.rate())
.content(command.content())
.build();
feedbackRepository.save(feedback);
}
@Override
@Transactional
public void createFeedback(FeedbackCommand command) {
// Validate command (or use @Valid parameter)
if (command.userId() == null || command.rate() == null || command.content() == null) {
throw new IllegalArgumentException("All feedback fields are required");
}
if (command.rate() < 1 || command.rate() > 5) {
throw new IllegalArgumentException("Rate must be between 1 and 5");
}
if (command.content().trim().isEmpty() || command.content().length() > 128) {
throw new IllegalArgumentException("Content must not be empty and max 128 characters");
}
Feedback feedback = Feedback.builder()
.userId(command.userId())
.rate(command.rate())
.content(command.content().trim())
.build();
try {
feedbackRepository.save(feedback);
} catch (Exception e) {
throw new RuntimeException("Failed to save feedback", e);
}
}
🤖 Prompt for AI Agents
In
src/main/java/org/runimo/runimo/user/service/usecases/FeedbackUsecaseImpl.java
around lines 16 to 25, the createFeedback method lacks input validation and
error handling. Add checks to validate the command's userId, rate, and content
before building the Feedback object, throwing appropriate exceptions if
validation fails. Wrap the save operation in a try-catch block to handle
persistence exceptions and provide clear error messages or rethrow as needed.

Comment on lines +16 to +17
@Length(max = 100)
String feedback
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add null validation for feedback field.

The feedback field can currently be null, which might not be intended. Consider adding @NotNull or @NotBlank validation if feedback is required.

@Schema(description = "피드백 내용", example = "피드백 내용")
+@NotBlank
@Length(max = 100)
String feedback
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Length(max = 100)
String feedback
@Schema(description = "피드백 내용", example = "피드백 내용")
@NotBlank
@Length(max = 100)
String feedback
🤖 Prompt for AI Agents
In src/main/java/org/runimo/runimo/user/controller/request/FeedbackRequest.java
around lines 16 to 17, the feedback field lacks null validation, allowing it to
be null which may be unintended. Add the @NotNull or @NotBlank annotation above
the feedback field declaration to enforce that feedback must not be null or
blank, ensuring proper validation of this input.

Comment on lines +13 to +14
@Min(1) @Max(6)
Integer rate,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding validation context and constraints.

The rate field allows values 1-6 but lacks documentation about what these values represent. Consider adding more descriptive documentation or constants for the rating scale.

+public static final int MIN_RATE = 1;
+public static final int MAX_RATE = 6;
+
-@Schema(description = "평가지표", example = "1")
+@Schema(description = "평가지표 (1: 매우 불만족, 6: 매우 만족)", example = "3")
-@Min(1) @Max(6)
+@Min(MIN_RATE) @Max(MAX_RATE)
Integer rate,

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/org/runimo/runimo/user/controller/request/FeedbackRequest.java
around lines 13 to 14, the rate field has @Min(1) and @Max(6) annotations but
lacks descriptive documentation or constants explaining what the values 1 to 6
represent. Add JavaDoc comments to the rate field describing the meaning of each
rating value or define constants/enums representing the rating scale to improve
code clarity and maintainability.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jul 9, 2025

@ekgns33 ekgns33 merged commit 90e6ad3 into main Jul 9, 2025
3 checks passed
@ekgns33 ekgns33 deleted the feat/feedback branch July 9, 2025 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants