feat: 관리자 대시보드 문제 등록 조회 API추가 및 월별 접속자 조회 리팩토링#91
Conversation
| .select(access.accessDate, access.userId.countDistinct()) | ||
| .from(access) | ||
| .where(access.accessDate.between(start, end)) | ||
| .join(user).on(user.id.eq(access.userId)) |
There was a problem hiding this comment.
admin 제외의 의도는 맞는데, 이 코드는 제가 봤을땐, user 테이블이랑 JOIN을 태우게 돼서, 데이터가 쌓일수록 부담이 커질 수 있을 거 같아요, ADMIN계정은 소수이기 때문에, user테이블에서 admin id목록을 먼저 조회 한 후,
userId NOT IN (adminIds) 조건으로 처리하는 게 JOIN 오버헤드 없이 더 깔끔할 것 같습니다.
| public DashboardProblemsResponse getProblems(Pageable pageable) { | ||
| List<DashboardProblemItem> content = dashboardProblemQueryPort.findProblems(pageable); | ||
| long totalElements = dashboardProblemQueryPort.countProblems(); | ||
| int totalPages = totalElements == 0 ? 0 : (int) ((totalElements + pageable.getPageSize() - 1) / pageable.getPageSize()); |
There was a problem hiding this comment.
findProblems()와 countProblems()가 각각 독립적으로 작성되어 있어서, 나중에 findProblems()에
필터 조건이 추가될 때 countProblems()에 같은 조건을 빠뜨리면 페이지네이션 totalElements가
틀려지는 버그가 생길 수 있을거같아여. where 조건을 공유하는 private 메서드로 묶어두면 어떨까요?
| .orElseThrow(() -> new ProblemException(ErrorCode.PROBLEM_NOT_FOUND)); | ||
|
|
||
| problemRepositoryPort.findById(row.problemId()) | ||
| .ifPresent(Problem::incrementViewCount); |
There was a problem hiding this comment.
Query 서비스인데 내부에서 쓰기 작업(viewCount 증가)을 하고 있어서, CQS 관점에서 좀 어색하다고 생각이 들기도하는거같아요
클래스 레벨이 readOnly = true인데 이 메서드만 @transactional로 오버라이드하고 있어서, 나중에
다른 개발자가 이 서비스를 읽기 전용 컨텍스트에서 호출하거나 캐싱을 붙이게 되면 카운트 증가가 누락될 수 있지않을까요?. viewCount 증가는 커맨드 서비스 쪽으로 옮기거나, 컨트롤러에서 조회
후 별도로 호출하는 구조가 더 자연스러울 것 같은데 어떠신가요?
| Problem problem = problemRepositoryPort.findByIdAndUserId(problemId, userId) | ||
| .orElseThrow(() -> new ProblemException(ErrorCode.PROBLEM_NOT_FOUND)); | ||
|
|
||
| problemRepositoryPort.incrementAiSolutionCount(problemId); |
There was a problem hiding this comment.
이 시점에 카운트를 올리면 요청 성공/실패 여부와 무관하게 항상 올라가는데 이 부분은 어떻게 생각하시나요??
AiSolutuonCount 필드명보다는 aiSolutinReqCount 같은건 어떨까요?
There was a problem hiding this comment.
일단은 수정 안하고 프론트랑 나중에 말 맞춰서 수정해야할 것 같습니당
| size = DEFAULT_SIZE; | ||
| if (size > MAX_SIZE) | ||
| size = MAX_SIZE; | ||
| } |
There was a problem hiding this comment.
if문에 중괄호가 없어서 다른 코드들과 코드 스타일이 조금 다른거 같은데 어떻게 생각하시나요?
이 방법을 사용하셔야한다면 혹시 이유가 있을까요?
There was a problem hiding this comment.
이건 그냥 원래 있던 코드 스타일 따라 했습니당
|
이번 대시보드 기능 구현 고생 많으셨습니다! 전반적인 헥사고날 아키텍처 구조를 잘 따르고 있고, |
Ⅰ. PR 내용 설명
관리자 대시보드에 문제 등록 현황 조회 API를 추가하고, 기존 월별 접속자 조회를 보강했습니다.
권한
Ⅱ. 관련 이슈
Ⅲ. 검증 방법
Ⅳ. 리뷰 시 참고 사항
Breaking change — 어드민 프론트 동기화 필요
DashboardDailyAccessItem의 JSON 필드명이 count → dailyVisitors로 변경됐습니다. 어드민 프론트가 기존 필드를 참조
중이라면 동시 배포가 필요합니다.
카운터 증가 구현 방식
조회수/AI 호출수 증가는 엔티티 load-modify-save 대신 JPQL @Modifying UPDATE로 처리했습니다.