btsk-115: fix all error - #148
Conversation
chore : 초기 환경설정 (btsk-1)
```
com.pullit
├─ boot/ # 애플리케이션 부트스트랩 및 설정
│ ├─ PullitApplication.java # 메인 애플리케이션 클래스
│ ├─ properties/ # 애플리케이션 설정 프로퍼티
│ │ ├─ AppProps.java # 애플리케이션 공통 설정
│ │ └─ SecurityProps.java # 보안 관련 설정
│
├─ shared/ # 도메인 무관 공통 (작고 순수하게)
│ ├─ error/ # 에러 처리 관련 클래스들
│ │ ├─ ApiErrorResponse.java # API 에러 응답 포맷
│ │ ├─ ErrorCode.java # 애플리케이션 에러 코드 정의
│ │ └─ GlobalExceptionAdvice.java # 글로벌 예외 처리
│ ├─ jpa/ # JPA 관련 공통 컴포넌트
│ │ ├─ AuditingConfig.java # JPA 감사(Auditing) 설정
│ │ └─ BaseEntity.java # 엔티티 기본 클래스
│ ├─ types/ # 값 객체(Value Object) 타입들
│ │ └─ YearWeek.java # 연도-주차 값 객체
│
├─ platform/ # 크로스컷팅 관심사 (도메인 독립적)
│ ├─ security/ # 애플리케이션 보안 설정
│ │ ├─ config/ # 보안 설정 클래스들
│ │ │ └─ SecurityConfig.java # Spring Security 메인 설정
│ │ ├─ jwt/ # JWT 토큰 처리
│ │ │ ├─ JwtAuthenticationFilter.java # JWT 인증 필터
│ │ │ └─ JwtTokenProvider.java # JWT 토큰 생성/검증
│ │ ├─ handler/ # 보안 예외 처리 핸들러
│ │ │ ├─ RestAuthenticationEntryPoint.java # 인증 실패 처리
│ │ │ └─ RestAccessDeniedHandler.java # 접근 거부 처리
│ │ └─ principal/ # 사용자 인증 정보
│ │ └─ AuthUserPrincipal.java # 인증된 사용자 정보
│ ├─ storage/ # 파일 스토리지 시스템
│ │ ├─ core/ # 스토리지 핵심 인터페이스
│ │ │ ├─ FileStorage.java # 파일 스토리지 인터페이스
│ │ │ ├─ FilePathPolicy.java # 파일 경로 정책
│ │ │ ├─ FileValidation.java # 파일 유효성 검증
│ │ │ └─ StorageProps.java # 스토리지 설정
│ │ ├─ local/ # 로컬 파일 시스템 스토리지
│ │ │ └─ LocalFileStorage.java # 로컬 파일 저장 구현
│ │ └─ s3/ # AWS S3 스토리지
│ │ ├─ S3FileStorage.java # S3 파일 저장 구현
│ │ └─ S3PresignedUrlService.java # S3 사전 서명 URL
│ ├─ docs/ # API 문서화 설정
│ │ └─ OpenApiConfig.java # OpenAPI/Swagger 설정
│ └─ web/ # 웹 계층 공통 설정
│ └─ WebConfig.java # 웹 MVC 설정
│
└─ modules/ # 도메인별 비즈니스 모듈
├─ member/ # 회원 도메인
│ ├─ api/ # 회원 도메인 공개 인터페이스
│ │ └─ MemberPublicApi.java # 회원 관련 공개 API
│ ├─ web/ # 회원 웹 계층
│ │ └─ MemberController.java # 회원 REST 컨트롤러
│ ├─ service/ # 회원 비즈니스 로직
│ │ └─ MemberService.java # 회원 서비스
│ ├─ repository/ # 회원 데이터 접근
│ │ ├─ MemberRepository.java # 회원 리포지토리 인터페이스
│ │ └─ adapter/jpa/ # JPA 어댑터
│ │ └─ MemberJpaRepository.java # JPA 회원 리포지토리
│ └─ domain/ # 회원 도메인 모델
│ └─ entity/Member.java # 회원 엔티티
│
├─ learningsource/ # 학습 소스 관련 모듈
│ ├─ source/ # 학습 소스 도메인
│ │ ├─ api/ # 학습 소스 공개 API
│ │ │ └─ SourcePublicApi.java
│ │ ├─ web/ # 학습 소스 웹 계층
│ │ │ └─ SourceController.java
│ │ ├─ service/ # 학습 소스 비즈니스 로직
│ │ │ └─ SourceService.java
│ │ ├─ repository/ # 학습 소스 데이터 접근
│ │ │ ├─ SourceRepository.java
│ │ │ ├─ SourceRepositoryImpl.java
│ │ │ └─ adapter/jpa/
│ │ │ └─ SourceJpaRepository.java
│ │ └─ domain/ # 학습 소스 도메인 모델
│ │ └─ entity/Source.java
│ │
│ └─ sourcefolder/ # 학습 소스 폴더 도메인
│ ├─ api/ # 폴더 공개 API
│ │ └─ SourceFolderPublicApi.java
│ ├─ web/ # 폴더 웹 계층
│ │ └─ SourceFolderController.java
│ ├─ service/ # 폴더 비즈니스 로직
│ │ └─ SourceFolderService.java
│ ├─ repository/ # 폴더 데이터 접근
│ │ ├─ SourceFolderRepository.java
│ │ ├─ SourceFolderRepositoryImpl.java
│ │ └─ adapter/jpa/
│ │ └─ LearningSourceFolderJpaRepository.java
│ └─ domain/ # 폴더 도메인 모델
│ └─ entity/SourceFolder.java
│
├─ questionset/ # 문제집 도메인
│ ├─ api/ # 문제집 공개 API
│ │ └─ QuestionSetPublicApi.java
│ ├─ web/ # 문제집 웹 계층
│ │ └─ QuestionSetController.java
│ ├─ service/ # 문제집 비즈니스 로직
│ │ ├─ QuestionSetService.java
│ │ └─ QuestionGenerationService.java
│ ├─ repository/ # 문제집 데이터 접근
│ │ ├─ QuestionSetRepository.java
│ │ ├─ QuestionRepository.java
│ │ ├─ QuestionSetSourceLinkRepository.java
│ │ └─ adapter/jpa/
│ │ ├─ QuestionJpaRepository.java
│ │ ├─ QuestionSetJpaRepository.java
│ │ └─ QuestionSetSourceLinkJpaRepository.java
│ └─ domain/ # 문제집 도메인 모델
│ ├─ entity/ # 엔티티들
│ │ ├─ Question.java
│ │ ├─ QuestionSet.java
│ │ └─ QuestionSetSourceLink.java
│ ├─ enums/ # 열거형들
│ │ ├─ DifficultyType.java
│ │ ├─ PublishStatus.java
│ │ ├─ QuestionType.java
│ │ └─ VisibilityScope.java
│ └─ policy/ # 비즈니스 정책 (빈 폴더)
│
├─ session/ # 스터디 세션 도메인
│ ├─ api/ # 세션 공개 API
│ │ └─ SessionPublicApi.java
│ ├─ web/ # 세션 웹 계층
│ │ └─ StudySessionController.java
│ ├─ service/ # 세션 비즈니스 로직
│ │ ├─ StudySessionService.java
│ │ └─ ScoringService.java
│ ├─ repository/ # 세션 데이터 접근
│ │ ├─ StudySessionRepository.java
│ │ └─ adapter/jpa/
│ │ └─ StudySessionJpaRepository.java
│ └─ domain/ # 세션 도메인 모델
│ ├─ entity/ # 엔티티
│ │ └─ StudySession.java
│ ├─ events/ # 도메인 이벤트
│ │ └─ StudySessionCompleted.java
│ └─ model/ # 도메인 모델
│ └─ SessionItemPayload.java
│
├─ wronganswer/ # 오답 노트 도메인
│ ├─ api/ # 오답 공개 API
│ │ └─ WrongAnswerPublicApi.java
│ ├─ web/ # 오답 웹 계층
│ │ └─ WrongAnswerController.java
│ ├─ service/ # 오답 비즈니스 로직
│ │ └─ WrongAnswerService.java
│ ├─ repository/ # 오답 데이터 접근
│ │ ├─ WrongAnswerRepository.java
│ │ └─ adapter/jpa/
│ │ └─ WrongAnswerJpaRepository.java
│ └─ domain/ # 오답 도메인 모델
│ └─ entity/WrongAnswer.java
│
├─ projection/ # 읽기 전용 프로젝션 도메인
│ ├─ userdailystats/ # 사용자 일별 통계 하위 도메인
│ │ ├─ api/
│ │ │ └─ UserDailyStatsPublicApi.java
│ │ ├─ domain/
│ │ │ └─ readmodel/UserDailyStats.java
│ │ ├─ repository/
│ │ │ └─ UserDailyStatsRepository.java
│ │ └─ service/
│ │ └─ UserDailyStatsService.java
│ │
│ ├─ userstreak/ # 사용자 스트릭 하위 도메인
│ │ ├─ api/
│ │ │ └─ UserStreakPublicApi.java
│ │ ├─ domain/
│ │ │ └─ readmodel/UserStreak.java
│ │ ├─ repository/
│ │ │ └─ UserStreakRepository.java
│ │ └─ service/
│ │ └─ UserStreakService.java
│ │
│ ├─ questionsetdailystats/ # 문제집 일별 통계 하위 도메인
│ │ ├─ api/
│ │ │ └─ QuestionSetDailyStatsPublicApi.java
│ │ ├─ domain/
│ │ │ └─ readmodel/QuestionSetDailyStats.java
│ │ ├─ repository/
│ │ │ └─ QuestionSetDailyStatsRepository.java
│ │ └─ service/
│ │ └─ QuestionSetDailyStatsService.java
│ │
│ ├─ userquestionsetsummary/ # 사용자 문제집 요약 하위 도메인
│ │ ├─ api/
│ │ │ └─ UserQuestionSetSummaryPublicApi.java
│ │ ├─ domain/
│ │ │ └─ readmodel/UserQuestionSetSummary.java
│ │ ├─ repository/
│ │ │ └─ UserQuestionSetSummaryRepository.java
│ │ └─ service/
│ │ └─ UserQuestionSetSummaryService.java
│ │
│ ├─ web/ # 프로젝션 웹 계층
│ │ └─ DashboardQueryController.java
│ ├─ domain/ # 프로젝션 도메인 모델
│ │ └─ mapper/ProjectionMappers.java
│ └─ listener/ # 이벤트 리스너
│ └─ StudySessionCompletedListener.java
│
└─ auth/ # 인증/인가 도메인
├─ web/ # 인증 웹 계층
│ └─ KakaoAuthController.java
├─ service/ # 인증 비즈니스 로직
│ └─ KakaoAuthService.java
└─ client/ # 외부 클라이언트
└─ KakaoOAuthClient.java
```
환경 설정에 대해 자세한건
DOCS_application.yml.md
DOCS_build.gradle.md
읽어주세요.
feat : qa서버 배포 스크립트 작성. 일단 ci 미구축
* Feat: 운영/QA/로컬 환경 분리 및 기본 CORS 설정 도입(btsk-2) - application-prod.yml, application-qa.yml 추가: 운영 및 QA 환경 설정 파일 생성. - WebCorsProps 추가 및 WebConfig 수정: CORS 설정을 별도 프로퍼티로 관리하여 환경별 Allowed Origins 정의. - SecurityConfig 개선: no-auth 프로필 추가로 인증이 필요한/불필요한 보안 체인 분리. 운영, QA, 로컬 환경의 분리를 위한 설정 파일을 각각 추가 SecurityConfig 내 no-auth 프로필을 도입하여 테스트 환경에서 인증 허용 범위를 쉽게 조정할 수 있도록 했음. - `application-prod.yml`에 운영 프론트엔드 도메인 추가 - https://www.pull.it.kr - https://pull.it.kr - `application-qa.yml`에 QA 및 로컬 개발 도메인 추가 - https://qa.pull.it.kr - http://local.pull.it.kr:3000 (hosts 파일 설정 연동) Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: 운영/QA/로컬 환경 분리 및 기본 CORS 설정 도입(btsk-2) - application-prod.yml, application-qa.yml 추가: 운영 및 QA 환경 설정 파일 생성. - WebCorsProps 추가 및 WebConfig 수정: CORS 설정을 별도 프로퍼티로 관리하여 환경별 Allowed Origins 정의. - SecurityConfig 개선: no-auth 프로필 추가로 인증이 필요한/불필요한 보안 체인 분리. 운영, QA, 로컬 환경의 분리를 위한 설정 파일을 각각 추가 SecurityConfig 내 no-auth 프로필을 도입하여 테스트 환경에서 인증 허용 범위를 쉽게 조정할 수 있도록 했음. - `application-prod.yml`에 운영 프론트엔드 도메인 추가 - https://www.pull.it.kr - https://pull.it.kr - `application-qa.yml`에 QA 및 로컬 개발 도메인 추가 - https://qa.pull.it.kr - http://local.pull.it.kr:3000 (hosts 파일 설정 연동) Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> --------- Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* chore: codestyle 및 spotless 세팅 * chore: +x 권한 부여 * style: lint init * merge
* feat: 경고0개 및 경고를 에러 취급 * chore: linter and formatter 설정 - main, develop으로 push, pr시 동작함 - jdk는 corretto, 버전은 21
Feat: 운영 환경용 Docker Compose 및 QA 배포 스크립트 업데이트 - docker-compose.prod.yml 추가: 운영 환경 구성 설정 - deploy-qa.sh 개선: Docker Compose 명령어 표기법 수정 및 배포 명령어 출력 내용 보완. - docker-compose.qa.yml 이미지 경로 수정: 잘못된 이미지 경로였음 DOCKER_REGISTRY를 hyeonjun/pullit-qa로 해놓을 것이기 때문에 수정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* fix: job id명 변경 * chore: pr title명 확인 workflow * docs: pr template 변경
* docs: update README.md * fix: checkstyle 수정 * docs: checkstyle 및 google java format 설정법
fix: pr-title-check 수정
* Feat: Resilience4j 기반 API Rate Limiting 및 CORS 정책 강화 - build.gradle 수정: Resilience4j 및 AOP 의존성 추가. - application.yml 및 application-qa.yml 수정: Rate Limiting, CORS 기본 설정 추가(max-age-seconds 등). qa 서버는 저희 외에는 사용하지 말아야 합니다. 그래서 총 5명의 팀원이 1분에 500번정도 api 호출하는 정도로 허용하였습니다. 그 이상이라면 무언가 잘못이 있는거로 판단하기 위해 설정해보았습니다! - HomeController에 echo API 추가: POST 요청 데이터 반환 테스트용. - SecurityConfig 변경: QA 환경에서 no-auth Profile과 통합, API 보안 설정 수정. - WebConfig, WebCorsProps 수정: CORS 설정 시간 프로퍼티 추가 및 적용. Rate Limiting 적용을 통해 API 요청 과부하를 방지 CORS 정책 설정 QA 환경에서 테스트를 위해 보안 제거. 개발/운영 환경 간 설정 충돌을 방지하도록 구성. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: 코드 스타일 컨벤션에 맞게 수정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> --------- Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* feat: 문제집 getById 구현 * refactor: QuestionRepository jpa 의존 수정 * docs: 모호한 필드 주석 추가 * fix: Date를 LocalDateTime 으로 변경 * fix(QuestioinSetService): Transactional 추가 * fix(QuestionSetDto): Date -> LocalDateTime (createTime)
Feat: 카카오 OAuth 2.0 인증 연동 초기 구현 - KakaoProps 추가: 카카오 OAuth 설정(clientId, secret, redirectUri 등) 관리. - KakaoUrlBuilder 추가: 카카오 인증 URL 생성 기능 구현. - KakaoAuthController 추가: 인증 요청 처리 엔드포인트(/oauth/authorize/kakao) 제공. - KakaoAuthService 추가: 인증 URL 빌드 로직 분리. - kakaoRestClient 등록: 카카오 API 호출을 위한 RestClient 설정. - AppProps 및 application.yml 수정: app.base-url 설정 추가. 앱의 base-url 설정을 위함. - DB 설정 변경: datasource URL과 사용자 정보 수정, Hibernate 개발 편의성을 위해 ddl-auto create-drop으로 설정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* Feat: 카카오 OAuth 2.0 인증 연동 초기 구현 - KakaoProps 추가: 카카오 OAuth 설정(clientId, secret, redirectUri 등) 관리. - KakaoUrlBuilder 추가: 카카오 인증 URL 생성 기능 구현. - KakaoAuthController 추가: 인증 요청 처리 엔드포인트(/oauth/authorize/kakao) 제공. - KakaoAuthService 추가: 인증 URL 빌드 로직 분리. - kakaoRestClient 등록: 카카오 API 호출을 위한 RestClient 설정. - AppProps 및 application.yml 수정: app.base-url 설정 추가. 앱의 base-url 설정을 위함. - DB 설정 변경: datasource URL과 사용자 정보 수정, Hibernate 개발 편의성을 위해 ddl-auto create-drop으로 설정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: Testcontainers 기반 통합 테스트 환경 및 Member 엔티티 추가 - Testcontainers 환경 설정: MariaDB 컨테이너 도입 및 H2 기반 테스트 환경 분리. - Member 모듈 업데이트: Member 엔티티, 상태(enum), JPA 및 커스텀 레포지토리 구현. - BaseEntity 적용: 공통 생성/수정일 자동 관리. - 간단한 통합 테스트(Member 저장/조회) 및 컨트롤러 테스트 추가. 테스트 환경 통합 Testcontainers를 활용하여 MariaDB 컨테이너 기반 테스트 환경을 구축하였으며, 안정적인 통합 테스트와 단위 테스트를 위해 H2 환경도 병렬적으로 설정했음. 신규 도메인 추가와 함께 Repository, Service, Controller 검증 Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor : 코드스타일 수정 * Refactor:build.gradle 로그 에러 해결 * Refactor: 환경설정 윈도우 자바 <-> 도커환경으로 인해 생기는 로그 숨김 * Chore: JDK 버전 21 - build.gradle 파일 내 JavaLanguageVersion 설정을 17에서 21로 변경. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: merge 충돌로 인한 application.yml 불필요 코드 제거 - application.yml 내 불필요한 충돌 관련 잔여 코드 삭제. - CORS `max-age-seconds` 설정 유지. merge 과정에서 발생한 불필요한 충돌 잔여 코드를 정리하여 설정 파일을 정상화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: 필요없는 파일 제거 * Refactor:깃이그노어추가 --------- Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* chore: swagger local setting 현재 http://localhost:8080/swagger-ui/index.html#/ 로 접속해야 보이고, https://api-qa.pull.it.kr 로 연결을 실패했습니다.. * Refactor:코드스타일 --------- Co-authored-by: 최현준 <osumaniaddict527@gmail.com>
* Feat: 카카오 OAuth 2.0 인증 연동 초기 구현 - KakaoProps 추가: 카카오 OAuth 설정(clientId, secret, redirectUri 등) 관리. - KakaoUrlBuilder 추가: 카카오 인증 URL 생성 기능 구현. - KakaoAuthController 추가: 인증 요청 처리 엔드포인트(/oauth/authorize/kakao) 제공. - KakaoAuthService 추가: 인증 URL 빌드 로직 분리. - kakaoRestClient 등록: 카카오 API 호출을 위한 RestClient 설정. - AppProps 및 application.yml 수정: app.base-url 설정 추가. 앱의 base-url 설정을 위함. - DB 설정 변경: datasource URL과 사용자 정보 수정, Hibernate 개발 편의성을 위해 ddl-auto create-drop으로 설정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: Testcontainers 기반 통합 테스트 환경 및 Member 엔티티 추가 - Testcontainers 환경 설정: MariaDB 컨테이너 도입 및 H2 기반 테스트 환경 분리. - Member 모듈 업데이트: Member 엔티티, 상태(enum), JPA 및 커스텀 레포지토리 구현. - BaseEntity 적용: 공통 생성/수정일 자동 관리. - 간단한 통합 테스트(Member 저장/조회) 및 컨트롤러 테스트 추가. 테스트 환경 통합 Testcontainers를 활용하여 MariaDB 컨테이너 기반 테스트 환경을 구축하였으며, 안정적인 통합 테스트와 단위 테스트를 위해 H2 환경도 병렬적으로 설정했음. 신규 도메인 추가와 함께 Repository, Service, Controller 검증 Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor : 코드스타일 수정 * Refactor : 머지컨플릭트 해결 * Refactor : 깃 이그노어 추가 * Feat: 소스 레퍼지토리 구현 Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: S3 파일 스토리지 클라이언트 및 설정 추가 - FileStorageClient 인터페이스 및 S3FileStorageClientManagingClient 구현체 추가: S3 presigned URL 생성, 파일 존재 여부 확인, 삭제 등 기능 구현. - AWS SDK(S3, Auth) 의존성 추가. - QA 및 테스트 환경의 S3 스토리지 관련 설정(application-qa.yml, application-testcontainers.yml) 추가 및 수정. AWS S3 통합 S3를 사용한 파일 업로드/관리 기능을 구현함. presigned URL을 사용하는 업로드 로직과 파일 삭제, 파일 존재 여부 확인을 위한 메서드를 포함하고 있음. 관련 설정값은 YML 파일을 통해 관리되며, 클라이언트는 Spring Component 기반으로 등록되어 다른 서비스에서 활용 가능하도록 설정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: S3 Pre-signed URL 생성 로직 및 파일 검증/경로 생성 처리 추가 - S3PresignedUrlService: 파일 검증, 경로 생성, Pre-signed URL 생성 서비스 구현. - FileValidation: PDF 파일 확장자, 크기, 타입 검증 로직 추가. - FilePathPolicy: 날짜 기반 폴더 구조와 UUID 파일명 생성 로직 추가. - PresignedUrlResponse: Pre-signed URL 응답 데이터 객체 추가. - S3PublicApi: S3 관련 공용 API 인터페이스 정의. S3 파일 업로드를 위한 Pre-signed URL 생성 기능을 추가하였음. 사용자가 업로드 요청 시 파일 경로를 생성하고, 입력 파일의 유효성을 검증한 뒤 사전 서명된 URL을 생성하여 반환하도록 구현했음. 이 서비스는 PDF 파일만 허용하며 최대 50MB 크기 제한을 적용함. 날짜별 폴더 구조와 고유 파일명을 사용하여 충돌을 방지함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: Presigned URL 생성 로직 추가 및 API 구현 - SourcePublicApi 메서드 추가: Presigned URL 생성을 위한 generateUploadUrl 메서드 정의. - SourceController 구현: /api/learning/source/upload 엔드포인트를 통해 Presigned URL 반환. - SourceService 구현: S3 API를 활용해 Presigned URL 생성 및 파일 경로 반환. - SourceJpaRepository 업데이트: memberId 기준 데이터 조회 메서드 추가. 학습 리소스를 업로드할 때 사용자가 파일을 올릴 수 있는 Presigned URL을 반환하는 기능을 추가. 이를 통해 사용자는 클라이언트에서 S3로 직접 파일 업로드를 수행 가능. 해당 엔드포인트는 SourceController를 통해 제공되며, 내부 서비스 로직은 S3 API를 활용해 구현됨. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat : 이미지 업로드(에러상태) * Refactor:build.gradle 로그 에러 해결 * Refactor: 환경설정 윈도우 자바 <-> 도커환경으로 인해 생기는 로그 숨김 * Chore: JDK 버전 21 - build.gradle 파일 내 JavaLanguageVersion 설정을 17에서 21로 변경. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: merge 충돌로 인한 application.yml 불필요 코드 제거 - application.yml 내 불필요한 충돌 관련 잔여 코드 삭제. - CORS `max-age-seconds` 설정 유지. merge 과정에서 발생한 불필요한 충돌 잔여 코드를 정리하여 설정 파일을 정상화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor: 호환성 맞지 않는 문제 해결 * Fix: 필요없는 파일 제거 * Refactor:깃이그노어추가 * Refactor: H2 기반 테스트 환경 제거 및 Testcontainers로 통합 - H2 관련 설정 및 테스트 클래스 제거: application-h2.yml, H2IntegrationTest, H2Test 등 삭제. - Testcontainers 관련 테스트 리팩토링: @DirtiesContext 추가, MariaDBContainer 재사용 설정 적용. H2 환경을 제거하고 Testcontainers를 기반으로 한 통합 테스트 환경으로 일원화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: PresignedUrlResponse 메서드 변경에 따른 필드 접근 수정 - PresignedUrlResponse 사용 시 변경된 메서드 방식(uploadUrl(), filePath())에 맞게 수정. 기존 getter 방식에서 기록된 메서드명 변경으로 인한 수정 작업. 이는 코드 실행 시 올바른 값 반환을 보장함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor: PresignedUrlResponse 불필요한 공백 제거 - 코드 가독성을 위해 불필요한 공백 라인 수정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor:깃이그노어에 불필요한 것 제거 --------- Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* Feat: 카카오 OAuth 2.0 인증 연동 초기 구현 - KakaoProps 추가: 카카오 OAuth 설정(clientId, secret, redirectUri 등) 관리. - KakaoUrlBuilder 추가: 카카오 인증 URL 생성 기능 구현. - KakaoAuthController 추가: 인증 요청 처리 엔드포인트(/oauth/authorize/kakao) 제공. - KakaoAuthService 추가: 인증 URL 빌드 로직 분리. - kakaoRestClient 등록: 카카오 API 호출을 위한 RestClient 설정. - AppProps 및 application.yml 수정: app.base-url 설정 추가. 앱의 base-url 설정을 위함. - DB 설정 변경: datasource URL과 사용자 정보 수정, Hibernate 개발 편의성을 위해 ddl-auto create-drop으로 설정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: Testcontainers 기반 통합 테스트 환경 및 Member 엔티티 추가 - Testcontainers 환경 설정: MariaDB 컨테이너 도입 및 H2 기반 테스트 환경 분리. - Member 모듈 업데이트: Member 엔티티, 상태(enum), JPA 및 커스텀 레포지토리 구현. - BaseEntity 적용: 공통 생성/수정일 자동 관리. - 간단한 통합 테스트(Member 저장/조회) 및 컨트롤러 테스트 추가. 테스트 환경 통합 Testcontainers를 활용하여 MariaDB 컨테이너 기반 테스트 환경을 구축하였으며, 안정적인 통합 테스트와 단위 테스트를 위해 H2 환경도 병렬적으로 설정했음. 신규 도메인 추가와 함께 Repository, Service, Controller 검증 Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor : 코드스타일 수정 * Refactor : 머지컨플릭트 해결 * Refactor : 깃 이그노어 추가 * Feat: 소스 레퍼지토리 구현 Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: S3 파일 스토리지 클라이언트 및 설정 추가 - FileStorageClient 인터페이스 및 S3FileStorageClientManagingClient 구현체 추가: S3 presigned URL 생성, 파일 존재 여부 확인, 삭제 등 기능 구현. - AWS SDK(S3, Auth) 의존성 추가. - QA 및 테스트 환경의 S3 스토리지 관련 설정(application-qa.yml, application-testcontainers.yml) 추가 및 수정. AWS S3 통합 S3를 사용한 파일 업로드/관리 기능을 구현함. presigned URL을 사용하는 업로드 로직과 파일 삭제, 파일 존재 여부 확인을 위한 메서드를 포함하고 있음. 관련 설정값은 YML 파일을 통해 관리되며, 클라이언트는 Spring Component 기반으로 등록되어 다른 서비스에서 활용 가능하도록 설정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: S3 Pre-signed URL 생성 로직 및 파일 검증/경로 생성 처리 추가 - S3PresignedUrlService: 파일 검증, 경로 생성, Pre-signed URL 생성 서비스 구현. - FileValidation: PDF 파일 확장자, 크기, 타입 검증 로직 추가. - FilePathPolicy: 날짜 기반 폴더 구조와 UUID 파일명 생성 로직 추가. - PresignedUrlResponse: Pre-signed URL 응답 데이터 객체 추가. - S3PublicApi: S3 관련 공용 API 인터페이스 정의. S3 파일 업로드를 위한 Pre-signed URL 생성 기능을 추가하였음. 사용자가 업로드 요청 시 파일 경로를 생성하고, 입력 파일의 유효성을 검증한 뒤 사전 서명된 URL을 생성하여 반환하도록 구현했음. 이 서비스는 PDF 파일만 허용하며 최대 50MB 크기 제한을 적용함. 날짜별 폴더 구조와 고유 파일명을 사용하여 충돌을 방지함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat: Presigned URL 생성 로직 추가 및 API 구현 - SourcePublicApi 메서드 추가: Presigned URL 생성을 위한 generateUploadUrl 메서드 정의. - SourceController 구현: /api/learning/source/upload 엔드포인트를 통해 Presigned URL 반환. - SourceService 구현: S3 API를 활용해 Presigned URL 생성 및 파일 경로 반환. - SourceJpaRepository 업데이트: memberId 기준 데이터 조회 메서드 추가. 학습 리소스를 업로드할 때 사용자가 파일을 올릴 수 있는 Presigned URL을 반환하는 기능을 추가. 이를 통해 사용자는 클라이언트에서 S3로 직접 파일 업로드를 수행 가능. 해당 엔드포인트는 SourceController를 통해 제공되며, 내부 서비스 로직은 S3 API를 활용해 구현됨. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Feat : 이미지 업로드(에러상태) * Refactor:build.gradle 로그 에러 해결 * Refactor: 환경설정 윈도우 자바 <-> 도커환경으로 인해 생기는 로그 숨김 * Chore: JDK 버전 21 - build.gradle 파일 내 JavaLanguageVersion 설정을 17에서 21로 변경. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: merge 충돌로 인한 application.yml 불필요 코드 제거 - application.yml 내 불필요한 충돌 관련 잔여 코드 삭제. - CORS `max-age-seconds` 설정 유지. merge 과정에서 발생한 불필요한 충돌 잔여 코드를 정리하여 설정 파일을 정상화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor: 호환성 맞지 않는 문제 해결 * Fix: 필요없는 파일 제거 * Refactor:깃이그노어추가 * Refactor: H2 기반 테스트 환경 제거 및 Testcontainers로 통합 - H2 관련 설정 및 테스트 클래스 제거: application-h2.yml, H2IntegrationTest, H2Test 등 삭제. - Testcontainers 관련 테스트 리팩토링: @DirtiesContext 추가, MariaDBContainer 재사용 설정 적용. H2 환경을 제거하고 Testcontainers를 기반으로 한 통합 테스트 환경으로 일원화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: PresignedUrlResponse 메서드 변경에 따른 필드 접근 수정 - PresignedUrlResponse 사용 시 변경된 메서드 방식(uploadUrl(), filePath())에 맞게 수정. 기존 getter 방식에서 기록된 메서드명 변경으로 인한 수정 작업. 이는 코드 실행 시 올바른 값 반환을 보장함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor: PresignedUrlResponse 불필요한 공백 제거 - 코드 가독성을 위해 불필요한 공백 라인 수정. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor:깃이그노어에 불필요한 것 제거 * Refactor:필요없는 파일 제거 * Refactor : 머지컨플릭트 해결 * Feat : 이미지 업로드(에러상태) * Refactor:build.gradle 로그 에러 해결 * Refactor: 환경설정 윈도우 자바 <-> 도커환경으로 인해 생기는 로그 숨김 * Chore: JDK 버전 21 - build.gradle 파일 내 JavaLanguageVersion 설정을 17에서 21로 변경. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: merge 충돌로 인한 application.yml 불필요 코드 제거 - application.yml 내 불필요한 충돌 관련 잔여 코드 삭제. - CORS `max-age-seconds` 설정 유지. merge 과정에서 발생한 불필요한 충돌 잔여 코드를 정리하여 설정 파일을 정상화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Refactor: 호환성 맞지 않는 문제 해결 * Refactor: H2 기반 테스트 환경 제거 및 Testcontainers로 통합 - H2 관련 설정 및 테스트 클래스 제거: application-h2.yml, H2IntegrationTest, H2Test 등 삭제. - Testcontainers 관련 테스트 리팩토링: @DirtiesContext 추가, MariaDBContainer 재사용 설정 적용. H2 환경을 제거하고 Testcontainers를 기반으로 한 통합 테스트 환경으로 일원화함. Signed-off-by: HyeonJun <osumaniaddict527@gmail.com> * Fix: 필요없는 파일 제거 * Refactor:필요없는 파일 제거 --------- Signed-off-by: HyeonJun <osumaniaddict527@gmail.com>
* Chore: .gitignore에 .env 파일 추가 - 운영에서 docker compose up 시 개인 설정 파일(.env) 관리 목적. Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Chore: Dockerfile 및 QA 설정 일부 수정 - Dockerfile: amazoncorretto 이미지 경로에 구체적인 `docker.io` 추가(podman 또한 사용 가능하게 하기 위함임.) 및 타임존 데이터 패키지 추가(tzdata). Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Feat: 업로드 완료 처리 및 프로퍼티 클래스 분리 - S3StorageProps 클래스 도입: 기존 StorageProps 삭제 및 S3용 프로퍼티 클래스 분리. - SourcePublicApi 인터페이스 수정: 업로드 완료 처리 메서드(processUploadComplete) 추가. - SourceService 구현: S3 파일 유무 확인 및 업로드된 파일 정보를 저장하는 로직 추가. - Source 도메인 수정: SourceCreationParam 생성 및 팩토리 메서드(create) 추가. - UploadResponse 및 UploadCompleteRequest DTO 확장: 업로드 파일 관련 상세 정보 추가. S3 Presigned URL 기존 StorageProps 클래스의 SRP(단일 책임 원칙)를 준수하기 위해 S3StorageProps로 분리, 이를 기반으로 S3 관련 모든 설정 값 관리. 업로드 완료 이후에는 S3에 저장된 파일 유무를 확인하고 메타데이터를 DB에 보존하는 프로세스를 추가. 나아가 클라이언트에서 요청된 upload-complete 시 파일 정보 검증을 보장하도록 개선함. Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Feat: 소스 파일 관련 DTO 리팩토링 및 학습 소스 조회 기능 추가 - 기존 UploadRequest/Response, UploadCompleteRequest 삭제 및 SourceUploadRequest/Response, SourceUploadCompleteRequest로 대체: S3 Pre-signed URL 방식 업로드 프로세스에 적합한 DTO 구조로 개선. - SourcePublicApi, SourceService 수정: 새로운 DTO 적용 및 인증 사용자 소스 조회 메서드 추가(getMySources). - SourceResponse 도입: 소스 엔티티를 응답 형태로 변환하는 DTO 추가. - SourceRepository 메서드 확장: 회원별 소스 목록 정렬 조회(findByMemberIdOrderByCreatedAtDesc) 구현. - SourceController에 학습 소스 조회 엔드포인트 추가: 사용자가 업로드한 모든 소스 목록 반환. 학습 소스 업로드, 업로드 완료 처리 가능 Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Feat: 코드포맷팅 Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Refactor: 레코드로 리팩토링. Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Refactor: 코드포매팅수정 --------- Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com>
* docs: update branch flow * docs: fix typo * chore: pr title 규칙에 review 추가 * docs: Release Notes 주석처리 * chore: draft 제외
chore: add hooks (checkCode)
* Chore: .gitignore에 .env 파일 추가 - 운영에서 docker compose up 시 개인 설정 파일(.env) 관리 목적. Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Chore: Dockerfile 및 QA 설정 일부 수정 - Dockerfile: amazoncorretto 이미지 경로에 구체적인 `docker.io` 추가(podman 또한 사용 가능하게 하기 위함임.) 및 타임존 데이터 패키지 추가(tzdata). Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Feat: 업로드 완료 처리 및 프로퍼티 클래스 분리 - S3StorageProps 클래스 도입: 기존 StorageProps 삭제 및 S3용 프로퍼티 클래스 분리. - SourcePublicApi 인터페이스 수정: 업로드 완료 처리 메서드(processUploadComplete) 추가. - SourceService 구현: S3 파일 유무 확인 및 업로드된 파일 정보를 저장하는 로직 추가. - Source 도메인 수정: SourceCreationParam 생성 및 팩토리 메서드(create) 추가. - UploadResponse 및 UploadCompleteRequest DTO 확장: 업로드 파일 관련 상세 정보 추가. S3 Presigned URL 기존 StorageProps 클래스의 SRP(단일 책임 원칙)를 준수하기 위해 S3StorageProps로 분리, 이를 기반으로 S3 관련 모든 설정 값 관리. 업로드 완료 이후에는 S3에 저장된 파일 유무를 확인하고 메타데이터를 DB에 보존하는 프로세스를 추가. 나아가 클라이언트에서 요청된 upload-complete 시 파일 정보 검증을 보장하도록 개선함. Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Feat: 소스 파일 관련 DTO 리팩토링 및 학습 소스 조회 기능 추가 - 기존 UploadRequest/Response, UploadCompleteRequest 삭제 및 SourceUploadRequest/Response, SourceUploadCompleteRequest로 대체: S3 Pre-signed URL 방식 업로드 프로세스에 적합한 DTO 구조로 개선. - SourcePublicApi, SourceService 수정: 새로운 DTO 적용 및 인증 사용자 소스 조회 메서드 추가(getMySources). - SourceResponse 도입: 소스 엔티티를 응답 형태로 변환하는 DTO 추가. - SourceRepository 메서드 확장: 회원별 소스 목록 정렬 조회(findByMemberIdOrderByCreatedAtDesc) 구현. - SourceController에 학습 소스 조회 엔드포인트 추가: 사용자가 업로드한 모든 소스 목록 반환. 학습 소스 업로드, 업로드 완료 처리 가능 Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Feat: 코드포맷팅 Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Refactor: 레코드로 리팩토링. Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com> * Refactor: 코드포매팅수정 * Feat:학습소스 쪽 스웨거 api 구현 open api yml 방식으로 스웨거 제작 --------- Signed-off-by: Hyeonjun0527 <osumaniaddict527@gmail.com>
* Feat:깃업 액션 배포 ci에서 빌드, 이미지 빌드 푸시를 추가하였고 cd에서 이미지 풀 땡기는 것 추가 * Feat : ci 에 이미지 배포는 develop에만 적용되게 수정 * Refactor : 중복으로 빌드하고 있던 부분 리팩토링 * Refactor : 환경변수명 리팩토링 * feat : qa 접두사 전부 제거 github environment 사용할 예정 * Refactor: 환경변수명 리팩토링 git environment적용 로컬에서 region 환경변수 없어도 작동하도록 변경 gradle에 필요없는 의존성 제거 application.yml로 로컬에서 실행할 수 있도록변경 * Refactor: 스웨거의 의존 취약성 제거 전이 의존성 버전이 최신화 되지 않아 의존 취약성이 생겼었음. * Refactor:코드스타일변경 * Refactor: 사소한 테스트 빌드 에러 및 코드스타일수정 * fix: cicd 수정 * fix:테스트수정 * Refactor:리팩토링코드스타일
* test:테스트 * fix:러너수정
* test:테스트 * fix:러너수정 * fix:배포수정OC * fix:배포스크립트수정 * Refactor:ci와 cd동시에 수행되어 생기는 이미지 문제 해결 * Refactor:리다이렉트uri변경 * Refactor:코드스타일 * Refactor:환경변수 수정 환경변수 명칭 변경
* test:테스트 * fix:러너수정 * fix:배포수정OC * fix:배포스크립트수정 * Refactor:ci와 cd동시에 수행되어 생기는 이미지 문제 해결 * Refactor:리다이렉트uri변경 * Refactor:코드스타일 * Refactor:환경변수 수정 환경변수 명칭 변경 * fix: 배포 스크립트수정 * Fix:테스트
* feat: 프메 그라파나 적용 * refactor: 명칭변경 * feat: learnstatresponse 수정 * refactor: 이름 변경
* feat: 프메 그라파나 적용 * refactor: 명칭변경 * feat: learnstatresponse 수정 * refactor: 이름 변경 * refactor: 코드스타일
* feat: 프메 그라파나 적용 * refactor: 명칭변경 * feat: learnstatresponse 수정 * refactor: 이름 변경 * refactor: 코드스타일 * refactor: 경로 및 체크스타일 * refactor: 코드스타이 * refactor: 코드스타일 재수정 * refacot * bts * btsk:wq
* feat: 레디스로 refresh-token 관리 * refactor: 코드스타일 * fix: test code fix * refactor: 안쓰는 import 제거 및 경고 제거 * fix:코드스타일변경 * fix: 로그보기 * fix: ci.yml * fix: 버그수정 * fix: 코드스타일
* feat: testcode and api docs * Merge remote-tracking branch 'origin/develop' into xqqldir/btsk-103/questionset-testcode * refoactor: checksytle 수정 * refactor --------- Co-authored-by: Hyeonjun0527 <osumaniaddict527@gmail.com>
* feat: 문제집 생성중 -> 생성실패 스케줄러 작성 * feat: 프로덕션 코드만 수정 테스트 코드 미수정 * feat: 재시도 스케줄링 * feat: 테스트코드 작성 * fix: 충돌 에러 * refactor: 코드스타일 수정 * fix: 테스트 코드 수정 * refactor: 테스트 코드 작성 * refactor: 코드스타일 * 잘됨 * refactor: 코드스타일 * refactor: 코드스타일 * refactor: 코드스타일 * refactor: 코드스타일
* feat: 테스트 코드 작성 * refactor: 코드스타일
* fix: 카카오로 리다이렉트하는 무한루프 로직 수정 * refactor: 코드스타일 수정
* feat: 래빗엠큐 도입 * feat: 래빗엠큐 * refactor: s3 저장소 이름 변경 * 코드스타일 * refactor: 리소스 누수 문제 해결 * 코드스타일 * 코드스타일
refactor: config설정 래빗엠큐 아이디
* fix: sse disconnect solve * fix: 로그 추가 및 쓸모없는 에러로그 삭제 및 빈주입문제 해결
* fix: 낙관적락을 비관적 락으로 변경 * fix: 테스트 코드 수정 및 폴더 삭제에 기본폴더 이전 로직에 생긴 문제 해결 * refactor: 코드스타일 * refactor: 코드스타일 * fix: 분산환경에서 스킵 락 필요 * fix: 테스트 코드 수정 * fix: 어노테이션 적용 네이티브쿼리에 적용안되는 문법 제거 * fix: 폴더없을시 보안로직 * fix: 코드스타일 * fix:코드스타일 * fix: 코드스타일 * fix: 테스트코드
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Important Review skippedMore than 25% of the files skipped due to max files limit. The review is being skipped to prevent a low-quality review. 192 files out of 299 files are above the max files limit of 100. Please upgrade to Pro plan to get higher limits. You can disable this status message by setting the WalkthroughAdded nginx SSL reverse proxy service with healthchecks, implemented idempotency framework using Spring AOP, enhanced repository methods for eager loading, migrated Gemini client to streaming API, updated learning progress calculation, and disabled auto-generated schema management. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant IdempotencyAspect
participant Redis
participant Handler
participant Exception Handler
Client->>IdempotencyAspect: Request with Idempotency-Key header
IdempotencyAspect->>IdempotencyAspect: Extract idempotency key<br/>(header + method + URI + user)
IdempotencyAspect->>IdempotencyAspect: Build Redis key (hashed)
IdempotencyAspect->>Redis: Check if key exists
alt Key exists
Redis-->>IdempotencyAspect: Key found
IdempotencyAspect->>Exception Handler: Throw DuplicateRequestException
Exception Handler-->>Client: 409 Conflict
else Key does not exist
Redis-->>IdempotencyAspect: Key not found
IdempotencyAspect->>IdempotencyAspect: Attempt to acquire lock
rect rgb(200, 220, 255)
Note over IdempotencyAspect,Handler: Execute method
IdempotencyAspect->>Handler: proceed()
Handler-->>IdempotencyAspect: Response
end
IdempotencyAspect->>Redis: Set key = "DONE"<br/>with TTL
IdempotencyAspect-->>Client: Response
end
sequenceDiagram
participant Client
participant GeminiClient
participant GeminiAPI
participant Parser
Client->>GeminiClient: callGeminiApi(request)
GeminiClient->>GeminiAPI: generateContentStream(request)
GeminiAPI-->>GeminiClient: ResponseStream<GenerateContentResponse>
rect rgb(220, 240, 220)
Note over GeminiClient: aggregateStreamResponse
loop For each response in stream
GeminiAPI-->>GeminiClient: GenerateContentResponse (chunk)
GeminiClient->>GeminiClient: Validate finish reason<br/>(STOP or FINISH_REASON_UNSPECIFIED)
GeminiClient->>GeminiClient: Concatenate text field
end
end
GeminiClient->>Parser: parseResponse(aggregatedString)
Parser-->>GeminiClient: Parsed object
GeminiClient-->>Client: Result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
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: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/kr/it/pullit/modules/projection/learnstats/domain/LearnStats.java (1)
63-68: Add data validation constraints to prevent integrity violations from this breaking semantic change.The breaking change from
totalSolvedQuestionCount(attempted) tototalCorrectQuestionCount(correct answers) in thecalculateLearningProgress()method is confirmed—this shifts the metric from measuring engagement to mastery. While semantically meaningful, this change introduced data integrity risks.Critical issues:
- No constraints enforce
totalCorrectQuestionCount ≤ totalSolvedQuestionCount— if business logic elsewhere is buggy, the system could record more correct answers than attempted questions.- Missing documentation — no migration notes for this breaking semantic change are present in the codebase.
- Insufficient test coverage — the test at
QuestionSetWithStatsFacadeImplTest.java:99sets values but doesn't validate constraints.Required fixes:
Add validation in
increaseCorrectQuestionCount():public void increaseCorrectQuestionCount(long correctCount) { if (correctCount > 0) { if (this.totalCorrectQuestionCount + correctCount > this.totalSolvedQuestionCount) { throw new IllegalStateException("Correct count cannot exceed solved count"); } this.totalCorrectQuestionCount += correctCount; } }Document the breaking change in migration notes, and add test cases verifying the constraint.
🧹 Nitpick comments (7)
src/test/java/kr/it/pullit/modules/questionset/client/GeminiClientTest.java (1)
60-65: Suggest adding a helper method to reduce duplication.The mock setup for
ResponseStream(mocking bothiterator()andspliterator()) is repeated in lines 86-93, 108-115, and here. Consider extracting this into a helper method to improve maintainability.Add this helper method to the test class:
private ResponseStream<GenerateContentResponse> mockResponseStream(List<GenerateContentResponse> responses) { ResponseStream<GenerateContentResponse> mockStream = Mockito.mock(ResponseStream.class); when(mockStream.iterator()).thenReturn(responses.iterator()); when(mockStream.spliterator()).thenReturn(responses.spliterator()); return mockStream; }Then simplify the test setup:
- List<GenerateContentResponse> responses = - List.of(successResponse(responseJsonChunk1), successResponse(responseJsonChunk2)); - - ResponseStream<GenerateContentResponse> mockResponseStream = Mockito.mock(ResponseStream.class); - when(mockResponseStream.iterator()).thenReturn(responses.iterator()); - when(mockResponseStream.spliterator()).thenReturn(responses.spliterator()); + List<GenerateContentResponse> responses = + List.of(successResponse(responseJsonChunk1), successResponse(responseJsonChunk2)); + ResponseStream<GenerateContentResponse> mockResponseStream = mockResponseStream(responses);nginx/conf.d/default.conf (1)
1-10: LGTM! SSL configuration is appropriate for local development.The TLS 1.2/1.3 protocols and cipher suite are reasonable for development. For production deployment, consider using a more specific cipher suite following Mozilla SSL Configuration Generator recommendations.
compose.yaml (2)
2-14: Consider adding a healthcheck for the nginx service.The nginx service configuration is correct, but adding a healthcheck would improve orchestration reliability.
Apply this diff to add a healthcheck:
depends_on: - pullit-local-api + healthcheck: + test: ["CMD", "curl", "-f", "-k", "https://localhost/actuator/health"] + interval: 10s + timeout: 5s + retries: 5 networks: - pullit-local-network
62-69: Consider reducing environment variable duplication.The same environment variables are duplicated between
pullit-local-apiandpullit-local-worker. Consider using YAML anchors or a shared .env file to reduce maintenance burden.Example using YAML anchors:
x-common-env: &common-env APP_GEMINI_APIKEY: ${APP_GEMINI_APIKEY} AWS_REGION: ${AWS_REGION} GOOGLE_API_KEY: ${GOOGLE_API_KEY} KAKAO_CLIENT_SECRET: ${KAKAO_CLIENT_SECRET} KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI} KAKAO_REST_API_KEY: ${KAKAO_REST_API_KEY} S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} services: pullit-local-api: environment: - SPRING_PROFILES_ACTIVE=local # ... other vars ... <<: *common-envsrc/main/java/kr/it/pullit/modules/questionset/repository/adapter/jpa/QuestionSetJpaRepository.java (1)
16-24: Add DISTINCT to the fetch-join queryWithout
DISTINCT, the fetch join will emit one row per question, and depending on JPA provider settings that can surface as duplicate-entity trouble (or evenNonUniqueResultException) when wrapping the result in anOptional. AddingDISTINCTkeeps the ORM from tripping over duplicates while still eagerly loading the questions.Apply:
- SELECT qs + SELECT DISTINCT qssrc/main/java/kr/it/pullit/modules/questionset/service/QuestionSetService.java (1)
222-225: Retry the “update and complete” path as wellGreat call adding retry to
update(...), butupdateAndMarkAsComplete(...)mutates the same entity and is exposed to the identical optimistic-lock failure. Leaving it without retry means concurrent completions will still bubble anObjectOptimisticLockingFailureExceptionback to clients. Please annotate that method with the same@Retryableconfiguration so both flows behave consistently.A minimal change:
@Override @Transactional + @Retryable( + value = {ObjectOptimisticLockingFailureException.class}, + maxAttempts = 3, + backoff = @Backoff(delay = 200)) public void updateAndMarkAsComplete( Long questionSetId, QuestionSetUpdateRequestDto request, Long memberId) {src/main/java/kr/it/pullit/shared/error/CommonErrorCode.java (1)
10-14: Fix code naming inconsistency.The error code naming is inconsistent:
C_001andC_002use underscores, whileC004,C005, andC006do not. Consider standardizing to eitherC_004,C_005,C_006or removing the underscore from the earlier codes.Apply this diff to standardize the naming:
- INVALID_CONFIGURATION(HttpStatus.INTERNAL_SERVER_ERROR, "C_001", "서버 설정이 올바르지 않습니다: %s"), - INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "C_002", "잘못된 입력 값입니다."), - UNSUPPORTED_HTTP_METHOD(HttpStatus.METHOD_NOT_ALLOWED, "C004", "지원하지 않는 HTTP Method입니다."), - UNHANDLED_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "C005", "알 수 없는 서버 에러입니다."), - DUPLICATE_REQUEST(HttpStatus.CONFLICT, "C006", "이미 처리된 요청입니다."); + INVALID_CONFIGURATION(HttpStatus.INTERNAL_SERVER_ERROR, "C_001", "서버 설정이 올바르지 않습니다: %s"), + INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "C_002", "잘못된 입력 값입니다."), + UNSUPPORTED_HTTP_METHOD(HttpStatus.METHOD_NOT_ALLOWED, "C_004", "지원하지 않는 HTTP Method입니다."), + UNHANDLED_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "C_005", "알 수 없는 서버 에러입니다."), + DUPLICATE_REQUEST(HttpStatus.CONFLICT, "C_006", "이미 처리된 요청입니다.");
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
compose.yaml(6 hunks)nginx/certs/localhost.crt(1 hunks)nginx/certs/localhost.key(1 hunks)nginx/conf.d/default.conf(1 hunks)src/main/java/kr/it/pullit/modules/learningsource/source/service/SourceService.java(1 hunks)src/main/java/kr/it/pullit/modules/projection/learnstats/domain/LearnStats.java(1 hunks)src/main/java/kr/it/pullit/modules/projection/outbox/domain/OutboxEvent.java(1 hunks)src/main/java/kr/it/pullit/modules/questionset/client/GeminiClient.java(3 hunks)src/main/java/kr/it/pullit/modules/questionset/repository/QuestionSetRepository.java(1 hunks)src/main/java/kr/it/pullit/modules/questionset/repository/QuestionSetRepositoryImpl.java(1 hunks)src/main/java/kr/it/pullit/modules/questionset/repository/adapter/jpa/QuestionSetJpaRepository.java(1 hunks)src/main/java/kr/it/pullit/modules/questionset/service/QuestionService.java(1 hunks)src/main/java/kr/it/pullit/modules/questionset/service/QuestionSetService.java(3 hunks)src/main/java/kr/it/pullit/modules/questionset/web/QuestionSetController.java(2 hunks)src/main/java/kr/it/pullit/platform/security/config/SecurityConfig.java(1 hunks)src/main/java/kr/it/pullit/platform/web/cookie/CookieManager.java(1 hunks)src/main/java/kr/it/pullit/shared/error/CommonErrorCode.java(1 hunks)src/main/java/kr/it/pullit/shared/idempotency/DuplicateRequestException.java(1 hunks)src/main/java/kr/it/pullit/shared/idempotency/IdempotencyAspect.java(1 hunks)src/main/java/kr/it/pullit/shared/idempotency/IdempotencyExceptionHandler.java(1 hunks)src/main/java/kr/it/pullit/shared/idempotency/Idempotent.java(1 hunks)src/main/resources/application.yml(2 hunks)src/main/resources/data.sql(0 hunks)src/test/java/kr/it/pullit/modules/questionset/client/GeminiClientTest.java(5 hunks)src/test/java/kr/it/pullit/platform/web/cookie/CookieManagerTest.java(1 hunks)
💤 Files with no reviewable changes (1)
- src/main/resources/data.sql
🧰 Additional context used
🧬 Code graph analysis (2)
src/main/java/kr/it/pullit/modules/questionset/client/GeminiClient.java (2)
src/main/java/kr/it/pullit/modules/questionset/client/exception/LlmResponseParseException.java (1)
LlmResponseParseException(5-14)src/main/java/kr/it/pullit/modules/questionset/client/exception/LlmException.java (1)
LlmException(5-22)
src/main/java/kr/it/pullit/platform/security/config/SecurityConfig.java (2)
src/main/java/kr/it/pullit/platform/security/jwt/filter/DevAuthenticationFilter.java (1)
Profile(15-33)src/main/java/kr/it/pullit/platform/security/jwt/handler/LocalAuthenticationHandler.java (1)
Profile(12-47)
🪛 Gitleaks (8.28.0)
nginx/certs/localhost.key
[high] 1-28: Identified a Private Key, which may compromise cryptographic security and sensitive data encryption.
(private-key)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: code_check
🔇 Additional comments (24)
src/main/java/kr/it/pullit/platform/web/cookie/CookieManager.java (2)
49-50: Excellent fix for the cookie deletion issue!This correctly addresses the logout bug by ensuring cookies are expired with the same path they were created with. The
refresh_tokencookie is created with path/auth/refresh(line 35), and this change ensures it's expired with the same path, which is required for proper cookie deletion.Also applies to: 55-55
63-68: LGTM! Clean helper method.The logic is clear and correctly implements path determination. The string comparison uses
.equals()appropriately to avoid NPE when the constant is checked against the parameter.src/test/java/kr/it/pullit/platform/web/cookie/CookieManagerTest.java (1)
118-135: LGTM! Comprehensive test coverage.The test properly verifies that the refresh token cookie is expired with the correct path (
/auth/refresh), ensuring the bug fix works as expected. The test follows established patterns and validates all critical cookie attributes.src/main/java/kr/it/pullit/platform/security/config/SecurityConfig.java (1)
30-30: Based on the verification results, I can now provide the final response:
No security concerns with excluding SecurityConfig for the worker profile.
The worker profile is exclusively for RabbitMQ message-driven background processing. QuestionGenerationWorker uses
@RabbitListenerto consume messages from queues, not HTTP endpoints. No HTTP server configuration or alternative security is needed since the worker process doesn't expose any HTTP interfaces.src/main/java/kr/it/pullit/modules/questionset/client/GeminiClient.java (1)
97-107: LGTM: Enhanced error logging for parse failures.The signature change to accept a
Stringparameter aligns well with the streaming aggregation approach, and the error logging at lines 101-104 will be helpful for debugging malformed responses.src/test/java/kr/it/pullit/modules/questionset/client/GeminiClientTest.java (1)
57-69: Excellent test coverage for streaming aggregation.The test correctly validates that multiple JSON chunks can be aggregated and parsed successfully. Splitting the JSON mid-object (
{"title":"AI Quiz",and"questions":[]}) is a great edge case to test.src/main/resources/application.yml (2)
24-26: LGTM! Improved schema management approach.Disabling Hibernate's DDL auto-generation and moving to explicit schema.sql management prevents accidental schema modifications and is more appropriate for non-ephemeral environments.
110-110: LGTM! Necessary for nginx reverse proxy.This configuration enables Spring to correctly process X-Forwarded-* headers from the nginx reverse proxy, ensuring proper URL generation and security context.
nginx/certs/localhost.crt (1)
1-24: LGTM! Development certificate for local SSL.This mkcert-generated certificate for localhost is appropriate for local development and pairs with the private key. The expiration date (2028-02-06) provides sufficient time for local testing.
nginx/conf.d/default.conf (2)
14-28: Verify the 2-hour keepalive timeout is intentional.The SSE configuration looks correct overall:
proxy_buffering offandproxy_cache offenable real-time streamingConnection ''prevents connection closure between proxy and backendproxy_read_timeout 1his appropriate for long-lived SSE connectionsHowever,
keepalive_timeout 7200s(2 hours) is unusually long. Please confirm this value aligns with your SSE connection lifecycle requirements.
30-38: LGTM! Standard reverse proxy with WebSocket support.The general proxy configuration correctly forwards client information and includes WebSocket support via the Upgrade and Connection headers.
compose.yaml (5)
20-20: LGTM! Port exposure correctly removed.Removing direct port 8080 exposure is correct since nginx now serves as the sole entry point on port 443.
91-95: LGTM! MariaDB healthcheck properly configured.The healthcheck correctly tests database connectivity with authentication and selects the target database.
137-137: LGTM! Redis timeout adjustment is reasonable.The timeout reduction from 10s to 5s is appropriate for Redis's fast response times.
149-151: LGTM! RabbitMQ healthcheck updated appropriately.Using
rabbitmq-diagnostics check_runningis the recommended way to verify RabbitMQ availability.
30-37: Document required environment variables in .env.example or README.Verified: The compose.yaml contains 9 environment variables without fallback values across three services (pullit-local-api, pullit-local-worker, and grafana). If these external API credentials (Gemini, AWS, Google, Kakao, S3, Grafana admin) are not set on the host, the services will fail to start or run with undefined values.
No .env.example file currently exists in the repository. Adding documentation of required variables is recommended. For sensitive values (API keys and secrets), defaults should not be provided; instead, document them as required and consider adding setup instructions in README or a .env.example template showing which variables must be configured.
src/main/java/kr/it/pullit/shared/idempotency/IdempotencyExceptionHandler.java (1)
14-16: Guard against null response values
Map.ofrejects null entries. If aDuplicateRequestExceptionis raised without a non-null message (default ctor or an explicitnull), this handler will throw aNullPointerException, masking the intended 409 response. Either guarantee that every throw site supplies a message or defensively fall back to the error-code message before building the map.If you decide to guard it locally, a diff like this would do:
+import java.util.Objects; +import kr.it.pullit.shared.error.CommonErrorCode; ... - return ResponseEntity.status(HttpStatus.CONFLICT) - .body(Map.of("error", "duplicate_request", "message", ex.getMessage())); + return ResponseEntity.status(HttpStatus.CONFLICT) + .body( + Map.of( + "error", + "duplicate_request", + "message", + Objects.requireNonNullElse( + ex.getMessage(), CommonErrorCode.DUPLICATE_REQUEST.getMessage())));src/main/java/kr/it/pullit/shared/idempotency/Idempotent.java (1)
10-18: LGTM! Well-structured idempotency annotation.The annotation design is solid with sensible defaults (10-minute TTL, standard header name). The runtime retention and method target are correct for AOP interception.
src/main/java/kr/it/pullit/modules/questionset/service/QuestionService.java (1)
140-156: LGTM! Good refactoring for consistency.Consolidating the model name to use
DEFAULT_MODEL_NAMEthroughout simplifies the code and ensures consistent model selection across all LLM calls.src/main/java/kr/it/pullit/shared/idempotency/IdempotencyAspect.java (5)
30-49: Verify the duplicate request behavior aligns with requirements.The current implementation throws
DuplicateRequestExceptionfor duplicate requests rather than returning a cached result. Line 43 stores only"DONE"as a marker, not the actual response.This means:
- First request: Executes and returns result
- Duplicate request within TTL: Throws exception (HTTP 409 Conflict)
If the requirement is to return the cached result for idempotent requests (common in payment APIs), you would need to serialize and store the actual return value instead of just
"DONE".Can you confirm whether duplicate requests should:
- Throw an exception (current behavior), or
- Return the cached result from the first request?
60-64: Document the fail-open behavior for missing idempotency headers.When the
Idempotency-Keyheader is missing, the aspect logs a warning but allows the request to proceed without idempotency protection (returns null, which causes line 34 to bypass the check).This "fail-open" behavior means:
- Requests without the header are processed normally
- No duplicate protection is applied
Consider:
- If this header should be required for annotated endpoints, throw an exception here instead of returning null
- If optional, document this behavior clearly so developers understand that idempotency is opt-in per request
Which behavior is intended?
- Opt-in: Requests without the header proceed normally (current)
- Required: Requests without the header are rejected
77-80: LGTM! Appropriate use of MD5 for key generation.Using MD5 to hash the scope string is suitable for generating cache keys. While MD5 is not cryptographically secure, it's perfectly adequate for this non-security use case (no collision concerns at this scale).
82-96: LGTM! Thread-safe lock acquisition.The implementation correctly handles concurrent access:
- The initial check (line 85-86) provides early detection and better logging
- The atomic
setIfAbsent(line 91) ensures thread-safety even if multiple threads pass the first check- Different log messages distinguish between "already processed" vs "concurrent race"
The two-stage check (get + setIfAbsent) is intentional and provides better observability without sacrificing correctness.
98-101: LGTM! Safe duration conversion.The null check and conversion logic are correct.
| -----BEGIN PRIVATE KEY----- | ||
| MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDNa/ICheP/Ojm/ | ||
| pE2EZjH5tWE0VSSaEqGB51SSS7zbNXT57fET/LQD6pU100lED15RVsvvRWD89Xeb | ||
| tBASfLb+dLT8zn2m/rJtveteW8JGHSTePm1VAhLfrzdtFwzXuGHWtERViPg1lzsH | ||
| NcfigugUT2cgvHd7xN8AQ6SbPM1vTXrK8IHb9HS5IJcQgOTqlW0a0kR7e5rbApQI | ||
| EiCIgEAan7W7nAktDUw7480lS2tHhV+poTbPMWiR7SoxYd/dAEF0q3/3b6KFDNcv | ||
| 0RCmw3VZRBe0QioZUrE6qwg/MKa+Amw7I0ZugeWxoB18A7+SXeo6fvJtHvznVI/p | ||
| hXvDXzUJAgMBAAECggEANqu98xHzRiAW8nwl7VDNiCnPvv/SB/dhaJNKnMzvbF/j | ||
| zAiZmrospsYuA+9Blo2IiplRGVMbpvclaBkaFfF/OmWRLZ8/LcynbDGZjLlbERH8 | ||
| l/GBY5hzsXiOhcgWsOrvjxbXAPS9KnYfTaHwmsZAQfeH+Nxv6E7TEtzt2Crseexo | ||
| bewHioCpAtp/SOHdQaoIQWfmHn5a9kCK/+1JFd9kwy8UCKm7rZC3hgRIeIsZ4Qj/ | ||
| txQ64hv2kovY7UU/g6VX+yJOO84V4I+f0xUbBDUvWZyJDVr3q1myoCBXGLJtn2BO | ||
| BFgBgMCH/NZomsJ0cpnmSt7CMqhizmhEZWvnE2UoAQKBgQD6zYkSwbXeozWkAu/7 | ||
| CmYwnbJeIkhjj4hkO9fWDBVyKAvJfqN/ye/LhqtjQ4TTptrT9MjmO08UcT5H6gNi | ||
| WvFEnEKg0ULWFHdYxpR++Y9nL07lTSjDO/hiICwsy3ISZXUrwXyBWBeU0OojdIVA | ||
| zb6qrXbeEQ61XMZoAgqSuSAygQKBgQDRrauw4MP63dQjlcD2+Ycf5+Jow7Dj61lK | ||
| l2o2PmnimsfzSXqwcFkqEntztBtGDLT8IfxNyLWrp7UV3hJ66Wck/sWNiswcGST4 | ||
| /BzOXL1pRLOM9ndKpn+l773Gcs/k1rBW3PUH8iH5yt2GeRwNU7hGQwN8DEyNThlI | ||
| uh+FzZEuiQKBgHWbpEeTZsF8L081wWsrOTha+qWB1gg56m92UIQjLntVpBFcvTbT | ||
| bws1n3Dw3HyTpdH226566V5grB/08JlSpAjUbboT5w+UkVKj7EaOqFxupsSIJjFH | ||
| EfaRt6VZ0agmw4c9ODE/Ke+y99igb0wwLtTCexcvUIJjevaS3npnLV4BAoGAewNp | ||
| 1Ba5w8c6+zmTgRH53ZUcdpxAficINsPIc1SAqIpoPmpgiX0QQqefN811ps4zrCyA | ||
| Kl5TfwagLdkgfG3Mrp6t5hGFGAMEdvLqL4OnOEgvEsdSS0CNaRvS+cdIApiV0hBF | ||
| zUiX+EW1W3xYIdV5KfeM5s0MaGZmXQ2dCtIEmAkCgYEA9yY8rPoY3OXKSD2pAr5y | ||
| 4UVAlawCdSXUKgbvdrCylg0Rll3+15qgec8ffPuZfMbqI/UBMZlPJuu6v0z5cWqI | ||
| UkjNgSYJ2CJUahxFeuZp8w9UzXZdzRgKQ4aetKn5rIfoMsz3cVCOqS1QSJkyK8i8 | ||
| Ed741X8Al8o6UeZX1DZwZnM= | ||
| -----END PRIVATE KEY----- |
There was a problem hiding this comment.
🧩 Analysis chain
Verify this private key is for local development only.
Static analysis correctly flagged this as a private key. While the filename and corresponding certificate (mkcert-issued) suggest this is for local development, please confirm:
- This certificate/key pair is only used for local development
- Developers are instructed to regenerate their own certificates using mkcert
- Consider adding a README.md in the
nginx/certs/directory documenting the certificate generation process
To verify there are no production credentials in the repository, run:
🏁 Script executed:
#!/bin/bash
# Check for any references to production domains or credentials
rg -i "production|prod\.pull\.it\.kr|api\.pull\.it\.kr" nginx/Length of output: 0
🏁 Script executed:
#!/bin/bash
# Verify nginx directory structure and certificate files
echo "=== Listing nginx/certs/ directory ==="
fd . nginx/certs/ 2>/dev/null || echo "nginx/certs/ not found or empty"
echo ""
echo "=== Checking .gitignore for cert/key patterns ==="
rg -n "\.key|\.crt|\.pem|certs/" .gitignore 2>/dev/null || echo "No cert-related entries in .gitignore"
echo ""
echo "=== Looking for nginx-related README or documentation ==="
fd README nginx/ 2>/dev/null || echo "No README files in nginx/"
echo ""
echo "=== Checking nginx configuration files ===="
fd "\.conf" nginx/ 2>/dev/null | head -20Length of output: 309
🏁 Script executed:
#!/bin/bash
# Check if mkcert certificate is typical development cert
echo "=== Checking certificate subject and issuer ==="
openssl x509 -in nginx/certs/localhost.crt -text -noout 2>/dev/null | grep -A2 "Subject:\|Issuer:" || echo "Certificate file not accessible or not found"Length of output: 92
🏁 Script executed:
#!/bin/bash
# Check how certificates are referenced in nginx config
echo "=== nginx/conf.d/default.conf content ==="
cat nginx/conf.d/default.conf 2>/dev/null | head -50
echo ""
echo "=== Check root .gitignore for patterns ==="
cat .gitignore 2>/dev/null | head -30
echo ""
echo "=== Check for docker-compose or similar that might use these certs ==="
fd -e yml -e yaml . 2>/dev/null | xargs grep -l "localhost\|certs" 2>/dev/null | head -5Length of output: 2016
Add .gitignore entry and documentation for certificate files.
Verification confirms this is development-only (mkcert-issued certificate, localhost-only nginx config targeting local API service). However, two gaps were identified:
-
Missing .gitignore: Private key files (*.key) are not excluded from version control. Add to .gitignore:
nginx/certs/*.key -
Missing developer guidance: No documentation exists explaining certificate generation. Create
nginx/certs/README.mdwith instructions for regenerating certificates using mkcert, or document this in a main README.
Either protect the key file via .gitignore, or add explicit documentation that developers can reference. Preferably do both.
🧰 Tools
🪛 Gitleaks (8.28.0)
[high] 1-28: Identified a Private Key, which may compromise cryptographic security and sensitive data encryption.
(private-key)
🤖 Prompt for AI Agents
In nginx/certs/localhost.key (lines 1-28) the private key is committed without
.gitignore entry or developer guidance; add an entry to .gitignore to exclude
nginx/certs/*.key, create nginx/certs/README.md (or update the main README) with
step-by-step mkcert instructions to regenerate the localhost certificate and
key, and remove or rotate the committed key from the repository history (or
replace it with a placeholder) so secrets are not stored in version control.
c9e33c5 to
776b873
Compare
로컬환경에서 워커등 nginx 모방 및 운영디비와 일치하게 변경 로컬 정책 validation으로 변경,깃이그노어에 키 추가 및 가이드 및 null방어
776b873 to
b0e4528
Compare
PR 설명
문제집삭제, 소스삭제안되는문제해결. jpa 캐시 관련 문제 해결
패스때문에 로그아웃 쿠키 삭제 안되는 문제 해결
비동기 방식으로 문제집 요청을 보내서 문제집 10개 생성할시 11개 생성되는 문제 멱등성키로 해결
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Infrastructure