Skip to content

[FEAT] #212 어드민 패널 구현 (SSR) - #224

Merged
PBEM22 merged 15 commits into
developfrom
feat/#212/admin-panel
Jul 28, 2026
Merged

[FEAT] #212 어드민 패널 구현 (SSR)#224
PBEM22 merged 15 commits into
developfrom
feat/#212/admin-panel

Conversation

@PBEM22

@PBEM22 PBEM22 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

📌 관련 이슈

✨ 변경 사항

  • Thymeleaf + Bootstrap 5 기반 어드민 패널 SSR 구현
  • 로그인 페이지 (Spring Security session 기반)
  • 대시보드: 유저 수 / 분철글 수 / 주문 수 통계 카드
  • 유저 관리: 전체 유저 조회, 정지 / 정지 해제 / 강제 탈퇴
  • 분철글 관리: 상태 필터, 분철글 삭제
  • 어드민 전용 SecurityFilterChain 분리 (@Order(1))
  • 어드민 패널 UI 전면 개선 (다크 사이드바, 컬러 배지, pill 필터 탭)
  • 엣지 케이스 처리
    • 진행 중 분철글(CLOSED/PAYMENT_DONE/SHIPPING) 삭제 차단
    • 주문 존재하는 분철글 삭제 시 FK 제약 위반 방지
    • 탈퇴 유저 정지/해제/재탈퇴 시도 차단
    • 에러 발생 시 JSON 대신 flash 메시지로 표시

📸 테스트 증명 (필수)

  • https://dev.poti.kr/admin/login 에서 로컬 및 dev 서버 동작 확인

