Skip to content

Conversation

@eraser502
Copy link
Contributor

@eraser502 eraser502 commented Dec 17, 2025

Overview

  • 관리자 대시보드 통계 API를 도입하고 고객·상담·관리자 수, 관련 마이그레이션/인덱스를 구성했어요.

Related Issue


PR Checklist

  • [ ]

Additional Information

  • 상담 상태별 집계 성능을 높이기 위해 consultations.status 컬럼 인덱스 추가를 추후 검토 예정이에요.

@eraser502 eraser502 self-assigned this Dec 17, 2025
@eraser502 eraser502 added this to Admin Dec 17, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Warning

Rate limit exceeded

@eraser502 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4f18f67 and d2d89ab.

📒 Files selected for processing (1)
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1 hunks)

Walkthrough

관리자 대시보드 통계 API가 추가되었습니다. 새 REST 컨트롤러 AdminDashboardController/api/v1/redot/admin/dashboard에 등록되어 GET /stats 요청을 처리하고 AdminDashboardService#getDashboardStats()를 호출합니다. 서비스는 Asia/Seoul 기준 오늘 시작 시각을 계산해 RedotMemberRepository.count(), RedotMemberRepository.countByCreatedAtBefore(...), ConsultationRepository.countByStatus(ConsultationStatus.PENDING), AdminRepository.count()를 호출해 집계한 값을 AdminDashboardStatsResponse로 반환합니다. Swagger 문서용 AdminDashboardControllerDocs, DTO 레코드, 관련 리포지토리 메서드와 created_at 인덱스 마이그레이션이 추가되었습니다.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller as AdminDashboardController
    participant Service as AdminDashboardService
    participant Members as RedotMemberRepository
    participant Consults as ConsultationRepository
    participant Admins as AdminRepository

    Client->>Controller: GET /api/v1/redot/admin/dashboard/stats
    Controller->>Service: getDashboardStats()
    Service->>Service: compute startOfToday (Asia/Seoul -> UTC)
    Service->>Members: count()
    Members-->>Service: totalRedotMembers
    Service->>Members: countByCreatedAtBefore(startOfTodayUtc)
    Members-->>Service: redotMembersUntilYesterday
    Service->>Consults: countByStatus(PENDING)
    Consults-->>Service: pendingConsultationCount
    Service->>Admins: count()
    Admins-->>Service: adminCount
    Service-->>Controller: AdminDashboardStatsResponse
    Controller-->>Client: 200 OK (AdminDashboardStatsResponse)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • 주의 깊게 볼 항목:
    • Asia/Seoul 기준 startOfToday 계산 및 UTC 변환 로직
    • countByCreatedAtBefore 쿼리의 파라미터 타입(LocalDateTime) 및 인덱스 사용 여부
    • countByStatus와 ConsultationStatus enum 값(PENDING) 일치성
    • Swagger 문서(응답 스키마)와 실제 DTO 일치 여부
    • 트랜잭션(readOnly) 범위와 예외 처리 누락 여부

Possibly related PRs

Poem

🐰 아침 이슬 머금은 깃발 아래 뛰며 세어보네
총원, 어제까지, 대기 상담과 관리자 수
당근 한 조각처럼 알차게 모아 담아
토끼가 춤추며 대시보드에 숫자 별을 꽂네 ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명이 템플릿 구조만 있고 모든 섹션이 비어있거나 미완성 상태입니다. Overview, Related Issue, Checklist, Additional Information이 모두 채워지지 않았습니다. Overview에 기능 설명, Related Issue에 이슈 번호, PR Checklist에 확인 항목들, Additional Information에 검토자가 참고할 정보를 작성하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 구현된 기능의 핵심 변경사항을 명확하게 반영하고 있습니다. '관리자 대시보드' 기능 추가를 간결하게 설명합니다.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1)

26-31: 데이터 정합성 이상 징후를 로깅하는 것을 고려해보세요.

Line 28에서 Math.max를 사용하여 음수 값을 방지하고 있는데, 만약 계산 결과가 음수라면 데이터 정합성에 문제가 있다는 신호일 수 있습니다. 이러한 경우를 로깅하면 향후 디버깅에 도움이 될 수 있습니다.

예시:

+        long newRedotMembersSinceYesterday = totalRedotMembers - redotMembersUntilYesterday;
+        if (newRedotMembersSinceYesterday < 0) {
+            log.warn("신규 회원 수 계산 결과가 음수입니다. total={}, untilYesterday={}", 
+                     totalRedotMembers, redotMembersUntilYesterday);
+            newRedotMembersSinceYesterday = 0L;
+        }
-        long newRedotMembersSinceYesterday = Math.max(0L, totalRedotMembers - redotMembersUntilYesterday);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abc9ff8 and ef8780d.

