feat(application): Application JPA 저장소 구성 #24 - #63
Conversation
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
🚫 Excluded labels (none allowed) (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 Walkthrough지원자는 REST API를 통해 지원서 정보와 성적 정보를 단계별로 저장·수정할 수 있습니다. 시스템은 전형별 평가 점수를 계산하고 표준화된 응답과 오류를 반환합니다. 아키텍처 변경
위험 영역
마이그레이션 및 호환성
검증 체크리스트 및 롤아웃
Walkthrough지원서 작성·제출 API와 평가 API를 추가했습니다. 지원자 도메인 모델, 전형별 점수 계산, 애플리케이션 서비스, JPA 영속화, 공통 오류 응답을 함께 구현했습니다. Changes지원서 및 평가 기능
Estimated code review effort: 4 (Complex) | ~60 minutes Suggested labels: Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant Client
participant ApplicationController
participant ApplicationCommandService
participant ApplicantPersistenceAdapter
Client->>ApplicationController: 지원서 요청
ApplicationController->>ApplicationCommandService: 명령 객체 전달
ApplicationCommandService->>ApplicantPersistenceAdapter: 지원자 저장 또는 조회
ApplicantPersistenceAdapter-->>ApplicationCommandService: 도메인 객체 반환
ApplicationCommandService-->>ApplicationController: 처리 결과 반환
ApplicationController-->>Client: ApiResponse 반환
sequenceDiagram
participant Client
participant EvaluationController
participant EvaluationCommandService
participant ScoreCalculator
Client->>EvaluationController: 평가 정보 또는 결과 요청
EvaluationController->>EvaluationCommandService: 평가 명령 전달
EvaluationCommandService->>ScoreCalculator: 점수 계산 요청
ScoreCalculator-->>EvaluationCommandService: 전형별 점수 반환
EvaluationCommandService-->>EvaluationController: 평가 결과 반환
EvaluationController-->>Client: EvaluationResultResponse 반환
🚥 Pre-merge checks | ✅ 8 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (8 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 26
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.kt`:
- Around line 55-64: Update ApplicationController.kt:55-64 to derive accountId
from the validated authentication principal instead of request.accountId; update
ApplicationController.kt:67-174 so every modification or submission verifies
that the principal owns the target applicant; update
EvaluationController.kt:31-105 to apply the same authentication and
applicant-ownership checks before saving scores or retrieving evaluation
results.
- Around line 41-192: Add web or integration tests in the application adapter-in
subsystem for ApplicationController
(systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.kt:41-192),
covering applicant creation, updates, submission, successful responses,
validation failures, ownership failures, and expected HTTP status codes. Add
corresponding tests for EvaluationController
(systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/EvaluationController.kt:26-126)
covering grade saving and evaluation-result response contracts, including normal
and failure cases.
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.kt`:
- Around line 3-5: 요청 본문에서 계정·지원자 식별자를 신뢰하지 않도록 인증 주체 기반으로 소유권을 검증하십시오.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.kt#L3-L5에서는
accountId를 제거하고 principal의 계정 식별자를 사용하십시오. SaveAcademicRecordRequest.kt#L3-L11,
SaveCertificatesRequest.kt#L3-L7, SaveGedScoresRequest.kt#L3-L12,
SubmitApplicationRequest.kt#L3-L5의 각 저장·제출 경로에서는 작업 전에 principal이 applicantId의
소유자인지 포트 또는 애플리케이션 서비스에서 검증하십시오.
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt`:
- Around line 9-14: SaveAcademicRecordRequest의 volunteerTime 입력 계약을 단일 필수 필드로
통합하십시오. volunteer_time 프로퍼티와 resolvedVolunteerTime() 메서드를 제거하고 volunteerTime만
사용하도록 요청 DTO와 호출부를 갱신하십시오. API 경계에서 두 이름을 모두 받는 로직이 있다면 충돌 요청은 거부하며, 프로퍼티·함수·지역
변수는 lowerCamelCase를 유지하십시오.
- Around line 12-14: 동일 서브시스템에 변환 로직과 웹 계약을 검증하는 테스트가 누락되었습니다.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt#L12-L14에는
누락 값, 두 입력 이름이 모두 제공된 충돌 값의 거부, 각 단일 입력의 정상 처리를 검증하는 테스트를 추가하십시오.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.kt#L15-L40에는
결과 객체의 모든 필드가 응답 DTO에 보존되는 테스트를,
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.kt#L15-L24에는
일곱 과목 등급이 대응하는 도메인 과목 필드로 정확히 매핑되는 테스트를 추가하십시오. 웹 계층 테스트에서는 JSON 요청 역직렬화와 HTTP
응답 계약도 검증하십시오.
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/exception/GlobalExceptionHandler.kt`:
- Around line 23-59: Update GlobalExceptionHandler.handleApplicantNotFound and
handleInvalidRequest to return fixed client-safe messages instead of
exception.message, while preserving their 404/APPLICANT_NOT_FOUND and
400/INVALID_REQUEST mappings. Add deterministic application-adapter-in contract
tests covering those handlers plus handleUnhandledException’s
500/INTERNAL_SERVER_ERROR response and confirming exception details are absent
from every response.
- Around line 40-45: handleInvalidRequest in GlobalExceptionHandler must stop
exposing exception.message in ErrorResponse; always return the fixed "invalid
request" message while preserving the BAD_REQUEST status and INVALID_REQUEST
code. Log the detailed exception server-side with the correlation ID, and add
module tests covering the exception mapping and fixed response message.
In `@systems/application/application-adapter-out/deps.bzl`:
- Around line 1-6: Remove com_mysql_mysql_connector_j from KOTLIN_DEPS and
declare it under the kt_jvm_library runtime_deps for application-adapter-out.
Keep the existing compile-time dependencies unchanged.
In
`@systems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/AcademicRecordJpaEntity.kt`:
- Around line 18-26: AcademicRecordJpaEntity의 applicant 지연 로딩 프록시가 생성되도록 JPA
all-open 설정을 적용하세요. application-adapter-out의 kt_jvm_library에 spring_allopen
플러그인과 jakarta.persistence.Entity 대상 설정을 추가하거나, 해당 프로퍼티를 open var로 선언해 기존
FetchType.LAZY 동작을 보장하세요.
- Around line 63-74: Update the entity-mapping logic around the subjectGrades
and gedScores assignments to reconcile existing entities by their keys and
update them in place, rather than clearing collections or replacing associated
instances. Reuse matching SubjectGradeJpaEntity entries by schoolSemester and
the existing GedScoreJpaEntity for the academic record, add only genuinely new
entries, and remove entries no longer present while preserving orphan removal
behavior.
In
`@systems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/ApplicantJpaEntity.kt`:
- Around line 114-118: 기본 EAGER 연관 로딩을 제거해 지원자 조회 시 불필요한 조인을 방지하세요.
ApplicantJpaEntity.kt의 middleSchoolInfo와 academicRecord,
AcademicRecordJpaEntity.kt의 subjectGrades와 gedScores를 FetchType.LAZY로 변경하고, 필요한
도메인 변환 조회에는 ApplicantJpaRepository의 `@EntityGraph` 지정 조회 메서드를 추가해 해당 연관만 명시적으로
로딩하세요.
- Line 192: Update updateAcademicRecord to use the imported AcademicRecord type
instead of the fully qualified
hs.kr.entrydsm.application.domain.model.AcademicRecord name, adding the import
with the other domain model imports and preserving the method behavior.
- Line 177: Update ApplicantJpaEntity.updateFrom to stop assigning
domain.createdAt, preserving the existing entity creation timestamp during
updates. Keep createdAt initialized only once when constructing a new entity
through from, and declare the corresponding persistence column immutable.
- Around line 201-205: ApplicantJpaEntity.Companion.from에서 신규 엔티티를 생성할 때는 항상 id를
null로 유지하고, 양수 domain.id가 기존 엔티티 조회에 실패하면 해당 ID를 가진 행을 생성하지 말고 예외를 발생시키도록 수정하세요.
id가 0인 신규 생성 경로와 양수 ID 조회 실패 경로를 검증하는 결정적 테스트를 추가하세요.
In
`@systems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantPersistenceAdapter.kt`:
- Around line 9-26: Add repository tests for ApplicantPersistenceAdapter
covering new Applicant ID assignment, existing Applicant updates preserving
createdAt, repeated persistence of academic records and subject grades, and
findById returning null for unknown IDs. Extend TEST_DEPS beyond junit_junit
with the dependencies required for the project’s JPA integration-test setup, and
use the existing test infrastructure and entity/domain fixtures.
- Around line 14-21: Apply optimistic locking to ApplicantJpaEntity by adding a
`@Version` field and preserving its value through entity/domain conversions.
Update ApplicantPersistenceAdapter.save to translate
OptimisticLockingFailureException into the project’s domain exception that
signals callers to retry, while retaining the existing save behavior for
non-conflicting writes.
In
`@systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/ApplicationCommandService.kt`:
- Around line 220-228: Update submit in ApplicationCommandService to persist a
submission marker, such as submittedAt or applicationStatus, in the Applicant
domain and persistence models. Set this marker atomically with the existing
saveTouched operation after validation, so submitted applications remain
distinguishable from drafts.
- Around line 32-34: ApplicationCommandService의 createApplicant 및 관련 생성·입력
검증·수정·제출 유스케이스에 대한 테스트를 같은 application 서브시스템에 추가하십시오. 정상 흐름과 GED 졸업일 규칙, 전화번호
검증, 자기소개서 길이 제한, 제출 후 완료 상태를 각각 검증하고, 기존 테스트 구조와 픽스처를 재사용하십시오.
- Around line 26-31: ApplicationCommandService에서 Spring 의존성을 제거하십시오.
org.springframework.stereotype.Service import와 클래스의 `@Service` 어노테이션을 삭제하고, 해당 서비스
빈 등록은 구성 계층에서 처리하도록 구성하십시오.
- Around line 235-237: ApplicationCommandService의 saveTouched 흐름에서 오래된 Applicant
Aggregate 전체 저장으로 인한 덮어쓰기를 방지하십시오. ApplicantPersistenceAdapter.save에 버전 조건부 저장을
적용하거나 명령별 부분 업데이트로 변경하고, 동시 수정 시 충돌 저장이 거부되도록 구현하십시오. 충돌 동작을 검증하는 테스트도 추가하십시오.
In
`@systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.kt`:
- Around line 137-142: Update calculateResult so totalScore uses the score key
matching applicant.admissionType instead of always using "REGULAR". Reject
calculation when admissionType is missing, while preserving the existing score
calculation, timestamp update, and repository save flow for valid applicants.
- Around line 139-142: Update the score refresh flow in EvaluationCommandService
around scoreCalculator.calculate and applicantRepository.save by calling
applicant.touch() after updating totalScore and totalScoreUpdatedAt, before
saving the applicant.
- Around line 20-26: Remove the Spring `@Service` annotation and its import from
EvaluationCommandService, then register EvaluationCommandService as a bean in
the external bootstrap or adapter configuration. In
systems/application/application-application/deps.bzl lines 1-4, remove the
Spring Boot starter if it is only used for this annotation; otherwise move the
dependency to the adapter or bootstrap module.
In
`@systems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.kt`:
- Around line 21-26: Enforce graduationType-based score invariants in
ScoreCalculator.kt: select the GED or school calculation solely from
applicant.graduationType and reject unsupported or mismatched score states
instead of inferring the type from gedScores. In EvaluationCommandService.kt,
validate before persistence that the submitted score type matches
applicant.graduationType, and either remove opposite-type data or reject the
save consistently.
- Around line 67-78: Update the score calculation around semesterWeights and
weightedScores in ScoreCalculator so every required semester has a subject grade
before calculating a score. If any required semester is missing, return the
existing incomplete/empty result instead of excluding it and normalizing by
reflectedWeight; only perform the weighted calculation when all required
semesters are present.
- Around line 13-197: Add deterministic unit tests for ScoreCalculator covering
graduation and GED scoring, missing required semesters, attendance boundary
values, additional-score caps, and rounding with meaningful assertions. Add
service tests for EvaluationCommandService covering per-track score persistence,
score-type validation, and updated-timestamp changes; apply the requested test
changes to both affected subsystem files.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 71ee815f-51e3-4bcd-a3a5-792f49a01078
📒 Files selected for processing (76)
systems/application/application-adapter-in/deps.bzlsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/EvaluationController.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/config/LandingScheduleProperties.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ApiResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorDetail.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/AddressRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveCertificatesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveGedScoresRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveSubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubmitApplicationRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateFamilyRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateIntroductionRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateMiddleSchoolRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdatePersonalRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateStudyPlanRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateTypeRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/AcademicRecordResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/CreateApplicantResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/EvaluationResultResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/LandingResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/PeriodResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/ScheduleResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/exception/GlobalExceptionHandler.ktsystems/application/application-adapter-out/deps.bzlsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/AcademicRecordJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/ApplicantJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/GedScoreJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/MiddleSchoolInfoJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultId.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeId.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantJpaRepository.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantPersistenceAdapter.ktsystems/application/application-application/deps.bzlsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/exception/ApplicantNotFoundException.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/ApplicationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/EvaluationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CalculateEvaluationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CreateApplicantCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveAcademicRecordCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveCertificatesCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveGedScoresCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveSubjectGradesCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SubmitApplicationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateFamilyCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateIntroductionCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateMiddleSchoolCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdatePersonalCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateStudyPlanCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateTypeCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/AcademicRecordResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/CreateApplicantResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/EvaluationResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/LandingResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/out/ApplicantRepository.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/ApplicationCommandService.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/AdmissionType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Gender.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GraduationType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GuardianRelation.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/PassResultStatus.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Region.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/ResultType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SchoolSemester.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SpecialAdmissionType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SubjectGrade.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/model/Applicant.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.kt
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{kt,go}
📄 CodeRabbit inference engine (Custom checks)
If production logic is changed in Kotlin or Go files, require corresponding test updates in the same subsystem unless the PR description explicitly justifies why tests are unnecessary
Files:
systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CalculateEvaluationCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateFamilyRequest.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/PassResultStatus.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Gender.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Region.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GuardianRelation.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveAcademicRecordCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/AddressRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateIntroductionRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateStudyPlanRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/LandingResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveCertificatesRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SubmitApplicationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/CreateApplicantResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveSubjectGradesCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/AdmissionType.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/ApplicationPort.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/EvaluationResultResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/CreateApplicantResponse.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/LandingResult.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateMiddleSchoolRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveCertificatesCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorDetail.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/AcademicRecordResponse.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SpecialAdmissionType.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveSubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateTypeRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateFamilyCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveGedScoresRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/ScheduleResponse.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SubjectGrade.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateMiddleSchoolCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CreateApplicantCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateStudyPlanCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SchoolSemester.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/AcademicRecordResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateTypeCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/PeriodResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdatePersonalRequest.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeId.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveGedScoresCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ApiResponse.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/out/ApplicantRepository.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdatePersonalCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/config/LandingScheduleProperties.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeJpaEntity.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/EvaluationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateIntroductionCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GraduationType.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/GedScoreJpaEntity.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/ResultType.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/MiddleSchoolInfoJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultId.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantJpaRepository.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubmitApplicationRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/exception/GlobalExceptionHandler.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/exception/ApplicantNotFoundException.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/ApplicantJpaEntity.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/model/Applicant.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/AcademicRecordJpaEntity.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/EvaluationController.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/ApplicationCommandService.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/EvaluationResult.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantPersistenceAdapter.kt
**/*-application/**/*.{java,kt,scala,groovy}
📄 CodeRabbit inference engine (Custom checks)
For files under *-application modules, flag direct dependency on infrastructure-specific framework classes unless justified
Files:
systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CalculateEvaluationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveAcademicRecordCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SubmitApplicationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/CreateApplicantResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveSubjectGradesCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/ApplicationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/LandingResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveCertificatesCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateFamilyCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateMiddleSchoolCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CreateApplicantCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateStudyPlanCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/AcademicRecordResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateTypeCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveGedScoresCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/out/ApplicantRepository.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdatePersonalCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/EvaluationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateIntroductionCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/exception/ApplicantNotFoundException.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/ApplicationCommandService.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/EvaluationResult.kt
**/*.{java,kt,scala,groovy,go,js,ts,tsx,jsx,py,rb,rs,cpp,c,h,hpp,cs}
📄 CodeRabbit inference engine (Custom checks)
Flag TODO/FIXME comments introduced by this PR that do not include an issue reference in the form
#123or a full tracker key like PROJ-123
Files:
systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CalculateEvaluationCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateFamilyRequest.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/PassResultStatus.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Gender.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Region.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GuardianRelation.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveAcademicRecordCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/AddressRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateIntroductionRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateStudyPlanRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/LandingResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveCertificatesRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SubmitApplicationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/CreateApplicantResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveSubjectGradesCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/AdmissionType.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/ApplicationPort.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/EvaluationResultResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/CreateApplicantResponse.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/LandingResult.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateMiddleSchoolRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveCertificatesCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorDetail.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/AcademicRecordResponse.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SpecialAdmissionType.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveSubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateTypeRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateFamilyCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveGedScoresRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/ScheduleResponse.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SubjectGrade.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateMiddleSchoolCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CreateApplicantCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateStudyPlanCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SchoolSemester.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/AcademicRecordResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateTypeCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/PeriodResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdatePersonalRequest.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeId.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveGedScoresCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ApiResponse.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/out/ApplicantRepository.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdatePersonalCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/config/LandingScheduleProperties.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeJpaEntity.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/EvaluationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateIntroductionCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GraduationType.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/GedScoreJpaEntity.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/ResultType.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/MiddleSchoolInfoJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultId.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantJpaRepository.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubmitApplicationRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/exception/GlobalExceptionHandler.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/exception/ApplicantNotFoundException.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/ApplicantJpaEntity.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/model/Applicant.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/AcademicRecordJpaEntity.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/EvaluationController.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/ApplicationCommandService.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/EvaluationResult.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantPersistenceAdapter.kt
**/*.kt
⚙️ CodeRabbit configuration file
**/*.kt: Apply Kotlin Official Coding Conventions.Formatting and structure:
- Use 4 spaces for indentation; no tabs.
- Keep files focused and readable; avoid horizontal alignment for spacing.
- Place related declarations together and keep overloads adjacent.
- Keep implementation member order stable and logical for readability.
Naming:
- Package names are lowercase and do not use underscores.
- Class/object names use UpperCamelCase.
- Functions/properties/local variables use lowerCamelCase.
- Constants use UPPER_SNAKE_CASE only for true constants.
API and null-safety:
- Avoid platform type leakage in public APIs.
- Use explicit types in public APIs when inference obscures meaning.
- Prefer immutable values (
val) over mutable values (var) unless mutation is required.- Flag nullable flows that can be replaced with safer modeling.
Imports and idioms:
- Avoid wildcard imports unless justified by language/tooling conventions.
- Prefer expression bodies for short, clear functions.
- Prefer standard library idioms over custom utility wrappers when equivalent.
Architecture and tests:
- Respect module boundaries (domain/application/adapter/bootstrap layering).
- Highlight behavior-changing code that lacks corresponding unit/integration tests.
- Ask for deterministic tests and meaningful assertions, not only happy-path checks.
Files:
systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CalculateEvaluationCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateFamilyRequest.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/PassResultStatus.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Gender.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Region.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GuardianRelation.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveAcademicRecordCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/AddressRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateIntroductionRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateStudyPlanRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/LandingResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveCertificatesRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SubmitApplicationCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/CreateApplicantResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveSubjectGradesCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/AdmissionType.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/ApplicationPort.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/EvaluationResultResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/CreateApplicantResponse.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/LandingResult.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateMiddleSchoolRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveCertificatesCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorDetail.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/AcademicRecordResponse.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SpecialAdmissionType.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveSubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdateTypeRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateFamilyCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveGedScoresRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/ScheduleResponse.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SubjectGrade.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateMiddleSchoolCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/CreateApplicantCommand.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateStudyPlanCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SchoolSemester.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/AcademicRecordResult.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateTypeCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/response/PeriodResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ErrorResponse.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/UpdatePersonalRequest.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeId.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/SaveGedScoresCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ApiResponse.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/out/ApplicantRepository.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdatePersonalCommand.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/config/LandingScheduleProperties.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/SubjectGradeJpaEntity.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/EvaluationPort.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/command/UpdateIntroductionCommand.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GraduationType.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/GedScoreJpaEntity.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/ResultType.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/MiddleSchoolInfoJpaEntity.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/PassResultId.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantJpaRepository.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubmitApplicationRequest.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/exception/GlobalExceptionHandler.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/exception/ApplicantNotFoundException.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/ApplicantJpaEntity.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/model/Applicant.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/entity/AcademicRecordJpaEntity.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/EvaluationController.ktsystems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/ApplicationController.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/ApplicationCommandService.ktsystems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/port/in/result/EvaluationResult.ktsystems/application/application-adapter-out/src/main/kotlin/hs/kr/entrydsm/application/adapterout/repository/ApplicantPersistenceAdapter.kt
**/*-domain/**/*.{java,kt,scala,groovy}
📄 CodeRabbit inference engine (Custom checks)
For files under *-domain modules, fail if imports reference adapter or bootstrap packages
Files:
systems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/PassResultStatus.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Gender.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/Region.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GuardianRelation.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/AdmissionType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SpecialAdmissionType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SubjectGrade.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/SchoolSemester.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/GraduationType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/enum/ResultType.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.ktsystems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/model/Applicant.kt
**/{BUILD.bazel,*.bzl}
📄 CodeRabbit inference engine (Custom checks)
In BUILD.bazel and .bzl files, require buildifier-compatible formatting and stable target naming
Files:
systems/application/application-adapter-out/deps.bzlsystems/application/application-adapter-in/deps.bzlsystems/application/application-application/deps.bzl
**/*.bzl
⚙️ CodeRabbit configuration file
**/*.bzl: Apply Bazel Starlark (.bzl) style guidance.Readability and docs:
- Keep file/module docstrings and docstrings for public functions/macros.
- Use descriptive parameter names and document attribute intent.
API design:
- Macros should take a
nameargument and derive generated target names from it.- Prefer keyword arguments when calling macros for clarity and stability.
- Keep macro side effects predictable and visible.
Encapsulation:
- Use private visibility for helper targets created by macros unless explicitly public.
- Avoid exposing internal implementation targets unintentionally.
Tooling:
- Enforce buildifier formatting and lint compliance.
Files:
systems/application/application-adapter-out/deps.bzlsystems/application/application-adapter-in/deps.bzlsystems/application/application-application/deps.bzl
| data class CreateApplicantRequest( | ||
| val accountId: Long, | ||
| ) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
요청 본문으로 대상 계정 또는 지원자를 결정하지 마십시오.
제공된 컨트롤러 경로는 요청의 accountId 또는 applicantId를 포트 명령으로 직접 전달합니다. ApplicationController의 생성·제출 경로는 선택적 Authorization 헤더도 사용하지 않습니다. 현재 경로에는 인증 주체와 대상 리소스의 소유 관계를 검증하는 지점이 없습니다. 공격자는 다른 식별자를 전송하여 다른 지원자의 정보 저장 또는 제출을 시도할 수 있습니다.
인증된 principal에서 계정 식별자를 파생하십시오. 지원자 수정·성적 저장·제출 전에는 principal이 해당 applicantId의 소유자인지 포트 또는 애플리케이션 서비스에서 검증하십시오.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.kt#L3-L5: 요청의accountId를 제거하고 인증된 principal의 계정 식별자를 사용하십시오.systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt#L3-L11: 저장 전에applicantId소유권을 검증하십시오.systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveCertificatesRequest.kt#L3-L7: 저장 전에applicantId소유권을 검증하십시오.systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveGedScoresRequest.kt#L3-L12: 저장 전에applicantId소유권을 검증하십시오.systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubmitApplicationRequest.kt#L3-L5: 제출 전에applicantId소유권을 검증하십시오.
📍 Affects 5 files
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.kt#L3-L5(this comment)systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt#L3-L11systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveCertificatesRequest.kt#L3-L7systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveGedScoresRequest.kt#L3-L12systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubmitApplicationRequest.kt#L3-L5
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.kt`
around lines 3 - 5, 요청 본문에서 계정·지원자 식별자를 신뢰하지 않도록 인증 주체 기반으로 소유권을 검증하십시오.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/CreateApplicantRequest.kt#L3-L5에서는
accountId를 제거하고 principal의 계정 식별자를 사용하십시오. SaveAcademicRecordRequest.kt#L3-L11,
SaveCertificatesRequest.kt#L3-L7, SaveGedScoresRequest.kt#L3-L12,
SubmitApplicationRequest.kt#L3-L5의 각 저장·제출 경로에서는 작업 전에 principal이 applicantId의
소유자인지 포트 또는 애플리케이션 서비스에서 검증하십시오.
| val volunteerTime: Int? = null, | ||
| val volunteer_time: Int? = null, | ||
| ) { | ||
| fun resolvedVolunteerTime(): Int = | ||
| volunteerTime ?: volunteer_time | ||
| ?: throw IllegalArgumentException("volunteerTime is required") |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
하나의 volunteerTime 입력 계약만 유지하십시오.
Line 9와 Line 10은 같은 값을 서로 다른 이름으로 받습니다. 클라이언트가 두 값을 다르게 보내면 Line 13은 volunteerTime을 조용히 선택합니다. 이 동작은 잘못된 출결 데이터를 저장할 수 있습니다.
volunteer_time 필드와 resolvedVolunteerTime()을 제거하고 volunteerTime 하나를 필수 필드로 사용하십시오. 하위 호환성이 필요하면 API 경계에서 별도 버전 정책을 정의하고, 두 값이 함께 오면 요청을 거부하십시오.
As per path instructions, “Functions/properties/local variables use lowerCamelCase.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt`
around lines 9 - 14, SaveAcademicRecordRequest의 volunteerTime 입력 계약을 단일 필수 필드로
통합하십시오. volunteer_time 프로퍼티와 resolvedVolunteerTime() 메서드를 제거하고 volunteerTime만
사용하도록 요청 DTO와 호출부를 갱신하십시오. API 경계에서 두 이름을 모두 받는 로직이 있다면 충돌 요청은 거부하며, 프로퍼티·함수·지역
변수는 lowerCamelCase를 유지하십시오.
Source: Path instructions
| fun resolvedVolunteerTime(): Int = | ||
| volunteerTime ?: volunteer_time | ||
| ?: throw IllegalArgumentException("volunteerTime is required") |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
동일 서브시스템에 결정적 테스트를 추가하십시오.
이 PR은 요청 변환과 응답 변환의 실행 로직을 추가하지만, 제공된 변경에는 해당 테스트가 없습니다. PR 설명에서 테스트를 후속 작업으로 미룬 것은 테스트가 불필요한 이유가 아닙니다.
SaveAcademicRecordRequest에는 두 입력 이름이 모두 있을 때의 거부 동작을 검증하는 테스트를 추가하십시오. ResponseMapper와 SubjectGradesRequest.toDomain()에는 모든 필드가 정확히 매핑되는 테스트를 추가하십시오. 웹 계층 테스트에서는 JSON 요청과 HTTP 응답 계약도 검증하십시오.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt#L12-L14: 누락 값, 충돌 값, 정상 값을 검증하는 테스트를 추가하십시오.systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.kt#L15-L40: 결과 객체의 모든 필드가 응답 DTO에 보존되는 테스트를 추가하십시오.systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.kt#L15-L24: 일곱 과목 등급이 같은 과목 필드로 변환되는 테스트를 추가하십시오.
As per coding guidelines, “If production logic is changed in Kotlin or Go files, require corresponding test updates in the same subsystem unless the PR description explicitly justifies why tests are unnecessary.”
📍 Affects 3 files
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt#L12-L14(this comment)systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.kt#L15-L40systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.kt#L15-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt`
around lines 12 - 14, 동일 서브시스템에 변환 로직과 웹 계약을 검증하는 테스트가 누락되었습니다.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SaveAcademicRecordRequest.kt#L12-L14에는
누락 값, 두 입력 이름이 모두 제공된 충돌 값의 거부, 각 단일 입력의 정상 처리를 검증하는 테스트를 추가하십시오.
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/common/ResponseMapper.kt#L15-L40에는
결과 객체의 모든 필드가 응답 DTO에 보존되는 테스트를,
systems/application/application-adapter-in/src/main/kotlin/hs/kr/entrydsm/application/adapterin/web/dto/request/SubjectGradesRequest.kt#L15-L24에는
일곱 과목 등급이 대응하는 도메인 과목 필드로 정확히 매핑되는 테스트를 추가하십시오. 웹 계층 테스트에서는 JSON 요청 역직렬화와 HTTP
응답 계약도 검증하십시오.
Sources: Coding guidelines, Path instructions
| class ScoreCalculator { | ||
| fun calculate(applicant: Applicant): Map<String, Double> { | ||
| val record = applicant.academicRecord ?: return mapOf( | ||
| "REGULAR" to EMPTY_SCORE, | ||
| "SOCIAL" to EMPTY_SCORE, | ||
| "MEISTER" to EMPTY_SCORE, | ||
| ) | ||
|
|
||
| val gedScores = record.gedScores | ||
| val baseSubjectScore = if (gedScores != null) { | ||
| calculateGedBaseScore(gedScores) | ||
| } else { | ||
| calculateSchoolBaseScore(record, applicant.graduationType) | ||
| } | ||
|
|
||
| val attendanceScore = calculateAttendanceScore(record) | ||
| val volunteerScore = calculateVolunteerScore(record.volunteerTime) | ||
| val regularAdditionalScore = calculateRegularAdditionalScore(record) | ||
| val specialAdditionalScore = calculateSpecialAdditionalScore(record) | ||
|
|
||
| val regularScore = calculateTotalScore( | ||
| subjectScore = baseSubjectScore * REGULAR_SUBJECT_SCORE_MULTIPLIER, | ||
| attendanceScore = attendanceScore, | ||
| volunteerScore = volunteerScore, | ||
| additionalScore = regularAdditionalScore, | ||
| maxScore = REGULAR_FIRST_SCREENING_MAX_SCORE, | ||
| ) | ||
| val specialScore = calculateTotalScore( | ||
| subjectScore = baseSubjectScore, | ||
| attendanceScore = attendanceScore, | ||
| volunteerScore = volunteerScore, | ||
| additionalScore = specialAdditionalScore, | ||
| maxScore = SPECIAL_FIRST_SCREENING_MAX_SCORE, | ||
| ) | ||
|
|
||
| return mapOf( | ||
| "REGULAR" to regularScore, | ||
| "SOCIAL" to specialScore, | ||
| "MEISTER" to specialScore, | ||
| ) | ||
| } | ||
|
|
||
| private fun calculateSchoolBaseScore( | ||
| record: AcademicRecord, | ||
| graduationType: GraduationType?, | ||
| ): Double { | ||
| if (record.subjectGrades.isEmpty()) { | ||
| return EMPTY_SCORE | ||
| } | ||
|
|
||
| val semesterWeights = when (graduationType) { | ||
| GraduationType.GRADUATED -> GRADUATED_SEMESTER_WEIGHTS | ||
| else -> PROSPECTIVE_GRADUATION_SEMESTER_WEIGHTS | ||
| } | ||
| val weightedScores = semesterWeights.mapNotNull { (semester, weight) -> | ||
| record.subjectGrades[semester] | ||
| ?.let(::calculateSemesterAveragePoint) | ||
| ?.let { averagePoint -> (averagePoint / MAX_GRADE_POINT) * weight to weight } | ||
| } | ||
| if (weightedScores.isEmpty()) { | ||
| return EMPTY_SCORE | ||
| } | ||
|
|
||
| val earnedScore = weightedScores.sumOf { it.first } | ||
| val reflectedWeight = weightedScores.sumOf { it.second } | ||
| return roundToThirdDecimal(earnedScore / reflectedWeight * SPECIAL_SUBJECT_MAX_SCORE) | ||
| } | ||
|
|
||
| private fun calculateGedBaseScore(scores: GedScores): Double { | ||
| val average = listOf( | ||
| scores.koreanScore, | ||
| scores.mathScore, | ||
| scores.englishScore, | ||
| scores.scienceScore, | ||
| scores.societyScore, | ||
| scores.technologyScore, | ||
| scores.historyScore, | ||
| ).average() | ||
|
|
||
| return roundToThirdDecimal(average / PERFECT_GED_SCORE * SPECIAL_SUBJECT_MAX_SCORE) | ||
| } | ||
|
|
||
| private fun calculateSemesterAveragePoint(subjectGrades: SubjectGrades): Double { | ||
| val points = listOf( | ||
| subjectGrades.koreanGrade, | ||
| subjectGrades.mathGrade, | ||
| subjectGrades.englishGrade, | ||
| subjectGrades.scienceGrade, | ||
| subjectGrades.societyGrade, | ||
| subjectGrades.technologyGrade, | ||
| subjectGrades.historyGrade, | ||
| ).filterNot { it == SubjectGrade.X } | ||
| .map(::gradeToPoint) | ||
|
|
||
| return if (points.isEmpty()) EMPTY_SCORE else points.average() | ||
| } | ||
|
|
||
| private fun calculateAttendanceScore(record: AcademicRecord): Double { | ||
| val convertedAbsences = record.absentCount + floor( | ||
| ( | ||
| record.lateCount + | ||
| record.earlyLeaveCount + | ||
| record.classAbsenceCount | ||
| ) / ATTENDANCE_CONVERSION_UNIT.toDouble(), | ||
| ).toInt() | ||
|
|
||
| return (ATTENDANCE_MAX_SCORE - convertedAbsences).coerceAtLeast(EMPTY_SCORE) | ||
| } | ||
|
|
||
| private fun calculateVolunteerScore(volunteerTime: Int): Double { | ||
| return volunteerTime.coerceIn(0, VOLUNTEER_MAX_SCORE.toInt()).toDouble() | ||
| } | ||
|
|
||
| private fun calculateRegularAdditionalScore(record: AcademicRecord): Double { | ||
| return if (record.isDsmAlgorithmAwarded) DSM_ALGORITHM_AWARD_SCORE else EMPTY_SCORE | ||
| } | ||
|
|
||
| private fun calculateSpecialAdditionalScore(record: AcademicRecord): Double { | ||
| var score = EMPTY_SCORE | ||
| if (record.isDsmAlgorithmAwarded) { | ||
| score += DSM_ALGORITHM_AWARD_SCORE | ||
| } | ||
| if (record.isProgrammingCertified) { | ||
| score += PROGRAMMING_CERTIFICATE_SCORE | ||
| } | ||
| return score.coerceAtMost(SPECIAL_ADDITIONAL_MAX_SCORE) | ||
| } | ||
|
|
||
| private fun calculateTotalScore( | ||
| subjectScore: Double, | ||
| attendanceScore: Double, | ||
| volunteerScore: Double, | ||
| additionalScore: Double, | ||
| maxScore: Double, | ||
| ): Double { | ||
| return roundToThirdDecimal( | ||
| (subjectScore + attendanceScore + volunteerScore + additionalScore) | ||
| .coerceIn(EMPTY_SCORE, maxScore), | ||
| ) | ||
| } | ||
|
|
||
| private fun gradeToPoint(grade: SubjectGrade): Double { | ||
| return when (grade) { | ||
| SubjectGrade.A -> 5.0 | ||
| SubjectGrade.B -> 4.0 | ||
| SubjectGrade.C -> 3.0 | ||
| SubjectGrade.D -> 2.0 | ||
| SubjectGrade.E -> 1.0 | ||
| SubjectGrade.X -> 0.0 | ||
| } | ||
| } | ||
|
|
||
| private fun roundToThirdDecimal(score: Double): Double { | ||
| return round(score * ROUNDING_SCALE) / ROUNDING_SCALE | ||
| } | ||
|
|
||
| companion object { | ||
| private const val EMPTY_SCORE = 0.0 | ||
| private const val MAX_GRADE_POINT = 5.0 | ||
| private const val PERFECT_GED_SCORE = 100.0 | ||
| private const val SPECIAL_SUBJECT_MAX_SCORE = 80.0 | ||
| private const val REGULAR_SUBJECT_SCORE_MULTIPLIER = 1.75 | ||
| private const val ATTENDANCE_MAX_SCORE = 15.0 | ||
| private const val ATTENDANCE_CONVERSION_UNIT = 3 | ||
| private const val VOLUNTEER_MAX_SCORE = 15.0 | ||
| private const val DSM_ALGORITHM_AWARD_SCORE = 3.0 | ||
| private const val PROGRAMMING_CERTIFICATE_SCORE = 6.0 | ||
| private const val SPECIAL_ADDITIONAL_MAX_SCORE = 9.0 | ||
| private const val REGULAR_FIRST_SCREENING_MAX_SCORE = 173.0 | ||
| private const val SPECIAL_FIRST_SCREENING_MAX_SCORE = 119.0 | ||
| private const val ROUNDING_SCALE = 1000.0 | ||
|
|
||
| private val PROSPECTIVE_GRADUATION_SEMESTER_WEIGHTS = linkedMapOf( | ||
| SchoolSemester.THIRD_GRADE_FIRST_SEMESTER to 40.0, | ||
| SchoolSemester.SECOND_GRADE_SECOND_SEMESTER to 20.0, | ||
| SchoolSemester.SECOND_GRADE_FIRST_SEMESTER to 20.0, | ||
| ) | ||
| private val GRADUATED_SEMESTER_WEIGHTS = linkedMapOf( | ||
| SchoolSemester.THIRD_GRADE_SECOND_SEMESTER to 20.0, | ||
| SchoolSemester.THIRD_GRADE_FIRST_SEMESTER to 20.0, | ||
| SchoolSemester.SECOND_GRADE_SECOND_SEMESTER to 20.0, | ||
| SchoolSemester.SECOND_GRADE_FIRST_SEMESTER to 20.0, | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
점수 계산과 저장 동작을 검증하는 테스트를 추가하세요. 이 PR은 점수 정책과 상태 변경을 추가하지만 같은 서브시스템의 테스트 변경이 없습니다. PR 설명의 후속 작업 계획은 테스트가 불필요한 이유가 아닙니다.
systems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.kt#L13-L197: 학력 유형, 필수 학기 누락, 출결 경계값, 가산점 상한, 반올림을 검증하는 결정적 단위 테스트를 추가하세요.systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.kt#L28-L158: 전형별 점수 저장, 성적 유형 검증, 갱신 시각 갱신을 검증하는 서비스 테스트를 추가하세요.
As per coding guidelines, "**/*.{kt,go}: If production logic is changed in Kotlin or Go files, require corresponding test updates in the same subsystem unless the PR description explicitly justifies why tests are unnecessary". As per path instructions, "Ask for deterministic tests and meaningful assertions, not only happy-path checks."
📍 Affects 2 files
systems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.kt#L13-L197(this comment)systems/application/application-application/src/main/kotlin/hs/kr/entrydsm/application/application/service/EvaluationCommandService.kt#L28-L158
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@systems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.kt`
around lines 13 - 197, Add deterministic unit tests for ScoreCalculator covering
graduation and GED scoring, missing required semesters, attendance boundary
values, additional-score caps, and rounding with meaningful assertions. Add
service tests for EvaluationCommandService covering per-track score persistence,
score-type validation, and updated-timestamp changes; apply the requested test
changes to both affected subsystem files.
Sources: Coding guidelines, Path instructions
| val weightedScores = semesterWeights.mapNotNull { (semester, weight) -> | ||
| record.subjectGrades[semester] | ||
| ?.let(::calculateSemesterAveragePoint) | ||
| ?.let { averagePoint -> (averagePoint / MAX_GRADE_POINT) * weight to weight } | ||
| } | ||
| if (weightedScores.isEmpty()) { | ||
| return EMPTY_SCORE | ||
| } | ||
|
|
||
| val earnedScore = weightedScores.sumOf { it.first } | ||
| val reflectedWeight = weightedScores.sumOf { it.second } | ||
| return roundToThirdDecimal(earnedScore / reflectedWeight * SPECIAL_SUBJECT_MAX_SCORE) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
필수 학기를 모두 반영하기 전에는 점수를 계산하지 마세요.
현재 코드는 없는 학기를 mapNotNull로 제외하고 reflectedWeight도 함께 줄입니다. 따라서 3학년 1학기 성적만 있어도 해당 학기의 높은 성적으로 과목 점수 80점을 받을 수 있습니다.
필수 학기 성적의 존재를 검증하세요. 성적이 불완전하면 계산을 거부하거나 미완료 상태를 반환하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@systems/application/application-domain/src/main/kotlin/hs/kr/entrydsm/application/domain/service/ScoreCalculator.kt`
around lines 67 - 78, Update the score calculation around semesterWeights and
weightedScores in ScoreCalculator so every required semester has a subject grade
before calculating a score. If any required semester is missing, return the
existing incomplete/empty result instead of excluding it and normalizing by
reflectedWeight; only perform the weighted calculation when all required
semesters are present.
91fbb11 to
01148a2
Compare
c11b860 to
7469534
Compare
Summary
원서작성 및 성적산출 기능의 MySQL JPA 저장소를 구성했습니다.
ERD 기준으로 applicants, middle_school_infos, academic_records, subject_grades, ged_scores, pass_results entity를 분리했습니다.
Spring Data repository와 ApplicantRepository persistence adapter를 추가했습니다.
Related Issue
Related to #24
Scope
In scope:
Out of scope:
Implementation
데이터 모델링 기준에 맞춰 지원자, 중학교 정보, 생활기록/성적, 검정고시 성적, 합격 결과를 별도 entity로 분리했습니다.
SubjectGrade와 PassResult는 복합키를 사용해 ERD의 PK 구조를 반영했습니다.
ApplicantPersistenceAdapter는 application 계층의 ApplicantRepository port를 구현합니다.
지원자 생성, 조회, 수정, 성적 정보 저장 흐름을 JPA repository로 처리합니다.
Testing
Deployment Notes
Feature flag: 없음
Migration required: 예, application DB schema 필요
Rollout considerations:
Checklist