📚 리뷰어 참고 사항

  • 어드민 계정은 환경변수 ADMIN_USERNAME / ADMIN_PASSWORD 로 관리
  • prod 서버 .env 에 해당 변수 추가 필요 (현재 dev만 적용됨)
  • 어드민 전용 SecurityFilterChain이 /admin/** 경로를 선점하므로 JWT 필터와 충돌 없음

✅ 체크리스트

  • 브랜치 전략(git flow)을 따랐나요? (develop -> feat/...)
  • 로컬에서 빌드 및 실행이 정상적으로 되나요?
  • 불필요한 주석(TODO 등)이나 더미 코드는 제거했나요?
  • 컨벤션(커밋 메시지, 코드 스타일)을 지켰나요?

Summary by CodeRabbit

  • 새 기능

    • 관리자 전용 로그인과 권한 보호 기능이 추가되었습니다.
    • 관리자 대시보드에서 사용자·게시글·주문 현황을 확인할 수 있습니다.
    • 사용자 및 게시글 관리 화면에 상태 필터, 페이지 이동, 삭제·정지 관리 기능이 제공됩니다.
    • 공통 관리자 레이아웃과 메뉴, 알림 UI가 적용되었습니다.
  • 버그 수정

    • 강제 탈퇴 시 연결된 알림 토큰도 함께 정리됩니다.
    • 탈퇴한 사용자를 정지하거나 정지 해제하려는 경우 적절한 오류가 표시됩니다.

PBEM22 added 10 commits July 20, 2026 23:41
- Thymeleaf + Bootstrap 5 기반 SSR 어드민 패널 추가
- InMemoryUserDetailsManager로 환경변수 기반 어드민 계정 관리
- Spring Security 별도 FilterChain(@order(1))으로 API와 세션 분리
- 대시보드(통계), 유저 관리(정지/해제/강제탈퇴), 분철글 관리(상태필터/삭제) 구현
- UserStatus에 SUSPENDED 추가, User에 suspend/unsuspend/withdraw(reason) 메서드 추가
- ErrorStatus에 PROMPT_ERROR(50005) 추가
- Keep Thymeleaf dependencies (admin SSR)
- Keep admin credentials config (ADMIN_USERNAME, ADMIN_PASSWORD)
- Merge withdraw() with reason param and validateNoActiveTransaction from develop
- Keep suspend()/unsuspend() methods in User added for admin panel
- deletePost() 실행 전 주문 존재 여부 체크 추가
- 주문이 있으면 POST_HAS_ORDERS(40020) 예외 반환
- OrderRepository에 existsByGroupBuyPost_Id() 추가
- CLOSED/PAYMENT_DONE/SHIPPING 상태 글은 주문 유무 무관하게 삭제 차단 (POST_IN_PROGRESS 40021)
- 상태 기반 체크를 주문 존재 체크보다 먼저 수행
- 프론트 confirm: RECRUITING은 일반 경고, 그 외 상태는 '진행 중' 강조 메시지로 구분
- User.suspend/unsuspend: WITHDRAWN 계정 상태 변경 시도 시 예외 발생
- AdminService.forceWithdrawUser: 이미 탈퇴한 유저 중복 탈퇴 차단
- AdminController: BusinessException 발생 시 JSON 대신 flash 메시지로 redirect
- layout.html: 에러 메시지 alert 영역 추가
탈퇴한 유저에 대해 suspend/unsuspend 호출 시
IllegalStateException 대신 BusinessException을 던져
AdminController에서 flash 에러로 정상 처리되도록 수정
- 사이드바: 다크 테마, 활성 메뉴 accent 색상, 계층 구조 개선
- 대시보드: 컬러 스탯 카드 + 아이콘 + 빠른 이동 섹션
- 유저/분철글 테이블: 상태별 색상 배지, 액션 버튼 시각화
- 분철글 상태 필터를 pill 탭으로 교체
- confirm 다이얼로그를 JS 함수로 분리하여 가독성 향상
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@PBEM22, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a4ecfec5-6bda-4138-a296-f5300515ceb5

📥 Commits

Reviewing files that changed from the base of the PR and between 5fc998e and 8e7218f.

📒 Files selected for processing (2)
  • src/main/java/org/sopt/poti/domain/admin/service/AdminService.java
  • src/main/java/org/sopt/poti/global/security/jwt/JwtAuthenticationFilter.java
📝 Walkthrough

Walkthrough

관리자 전용 보안 필터 체인과 공통 레이아웃을 추가하고, 대시보드·사용자·분철글 화면을 새 UI로 구성했습니다. 사용자 상태 변경과 강제 탈퇴 시 FCM 토큰 정리 동작도 보완했습니다.

Changes

관리자 SSR 패널

Layer / File(s) Summary
관리자 인증 및 SSR 기반
src/main/java/org/sopt/poti/global/config/AdminSecurityConfig.java, src/main/java/org/sopt/poti/global/security/SecurityConfig.java, src/main/resources/templates/admin/layout.html
관리자 필터 체인 순서를 메서드 수준으로 지정하고 로그아웃 리다이렉트 경로를 변경했으며, 공통 레이아웃·사이드바·에러 메시지·로그아웃 폼을 추가했습니다.
관리자 도메인 제어 및 상태 규칙
src/main/java/org/sopt/poti/domain/admin/service/AdminService.java, src/main/java/org/sopt/poti/domain/user/entity/User.java
탈퇴 사용자의 정지·정지 해제를 USER_NOT_FOUND로 처리하고, 강제 탈퇴 시 FCM 토큰을 삭제하도록 변경했습니다. 사용자 엔티티의 상태 전환 방어 분기도 제거했습니다.
관리자 대시보드 렌더링
src/main/resources/templates/admin/dashboard.html
사용자 수, 분철글 수, 주문 수를 카드로 표시하고 사용자·분철글 관리 화면 링크를 추가했습니다.
관리자 목록 화면 및 조작
src/main/resources/templates/admin/posts.html, src/main/resources/templates/admin/users.html
사용자·분철글 목록의 상태 표시, 필터, 페이지네이션, 빈 상태 화면과 확인 후 POST 동작을 새 마크업과 스타일로 변경했습니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: ✨ Feat, 👤 User/Auth, 🐴 채륜

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 강제 탈퇴 시 FCM 토큰까지 삭제하는 변경은 #212의 명시 요구사항에 없어 범위를 벗어납니다. FCM 토큰 정리 로직은 별도 이슈로 분리하거나, 이번 PR 범위에 맞게 제거하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 어드민 패널 SSR 구현이라는 핵심 변경을 짧고 명확하게 담고 있습니다.
Linked Issues check ✅ Passed 로그인, 통계 카드, 유저/분철글 관리, 세션 기반 보안 분리 요구가 모두 반영돼 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#212/admin-panel

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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 `@src/main/java/org/sopt/poti/domain/admin/service/AdminService.java`:
- Around line 76-83: Update AdminService.forceWithdrawUser to call
fcmTokenService.deleteAllByUserId with the withdrawn user’s ID, matching the
cleanup performed by AuthService.withdraw, while preserving the existing
withdrawal and refresh-token deletion flow.
- Around line 99-102: Update the deletion flow in AdminService to serialize the
order-existence check and group-buy post deletion using the same post-level
state or lock as order creation. Keep the operation atomic, and catch the
resulting integrity/FK violation to translate it into BusinessException with
ErrorStatus.POST_HAS_ORDERS instead of allowing a server error.
- Around line 61-62: Update the suspension flow around AdminService so
previously issued access JWTs cannot authenticate after user.suspend(). Enforce
SUSPENDED users as INVALID_TOKEN in JwtAuthenticationFilter on every request, or
integrate equivalent access-token revocation during suspension; keep
refresh-token deletion and ensure suspended users are rejected until
reactivated.

In `@src/main/java/org/sopt/poti/global/config/AdminSecurityConfig.java`:
- Around line 56-60: Update the logoutSuccessUrl configuration in
AdminSecurityConfig to redirect to the admin login path with the logout query
parameter present, so login.html can render the logout-success message. Keep the
existing logout URL and session invalidation behavior unchanged.
- Around line 15-16: Move the chain ordering annotations from the configuration
classes to their bean methods: in
src/main/java/org/sopt/poti/global/config/AdminSecurityConfig.java lines 15-16,
remove the class-level `@Order`(1) and place it directly below `@Bean` on
adminFilterChain; in
src/main/java/org/sopt/poti/global/security/SecurityConfig.java line 21, remove
the class-level `@Order`(2) and place it directly below `@Bean` on filterChain.

In `@src/main/resources/templates/admin/users.html`:
- Around line 141-159: Update the pagination controls in
src/main/resources/templates/admin/users.html lines 141-159 and
src/main/resources/templates/admin/posts.html lines 150-168 so first/last page
controls render without an href when users.first or users.last is true, while
retaining the existing navigation URLs for enabled controls. Use the existing
pagination symbols and preserve the disabled styling and page-number links.
- Around line 2-3: Update the layout invocations in
src/main/resources/templates/admin/users.html lines 2-3 and
src/main/resources/templates/admin/posts.html lines 2-3 so each passes its
page-specific style and script resources along with the section content. Ensure
the layout receives the confirmSuspend, confirmWithdraw, and confirmDelete
functions and the associated styles, either by placing them inside the section
fragment or by extending the layout arguments, so the existing confirmation
dialogs continue to work.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro Plus

Run ID: e233d30c-2ec2-4537-bcf6-afff566d9f01

📥 Commits

Reviewing files that changed from the base of the PR and between 4b0a773 and 5c321d8.

📒 Files selected for processing (17)
  • build.gradle
  • src/main/java/org/sopt/poti/domain/admin/controller/AdminController.java
  • src/main/java/org/sopt/poti/domain/admin/service/AdminService.java
  • src/main/java/org/sopt/poti/domain/auth/service/AuthService.java
  • src/main/java/org/sopt/poti/domain/groupbuy/repository/GroupBuyRepository.java
  • src/main/java/org/sopt/poti/domain/order/repository/OrderRepository.java
  • src/main/java/org/sopt/poti/domain/user/entity/User.java
  • src/main/java/org/sopt/poti/global/config/AdminSecurityConfig.java
  • src/main/java/org/sopt/poti/global/error/ErrorStatus.java
  • src/main/java/org/sopt/poti/global/security/SecurityConfig.java
  • src/main/resources/application.yml
  • src/main/resources/templates/admin/dashboard.html
  • src/main/resources/templates/admin/layout.html
  • src/main/resources/templates/admin/login.html
  • src/main/resources/templates/admin/posts.html
  • src/main/resources/templates/admin/users.html
  • src/test/resources/application-test.yml

Comment thread src/main/java/org/sopt/poti/domain/admin/service/AdminService.java
Comment thread src/main/java/org/sopt/poti/domain/admin/service/AdminService.java
Comment thread src/main/java/org/sopt/poti/domain/admin/service/AdminService.java Outdated
Comment thread src/main/java/org/sopt/poti/global/config/AdminSecurityConfig.java Outdated
Comment thread src/main/java/org/sopt/poti/global/config/AdminSecurityConfig.java
Comment thread src/main/resources/templates/admin/users.html
Comment thread src/main/resources/templates/admin/users.html
@PBEM22 PBEM22 self-assigned this Jul 28, 2026
@PBEM22 PBEM22 added 🧹 Chore 자잘한 수정, 빌드 설정, 패키지 관리 ☁️ P2 시간 남으면 진행 (고도화) 🐴 채륜 막시무스 labels Jul 28, 2026
@PBEM22
PBEM22 merged commit 9668a63 into develop Jul 28, 2026
2 checks passed
@PBEM22
PBEM22 deleted the feat/#212/admin-panel branch July 28, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧹 Chore 자잘한 수정, 빌드 설정, 패키지 관리 ☁️ P2 시간 남으면 진행 (고도화) 🐴 채륜 막시무스

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 어드민 패널 구현 (SSR)

1 participant