📒 Files selected for processing (5)
  • src/main/java/redot/redot_server/domain/admin/controller/AdminDashboardController.java (1 hunks)
  • src/main/java/redot/redot_server/domain/admin/controller/docs/AdminDashboardControllerDocs.java (1 hunks)
  • src/main/java/redot/redot_server/domain/admin/dto/response/AdminDashboardStatsResponse.java (1 hunks)
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1 hunks)
  • src/main/java/redot/redot_server/domain/redot/member/repository/RedotMemberRepository.java (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-17T01:39:43.440Z
Learnt from: eraser502
Repo: redotlabs/server PR: 134
File: src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java:58-71
Timestamp: 2025-12-17T01:39:43.440Z
Learning: In the RedotApp domain model, enforce 1:1 relationships: RedotApp must have exactly one Domain, one StyleInfo, and one SiteSetting. Review AdminRedotAppService and related domain entities to ensure constraints reflect this: enforce non-null associations, unique foreign keys or join tables as appropriate, and strict cascade rules. Validate that the database schema enforces one-to-one mappings (unique foreign keys or shared primary keys), and that service layer logic does not permit multiple related entities or optional links for RedotApp. Ensure getters/setters and persistence mappings (annotations or XML) align with a 1:1 relationship pattern and update tests to cover these invariants.

Applied to files:

  • src/main/java/redot/redot_server/domain/admin/controller/docs/AdminDashboardControllerDocs.java
  • src/main/java/redot/redot_server/domain/admin/dto/response/AdminDashboardStatsResponse.java
  • src/main/java/redot/redot_server/domain/admin/controller/AdminDashboardController.java
  • src/main/java/redot/redot_server/domain/redot/member/repository/RedotMemberRepository.java
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java
🔇 Additional comments (3)
src/main/java/redot/redot_server/domain/admin/dto/response/AdminDashboardStatsResponse.java (1)

5-12: 잘 구현되었습니다!

Java record를 사용한 깔끔한 DTO 구현입니다. 모든 필드에 명확한 Swagger 문서가 작성되어 있고, 불변 데이터 구조로 적절하게 설계되었습니다.

src/main/java/redot/redot_server/domain/admin/controller/docs/AdminDashboardControllerDocs.java (1)

11-18: API 문서화가 잘 되어 있습니다!

Swagger 어노테이션을 사용한 명확한 API 문서 작성이 잘 되어 있습니다.

src/main/java/redot/redot_server/domain/admin/controller/AdminDashboardController.java (1)

12-24: 보안 설정이 이미 적용되어 있습니다.

이 엔드포인트는 이미 전역 보안 설정으로 보호되고 있습니다. SecurityConfig의 adminApiChain(Order 6)에서 /api/v1/redot/admin/** 경로에 대해 .authenticated() 요구사항이 설정되어 있으며, AdminJwtAuthenticationFilter가 JWT 인증을 처리합니다. 메서드 레벨 어노테이션이 없어도 모든 요청은 유효한 관리자 토큰 없이는 접근할 수 없습니다.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/main/java/redot/redot_server/domain/redot/consultation/repository/ConsultationRepository.java (1)

9-9: 대시보드 성능 최적화를 위한 인덱스 고려

대시보드에서 상태별 집계 쿼리가 자주 호출될 경우, consultation 테이블의 status 컬럼에 인덱스를 추가하면 쿼리 성능이 향상됩니다. 데이터베이스 마이그레이션에서 인덱스 생성을 검토해주세요.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef8780d and 32d0421.

📒 Files selected for processing (3)
  • src/main/java/redot/redot_server/domain/admin/dto/response/AdminDashboardStatsResponse.java (1 hunks)
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1 hunks)
  • src/main/java/redot/redot_server/domain/redot/consultation/repository/ConsultationRepository.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/redot/redot_server/domain/admin/dto/response/AdminDashboardStatsResponse.java
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-17T01:39:43.440Z
Learnt from: eraser502
Repo: redotlabs/server PR: 134
File: src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java:58-71
Timestamp: 2025-12-17T01:39:43.440Z
Learning: In the RedotApp domain model, enforce 1:1 relationships: RedotApp must have exactly one Domain, one StyleInfo, and one SiteSetting. Review AdminRedotAppService and related domain entities to ensure constraints reflect this: enforce non-null associations, unique foreign keys or join tables as appropriate, and strict cascade rules. Validate that the database schema enforces one-to-one mappings (unique foreign keys or shared primary keys), and that service layer logic does not permit multiple related entities or optional links for RedotApp. Ensure getters/setters and persistence mappings (annotations or XML) align with a 1:1 relationship pattern and update tests to cover these invariants.

Applied to files:

  • src/main/java/redot/redot_server/domain/redot/consultation/repository/ConsultationRepository.java
🔇 Additional comments (2)
src/main/java/redot/redot_server/domain/redot/consultation/repository/ConsultationRepository.java (2)

5-5: LGTM!

ConsultationStatus import가 새로운 메서드 시그니처에 필요하며 올바르게 추가되었습니다.


8-9: [rewritten review comment]
[classification tag]

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32d0421 and 37871a4.

📒 Files selected for processing (2)
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1 hunks)
  • src/main/resources/db/migration/V7__add_index_to_redot_members_created_at.sql (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-17T01:39:43.440Z
Learnt from: eraser502
Repo: redotlabs/server PR: 134
File: src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java:58-71
Timestamp: 2025-12-17T01:39:43.440Z
Learning: In the RedotApp domain model, enforce 1:1 relationships: RedotApp must have exactly one Domain, one StyleInfo, and one SiteSetting. Review AdminRedotAppService and related domain entities to ensure constraints reflect this: enforce non-null associations, unique foreign keys or join tables as appropriate, and strict cascade rules. Validate that the database schema enforces one-to-one mappings (unique foreign keys or shared primary keys), and that service layer logic does not permit multiple related entities or optional links for RedotApp. Ensure getters/setters and persistence mappings (annotations or XML) align with a 1:1 relationship pattern and update tests to cover these invariants.

Applied to files:

  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java
🔇 Additional comments (3)
src/main/resources/db/migration/V7__add_index_to_redot_members_created_at.sql (1)

1-1: 인덱스 추가가 적절합니다.

created_at 컬럼에 대한 인덱스는 countByCreatedAtBefore 쿼리의 성능을 향상시킵니다. IF NOT EXISTS 사용으로 안전하게 마이그레이션이 실행됩니다.

src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (2)

15-22: 서비스 구조가 잘 설계되었습니다.

읽기 전용 트랜잭션 설정이 적절하며, 필요한 리포지토리들이 올바르게 주입되었습니다.


30-39: 대시보드 통계 로직이 명확합니다.

대기 중인 상담 수와 관리자 수를 집계하는 로직이 직관적이며, 응답 객체 구성도 적절합니다. 순차적인 count 쿼리 실행은 관리자 대시보드의 사용 빈도를 고려할 때 허용 가능한 수준입니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1)

29-33: 리포지토리 호출에 대한 예외 처리를 고려해주세요.

여러 리포지토리를 순차적으로 호출하고 있지만, 예외 처리가 없습니다. 특정 통계 조회가 실패하더라도 다른 통계는 반환할 수 있도록 하거나, 최소한 의미 있는 에러 메시지를 제공하는 것이 좋습니다.

예를 들어:

public AdminDashboardStatsResponse getDashboardStats() {
    try {
        // ... 기존 로직 ...
    } catch (Exception e) {
        log.error("Failed to fetch dashboard statistics", e);
        throw new DashboardException("대시보드 통계를 조회하는 중 오류가 발생했습니다", e);
    }
}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37871a4 and 4f18f67.

📒 Files selected for processing (1)
  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-17T01:39:43.440Z
Learnt from: eraser502
Repo: redotlabs/server PR: 134
File: src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java:58-71
Timestamp: 2025-12-17T01:39:43.440Z
Learning: In the RedotApp domain model, enforce 1:1 relationships: RedotApp must have exactly one Domain, one StyleInfo, and one SiteSetting. Review AdminRedotAppService and related domain entities to ensure constraints reflect this: enforce non-null associations, unique foreign keys or join tables as appropriate, and strict cascade rules. Validate that the database schema enforces one-to-one mappings (unique foreign keys or shared primary keys), and that service layer logic does not permit multiple related entities or optional links for RedotApp. Ensure getters/setters and persistence mappings (annotations or XML) align with a 1:1 relationship pattern and update tests to cover these invariants.

Applied to files:

  • src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java
🔇 Additional comments (2)
src/main/java/redot/redot_server/domain/admin/service/AdminDashboardService.java (2)

15-22: 클래스 구조가 잘 구성되어 있습니다.

Spring 서비스 어노테이션, 읽기 전용 트랜잭션, 그리고 생성자 주입이 적절하게 적용되었습니다.


25-27: 타임존 처리 개선이 잘 적용되었습니다.

이전 리뷰에서 지적된 ZoneId.systemDefault() 사용 문제가 명시적인 Asia/Seoul 타임존 사용으로 개선되었습니다. UTC로의 변환도 명확하게 처리되었습니다.

@eraser502 eraser502 merged commit e37189b into develop Dec 17, 2025
1 check passed
@github-project-automation github-project-automation bot moved this to Done in Admin Dec 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Feature / Admin / Dashboard API

2 participants