-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 반려동물용 강의 관리기능 추가 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| language: ko-KR | ||
|
|
||
| early_access: true | ||
| enable_free_tier: true | ||
| reviews: | ||
| profile: chill | ||
| request_changes_workflow: true | ||
| high_level_summary: true | ||
| high_level_summary_placeholder: '@coderabbitai 요약' | ||
| auto_title_placeholder: '@coderabbitai' | ||
| poem: true | ||
| review_status: true | ||
| collapse_walkthrough: false | ||
| path_filters: | ||
| - "!**/swagger.json" | ||
| - "!**/README.md" | ||
| path_instructions: | ||
| - path: "**/*.sql" | ||
| instructions: > | ||
| As a team convention, we do not specify FK constraints. Please avoid suggesting adding FK constraints in code reviews. | ||
| This file is a TypeScript file, but the SQL statements that modify the table structure are written as strings. For columns used as primary keys (PK) or foreign keys (FK), you must follow the convention of specifying the column type as "bigint". | ||
| If a table column name is "id" or ends with "_id", verify that the column type is "bigint". If the SQL is written with a type other than "bigint", issue a warning. This convention is mandatory, so please raise the severity level of the warning. Add the following characters to the beginning of the warning message so that users can easily notice it: 🚨🚨🚨 | ||
|
|
||
| - path: "**/*Controller*(V[0-9]*)?.ts" | ||
| instructions: > | ||
| Review the API endpoints based on this guidelines. | ||
|
|
||
| ### Richardson Maturity Model (RMM) | ||
| 1. Level 0: Single URI with POST requests for all actions. | ||
| 2. Level 1: Separate URIs for individual resources. | ||
| 3. Level 2: Use of HTTP methods (GET, POST, PUT, DELETE) to define operations on resources. | ||
| 4. Level 3: Hypermedia (HATEOAS) for advanced RESTful APIs. | ||
|
|
||
| ### API Conventions | ||
| - URI Rules: | ||
| - Should be intuitive and self-explanatory. | ||
| - Should not map 1:1 to database tables. | ||
| - Must be stateless, with no session state between requests. | ||
| - Include "api" and version in the URI (/api/{version}/resource). | ||
| - Use kebab-case for URIs and camelCase for parameters and body contents. | ||
| - Resource identifiers should be unique and only one per URI path. | ||
|
|
||
| - Design Principles: | ||
| - APIs should be designed around resources, which are abstractions rather than direct database tables. | ||
| - Stateless APIs facilitate scalability and flexibility. | ||
| - Clear separation of frontend and backend via URI structure. | ||
| - Versioning in URI paths is preferred for clarity and ease of caching. | ||
| - Maintain consistent naming conventions across the API. | ||
| - Use plural forms for resource names (/users instead of /user). | ||
| - Complex actions can include verbs in the URI (/orders/{orderId}/cancel). | ||
|
|
||
| - Implementation Details: | ||
| - Avoid deeply nested resource paths to ensure maintainability. | ||
| - Ensure URIs reflect the data they provide, not the permissions or roles required to access them. | ||
| - Keep URIs simple and predictable, aiding both developers and automated systems. | ||
| abort_on_close: true | ||
| auto_review: | ||
| enabled: true | ||
| auto_incremental_review: true | ||
| ignore_title_keywords: [] | ||
| labels: [] | ||
| drafts: false | ||
| base_branches: [] | ||
| tools: | ||
| shellcheck: | ||
| enabled: true | ||
| ruff: | ||
| enabled: true | ||
| markdownlint: | ||
| enabled: true | ||
| github-checks: | ||
| enabled: true | ||
| timeout_ms: 90000 | ||
| languagetool: | ||
| enabled: true | ||
| disabled_rules: | ||
| - EN_UNPAIRED_BRACKETS | ||
| - EN_UNPAIRED_QUOTES | ||
| disabled_categories: | ||
| - TYPOS | ||
| - TYPOGRAPHY | ||
| - CASING | ||
| enabled_only: false | ||
| level: default | ||
| enabled_rules: [] | ||
| enabled_categories: [] | ||
| biome: | ||
| enabled: true | ||
| hadolint: | ||
| enabled: true | ||
| swiftlint: | ||
| enabled: true | ||
| phpstan: | ||
| enabled: true | ||
| level: default | ||
| golangci-lint: | ||
| enabled: true | ||
| yamllint: | ||
| enabled: true | ||
| gitleaks: | ||
| enabled: true | ||
| checkov: | ||
| enabled: true | ||
| ast-grep: | ||
| packages: [] | ||
| rule_dirs: [] | ||
| util_dirs: [] | ||
| essential_rules: true | ||
| chat: | ||
| auto_reply: true | ||
| knowledge_base: | ||
| learnings: | ||
| scope: auto | ||
| issues: | ||
| scope: auto | ||
| jira: | ||
| project_keys: [] | ||
| linear: | ||
| team_keys: [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package org.springframework.samples.petclinic.course; | ||
|
|
||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| public interface CouresRepository extends JpaRepository<Course, Integer> { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package org.springframework.samples.petclinic.course; | ||
|
|
||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.EnumType; | ||
| import jakarta.persistence.Enumerated; | ||
| import jakarta.persistence.GeneratedValue; | ||
| import jakarta.persistence.GenerationType; | ||
| import jakarta.persistence.Id; | ||
| import jakarta.persistence.JoinColumn; | ||
| import jakarta.persistence.ManyToOne; | ||
| import jakarta.persistence.Table; | ||
| import lombok.Getter; | ||
| import lombok.Setter; | ||
| import org.springframework.samples.petclinic.model.BaseEntity; | ||
| import org.springframework.samples.petclinic.vet.Vet; | ||
|
|
||
| @Getter | ||
| @Setter | ||
| @Entity | ||
| @Table(name = "courses") | ||
| public class Course extends BaseEntity { | ||
| private String name; | ||
| private String description; | ||
| // 예: 초급, 중급, 고급 | ||
| private String difficulty; | ||
|
|
||
| @ManyToOne | ||
| @JoinColumn(name = "vet_id") | ||
| private Vet instructor; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,30 @@ | ||||||||||||||||||||||||||||||||||||||||
| package org.springframework.samples.petclinic.course; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.http.ResponseEntity; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.samples.petclinic.course.dto.CreateCourseRequest; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.samples.petclinic.vet.Vet; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.samples.petclinic.vet.VetRepository; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.PostMapping; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.RequestBody; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.RequestParam; | ||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.RestController; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| @RestController | ||||||||||||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||||||||||||
| @RequestMapping("/courses") | ||||||||||||||||||||||||||||||||||||||||
| public class CourseController { | ||||||||||||||||||||||||||||||||||||||||
| private final CourseService courseService; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| @PostMapping() | ||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<Integer> createCourse(@RequestBody CreateCourseRequest request) { | ||||||||||||||||||||||||||||||||||||||||
| System.out.println(request); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| Course course = courseService.createCourse(request.getName(), request.getDescription(), request.getDescription(), request.getVetId()); | ||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. createCourse 메서드 매개변수 오류가 있습니다.
- Course course = courseService.createCourse(request.getName(), request.getDescription(), request.getDescription(), request.getVetId());
+ Course course = courseService.createCourse(request.getName(), request.getDescription(), request.getDifficulty(), request.getVetId());📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(course.getId()); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+23
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 예외 처리가 없습니다. 현재 메서드에는 예외 처리 로직이 없습니다. 예를 들어, 존재하지 않는 VetId로 인한 오류나 DB 관련 예외를 처리하는 로직이 필요합니다. @PostMapping()
public ResponseEntity<Integer> createCourse(@RequestBody CreateCourseRequest request) {
System.out.println(request);
- Course course = courseService.createCourse(request.getName(), request.getDescription(), request.getDescription(), request.getVetId());
-
- return ResponseEntity.ok(course.getId());
+ try {
+ Course course = courseService.createCourse(request.getName(), request.getDescription(), request.getDifficulty(), request.getVetId());
+ return ResponseEntity.ok(course.getId());
+ } catch (Exception e) {
+ log.error("Course creation failed: {}", e.getMessage(), e);
+ return ResponseEntity.badRequest().build();
+ }
}더 나은 해결책은 예외 유형에 따라 적절한 응답을 반환하는 글로벌 예외 핸들러를 구현하는 것입니다. 📝 Committable suggestion
Suggested change
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. API 에서 발생하는 에러를 Controller 마다 catch 절로 처리하지 않고, 공통 관심사로 묶어서 처리하고 싶습니다. 어떻게 하면 API 에서 발생하는 예외들을 공통 관심사의 로직으로 처리할 수 있을까요 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yakpoong Spring에서는
package org.springframework.samples.petclinic.exception;
import lombok.Getter;
@Getter
public class ResourceNotFoundException extends RuntimeException {
private final String resourceName;
private final String fieldName;
private final Object fieldValue;
public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
this.resourceName = resourceName;
this.fieldName = fieldName;
this.fieldValue = fieldValue;
}
}
package org.springframework.samples.petclinic.exception;
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
package org.springframework.samples.petclinic.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import java.time.LocalDateTime;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(
ResourceNotFoundException ex, WebRequest request) {
log.error("Resource not found exception: {}", ex.getMessage());
ErrorResponse errorResponse = new ErrorResponse(
LocalDateTime.now(),
HttpStatus.NOT_FOUND.value(),
"Resource Not Found",
ex.getMessage(),
request.getDescription(false)
);
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<ErrorResponse> handleBadRequestException(
BadRequestException ex, WebRequest request) {
log.error("Bad request exception: {}", ex.getMessage());
ErrorResponse errorResponse = new ErrorResponse(
LocalDateTime.now(),
HttpStatus.BAD_REQUEST.value(),
"Bad Request",
ex.getMessage(),
request.getDescription(false)
);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(
Exception ex, WebRequest request) {
log.error("Unhandled exception: {}", ex.getMessage(), ex);
ErrorResponse errorResponse = new ErrorResponse(
LocalDateTime.now(),
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"Internal Server Error",
ex.getMessage(),
request.getDescription(false)
);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
package org.springframework.samples.petclinic.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
@PostMapping()
public ResponseEntity<Integer> createCourse(@RequestBody CreateCourseRequest request) {
// 유효성 검사
if (request.getName() == null || request.getName().trim().isEmpty()) {
throw new BadRequestException("Course name cannot be empty");
}
// 서비스 호출
Course course = courseService.createCourse(
request.getName(),
request.getDescription(),
request.getDifficulty(),
request.getVetId()
);
return ResponseEntity.ok(course.getId());
}
public Course createCourse(String name, String description, String difficulty, Integer vetId) {
// vetRepository.findById()가 빈 Optional을 반환할 경우 예외 발생
Vet vet = vetRepository.findById(vetId)
.orElseThrow(() -> new ResourceNotFoundException("Vet", "id", vetId));
Course course = new Course();
course.setName(name);
course.setDescription(description);
course.setDifficulty(difficulty);
course.setInstructor(vet);
return courseRepository.save(course);
}이 방식을 사용하면 모든 컨트롤러에서 공통적으로 발생하는 예외 처리 로직을 중앙화할 수 있습니다.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai 예외 처리 로직 중앙화처리는 별도의 Issue를 통해 해결하고 싶습니다. 이슈를 생성해 주세요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain@yakpoong 예외 처리 로직 중앙화에 대한 Issue를 생성해드렸습니다. Issue에는 다음 내용이 포함되어 있습니다:
해당 Issue는 yakpoong님께 할당되었습니다. 추가적인 요구사항이 있으시면 말씀해주세요. 🏁 Script executed: Length of output: 893 @yakpoong 요청하신 대로 예외 처리 로직 중앙화에 대한 이슈를 성공적으로 생성했습니다! 이슈는 다음 링크에서 확인하실 수 있습니다: #2 이슈는 yakpoong님께 할당되었으며, PR #1의 코멘트를 참조 링크로 포함했습니다. |
||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,40 @@ | ||||||||||||||||||||||||||
| package org.springframework.samples.petclinic.course; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||
| import org.springframework.samples.petclinic.vet.Vet; | ||||||||||||||||||||||||||
| import org.springframework.samples.petclinic.vet.VetRepository; | ||||||||||||||||||||||||||
| import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||
| import org.springframework.transaction.annotation.Transactional; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import java.util.Collection; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Service | ||||||||||||||||||||||||||
| @Transactional(readOnly = true) | ||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||
| public class CourseService { | ||||||||||||||||||||||||||
| private final CouresRepository courseRepository; | ||||||||||||||||||||||||||
| private final VetRepository vetRepository; | ||||||||||||||||||||||||||
|
Comment on lines
+12
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repository 이름에 오타가 있습니다. 코드에 - private final CouresRepository courseRepository;
+ private final CourseRepository courseRepository;📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Transactional() | ||||||||||||||||||||||||||
| public Course createCourse(String name, String description, String difficulty, Integer vetId) { | ||||||||||||||||||||||||||
| Collection<Vet> all = vetRepository.findAll(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| all.forEach(course -> { | ||||||||||||||||||||||||||
| System.out.println(course.getId()); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+20
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 디버깅 코드를 제거하세요. 프로덕션 코드에 람다 표현식에서 파라미터 이름이 - @Transactional()
+ @Transactional
public Course createCourse(String name, String description, String difficulty, Integer vetId) {
- Collection<Vet> all = vetRepository.findAll();
-
- all.forEach(course -> {
- System.out.println(course.getId());
- });
-
Vet instructor = vetRepository.findById(vetId)
.orElseThrow(() -> new RuntimeException("Vet not found"));📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||
| Vet instructor = vetRepository.findById(vetId) | ||||||||||||||||||||||||||
| .orElseThrow(() -> new RuntimeException("Vet not found")); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Course course = new Course(); | ||||||||||||||||||||||||||
| course.setName(name); | ||||||||||||||||||||||||||
| course.setDescription(description); | ||||||||||||||||||||||||||
| course.setDifficulty(difficulty); | ||||||||||||||||||||||||||
| course.setInstructor(instructor); | ||||||||||||||||||||||||||
| courseRepository.save(course); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return course; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package org.springframework.samples.petclinic.course.dto; | ||
|
|
||
| import lombok.Getter; | ||
|
|
||
| @Getter() | ||
| public class CreateCourseRequest { | ||
| private String name; | ||
| private String description; | ||
| private String difficulty; | ||
| private Integer vetId; | ||
|
|
||
| public CreateCourseRequest() { | ||
| } | ||
|
|
||
| public CreateCourseRequest(String name, String description, String difficulty, Integer vetId) { | ||
| this.name = name; | ||
| this.description = description; | ||
| this.difficulty = difficulty; | ||
| this.vetId = vetId; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "CreateCourseRequest{" + | ||
| "name='" + name + '\'' + | ||
| ", description='" + description + '\'' + | ||
| ", difficulty='" + difficulty + '\'' + | ||
| ", vetId=" + vetId + | ||
| '}'; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -62,3 +62,13 @@ CREATE TABLE visits ( | |||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); | ||||||||||||||||||||||||||||||
| CREATE INDEX visits_pet_id ON visits (pet_id); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| CREATE TABLE courses ( | ||||||||||||||||||||||||||||||
| id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, | ||||||||||||||||||||||||||||||
| name VARCHAR(255), | ||||||||||||||||||||||||||||||
| description VARCHAR(1000), | ||||||||||||||||||||||||||||||
| difficulty VARCHAR(255), | ||||||||||||||||||||||||||||||
| vet_id INTEGER | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
Comment on lines
+66
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚨🚨🚨 ID 및 FK 컬럼 타입이 팀 컨벤션을 따르지 않습니다.
CREATE TABLE courses (
- id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255),
description VARCHAR(1000),
difficulty VARCHAR(255),
- vet_id INTEGER
+ vet_id BIGINT
);📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
| CREATE INDEX courses_vet_id ON courses (vet_id); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인터페이스 이름에 오타가 있습니다
인터페이스 이름이
CouresRepository로 되어 있는데, 올바른 철자는CourseRepository입니다. 's'가 빠져있습니다. 이 오타는 다른 클래스에서 이 레포지토리를 참조할 때 혼란을 줄 수 있습니다.다음과 같이 수정하세요:
📝 Committable suggestion