You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
GlobalExceptionHandler(@RestControllerAdvice)에서 전역 처리
ExceptionType enum으로 에러 코드/메시지/HTTP 상태 관리
도메인 예외는 BusinessException 상속
Soft Delete
모든 엔티티가 BaseEntity 상속 → createdAt, updatedAt, deletedAt 자동 관리. User는 @SQLDelete로 삭제 시 데이터 마스킹 처리.
이중 랭킹 구조
실시간 랭킹: StudySessionRepository Native Query로 현재 기간 직접 계산 (진행중 세션 포함)
확정 랭킹: 기간 종료 후 UserRanking/DepartmentRanking 테이블에 저장
컨트롤러에서 date 파라미터 유무로 분기
시즌 시스템
4개 시즌 순환: SPRING_SEMESTER(36월) → SUMMER_VACATION(78월) → FALL_SEMESTER(912월) → WINTER_VACATION(12월). 시즌 종료 시 SeasonRankingSnapshot으로 불변 이력 저장 (Spring Retry 3회, 5초 backoff, JDBC 배치 2000건 청크).
학과 랭킹 계산
학과별 상위 30명의 공부 시간 합산. Native Query + CTE로 25개 학과 처리. MySQL 8+ 필수.
인증 플로우
OAuth2 로그인 (Kakao/Google/Apple)
→ GUEST 역할로 User 생성
→ 학교 이메일 인증 (@kumoh.ac.kr)
→ 학과/학번 입력 → USER 역할로 승격
→ JWT 발급 (Access + Refresh, 14일)
→ API 요청 시 Authorization: Bearer <token> 헤더
→ JwtAuthenticationFilter → @PreAuthorize → @AssignUserId
역할 계층: ADMIN ⊃ USER ⊃ GUEST
프로파일 설정
Profile
DB
DDL
용도
local
MySQL localhost:3311
create-drop
로컬 개발
dev
Docker MySQL
update
개발 서버
prod
Production DB
validate
운영
test
TestContainers MySQL 8.0
-
통합 테스트
unit-test
H2
-
단위 테스트
민감 설정 (Git Submodule)
src/main/resources/security/ 디렉토리에 git submodule로 관리. 절대 직접 커밋 금지.
CI (dev/prod): Java 21 빌드, TestContainers + Redis 서비스 연동, 테스트, JUnit 리포트
CD (dev): Docker 멀티 아키텍처 빌드 (AMD64/ARM64) → GHCR 푸시 → self-hosted 배포
CD (prod): 아티팩트 기반 Docker 빌드 → GHCR → production 환경 배포
Docker:
Base image: amd64/openjdk:21-jdk-slim
docker-compose.yml: MySQL 8.4.0 (포트 3311) + Redis Alpine (포트 6379)
Build & Run
# 인프라 실행 (MySQL 8.4, Redis)
docker-compose up -d
# 빌드
./gradlew clean build
# 로컬 실행
./gradlew bootRun --args='--spring.profiles.active=local'# 전체 테스트
./gradlew test# 단일 테스트 클래스
./gradlew test --tests "ClassName"
테스트
단위 테스트 (src/test/java/.../unit/)
JUnit 5 + Mockito + AssertJ, BaseUnitTest 기반
프로파일: unit-test (H2, Redis 비활성)
대상: StudySession 시간 계산, 랭킹 로직, Wi-Fi 검증, 시즌 서비스, 시즌 스냅샷 재시도
통합 테스트 (src/test/java/.../integration/)
TestContainers MySQL 8.0 + Redis 7.0, BaseIntegrationTest 기반
프로파일: test
각 테스트 후 전체 테이블 TRUNCATE + Redis FLUSHALL
대상: Controller E2E 테스트
Development Checklist
도메인 모듈 구조 준수: api/ → controller/ → service/ → repository/ → domain/ → dto/
인증 필요 엔드포인트에 @AssignUserId + @PreAuthorize 사용
@Transactional 적절히 적용 (읽기 전용은 readOnly = true)
ResponseUtil로 응답 표준화
새 에러는 ExceptionType enum에 추가 (접두사 규칙 준수)
security/ 디렉토리 파일 커밋 금지
StudySessionRepository Native Query 수정 시 랭킹/통계 도메인 영향 확인