Skip to content

[Feat] 권한 모델 개편 - recruitment, user 도메인 적용 - #213

Open
galgalrobot wants to merge 2 commits into
devfrom
feat/#212-permission-recruitment-user
Open

galgalrobot wants to merge 2 commits into
devfrom
feat/#212-permission-recruitment-user

Conversation

@galgalrobot

@galgalrobot galgalrobot commented Sep 26, 2026 •

Copy link
Copy Markdown

💡 개요

공통 권한 모듈을 활용하여 recruitment, user 도메인의 Admin API에 Permission 기반 인가를 적용하고,
recruitment 평가 영역의 요청자 인가 및 평가 범위 판정을 Permission + ScopeGuard 기반으로 전환했습니다.

PR 리뷰를 반영하여 평가자 조회 기준도 기존 role/teamName 기반에서 EffectivePermissions 기반으로 변경했으며,
추가 검토 과정에서 확인된 설계문서와 구현 간 불일치 및 일부 엣지 케이스를 함께 보완했습니다.

🪐 주요 변경 사항

대상 변경
RecruitmentAdminController 모집 공고, CSV, 지원서 삭제, 사전알림 관련 API에 RECRUITMENT_NOTICE_READ/WRITE, APPLICANT_CSV_READ, APPLICATION_DELETE_ALL, PRE_NOTIFICATION_READ/DELETE 적용
ApplicantEvaluationAdminController / RecruitmentService EVALUATION_OWN_TRACK_WRITE, EVALUATION_ALL_TRACK_WRITE, FINAL_DECISION_READ/WRITE 적용 및 평가 범위에 ScopeGuard 사용
평가자 조회 findEvaluatorPool의 role/teamName 기준을 제거하고 EffectivePermissions 기반으로 현재 평가 가능자 판정
UserAdminController / UserAdminService 정회원 승격에 MEMBER_PROMOTION_WRITE 적용 및 finalDecision == PASS 검증 추가
DefaultPermissions 설계문서 기준으로 HOST의 ADMIN_ACCOUNT_SELF_READ 제거
Test Permission Grid, Unit, Integration Test 보강

✅ 상세 내용

1. 평가 권한 및 평가자 조회

평가 API의 기존 role/teamName 기반 판정을 Permission 기반으로 변경했습니다.

  • EVALUATION_OWN_TRACK_WRITE 보유자는 본인 부문만 접근 가능합니다.
  • EVALUATION_ALL_TRACK_WRITE 보유자는 전 부문에 접근 가능합니다.
  • 단건 조회/수정은 ScopeGuard.checkTrack()으로 부문 범위를 검증합니다.
  • 목록 조회는 EVALUATION_ALL_TRACK_WRITE 보유 여부를 기준으로 필터링합니다.

PR 리뷰를 반영하여 기존 findEvaluatorPool의 role/teamName 조건도 제거했습니다.

현재 평가 가능자는 live Admin의 EffectivePermissions를 기준으로

  • EVALUATION_ALL_TRACK_WRITE
  • 또는 EVALUATION_OWN_TRACK_WRITE + 동일 track

인 경우에만 포함됩니다.

또한 이후 권한이 REVOKE되거나 변경되더라도,
이미 해당 지원자를 평가한 Admin은 과거 평가 작성자로 계속 유지됩니다.

근거

  • 권한 모듈 사용 가이드: EffectivePermissions = Default - REVOKE + GRANT
  • 권한 모델 설계: OWN/ALL 평가 Permission 및 ScopeGuard 기반 범위 판정
  • PR Review: 평가자 판정을 EffectivePermissions 기준으로 변경하고 기존 평가 작성자 유지 요청

2. 설계문서와 기존 구현 불일치 수정

최종 합불 수정

기존에는 FINAL_DECISION_WRITE 권한이 있어도
서류 평가용 checkTrack()을 추가로 검사하고 있었습니다.

설계상 track 범위는
EVALUATION_OWN_TRACK_WRITE / EVALUATION_ALL_TRACK_WRITE가 담당하는 서류 평가 범위이고,
최종 합불은 별도의 FINAL_DECISION_WRITE 권한으로 정의되어 있습니다.

따라서 최종 합불 수정에서는 평가용 track 검증을 제거하고,
FINAL_DECISION_WRITE 보유 여부만으로 판정하도록 수정했습니다.

근거

  • 권한 모델 수정안 v3
  • 권한 모델 수정안 압축본
  • FINAL_PERMISSION_MATRIX
  • 권한 모듈 사용 가이드의 Permission / ScopeGuard 구조

HOST 기본 권한

기존에는 (HOST, 그룹리더)에게
ADMIN_ACCOUNT_SELF_READ, ADMIN_ACCOUNT_SELF_WRITE가 모두 기본 부여되고 있었습니다.

설계문서에서는 HOST 기본 권한을
ADMIN_ACCOUNT_SELF_WRITE만으로 정의하고 있어
ADMIN_ACCOUNT_SELF_READ를 제거했습니다.

GET /accounts/me는 설계 가이드상 별도의 account-read Permission을 요구하지 않는 self endpoint이므로,
해당 권한 제거 이후에도 기존대로 접근 가능합니다.

근거

  • 권한 모델 수정안 압축본: (HOST, 그룹리더) = { ADMIN_ACCOUNT_SELF_WRITE }
  • FINAL_PERMISSION_MATRIX: HOST의 본인 계정 조회 권한 X
  • 권한 모듈 사용 가이드: /accounts/me는 Permission을 요구하지 않는 self endpoint

3. 설계문서에 없는 엣지 케이스 보완

아래 내용은 설계문서에 세부 처리 규칙이 명시되어 있지 않아,
추가 검토 과정에서 데이터 정합성 및 비즈니스 무결성을 위해 보완했습니다.

  • soft-delete 평가자 기록

    • 기존에는 soft-delete된 평가자의 평가가 집계에는 포함되지만,
      상세/면접 질문에서는 제외되어 집계 결과와 상세 데이터가 일치하지 않는 문제가 있었습니다.
    • 이를 현재 평가 가능 여부와 과거 평가 기록을 분리하는 방향으로 정리했습니다.
    • soft-delete된 계정은 현재 평가 가능자에서는 제외되며 새 평가는 작성할 수 없습니다.
    • 다만 이미 작성한 평가는 과거 기록으로 간주하여 집계 / 상세 / 면접 질문에 계속 유지합니다.
    • 평가 이력이 없는 soft-delete 계정은 평가자 목록에 새롭게 노출되지 않습니다.
    • 판단 근거: 리뷰에서 권한이 변경되더라도 기존 평가 결과는 유지되어야 한다는 방향이 제시되었고, soft-delete 역시 현재 평가 권한과 이미 생성된 평가 기록을 분리하는 것이 동일한 원칙에 부합한다고 판단했습니다.
  • 정회원 승격 대상 검증

    • 설계문서에는 합격자 정회원 승격 → MEMBER_PROMOTION_WRITE 권한 매핑까지 정의되어 있으며,
      finalDecision == PASS를 서비스에서 검증하는 세부 규칙은 명시되어 있지 않습니다.
    • 기존에는 SUBMITTED 지원서가 존재하면 FAIL / PENDING 지원자도 승격 가능한 경로가 있었습니다.
    • MEMBER_PROMOTION_WRITE는 누가 승격 기능을 사용할 수 있는지에 대한 인가로 그대로 유지하고,
      별도로 finalDecision == PASS인지 확인하여 실제 승격 대상인지 검증하도록 보완했습니다.
    • PASS인 경우에만 승격하며, FAIL / PENDING은 APPLICANT_NOT_PASSED로 처리합니다.
    • 판단 근거: 프론트에서 잘못된 userId를 넘기거나 운영 중 실수가 발생하더라도, FAIL/PENDING 지원자가 실제 MEMBER로 승격되지 않도록 서버에서 PASS 여부를 추가로 검증하도록 했습니다.

4. 테스트

Permission Grid, Unit, Integration Test를 통해 다음을 검증했습니다.

  • OWN / ALL track 평가 권한
  • GRANT / REVOKE 반영
  • 기존 평가 작성자 및 soft-delete 작성자 기록 유지
  • 최종 합불 cross-track 수정
  • HOST SELF_READ 제거 및 /accounts/me 접근 유지
  • 정회원 승격 PASS / FAIL / PENDING
  • bulk promotion 기존 부분 성공 동작

전체 테스트 결과:

./gradlew test

  • Test: 1294
  • Pass: 1294
  • Fail: 0
  • Skip: 0

🔔 참고 사항

  • SecurityConfig, Permission, EffectivePermissions, ScopeGuard의 기존 구조는 그대로 유지했습니다.
  • DefaultPermissions의 HOST 기본 권한만 설계문서와 일치하도록 수정했습니다.
  • bulkPromote의 사용자별 트랜잭션 / 부분 성공 방식은 기존 API 계약이므로 변경하지 않았습니다.
  • soft-delete 평가 기록 보존과 PASS 승격 검증은 설계문서에 명시되지 않은 추가 보완 사항입니다.
  • CSV는 기존과 동일하게 APPLICANT_CSV_READ 권한 기준을 유지했습니다.

@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: BOAZ-website/backend/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 855c7d34-9c01-448e-9c84-b8e323047fe5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@seoyeon83 seoyeon83 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

따로 코멘트 남긴 부분에 수정이 필요할 것 같아요. 그 외에는 괜찮아 보입니다.

scopeGuard.checkTrack(currentAdmin, permissions, applicant.getTrack());

// 평가자 풀 = 해당 부문 + 차기 대표진(전 부문 평가 권한). 미작성자도 포함.
List<Admin> evaluators = adminRepository.findEvaluatorPool(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

findEvaluatorPool() 함수의 경우, track + team_name 을 기반으로 동작하는 것으로 알고 있습니다.

그런데 이번에 권한 체계가 개편되면서 해당 부문과 차기 대표진이 아닌 운영진도 EVALUATION_ALL_TRACK_WRITE (전부문에 평가 가능) 권한이 부여될 수 있습니다. 이때 기존 findEvaluatorPool() 함수가 유지되면 대시보드 상에서 그 운영진의 평가가 보이지 않는 문제가 생기게 됩니다. (지원자 A에 대한 운영진의 평가는 다른 운영진도 볼 수 있어야 하기 때문)

이 부분의 경우 서비스 로직을 수정하는 것이지만 이번 작업에서 같이 수정해주셔야 할 것 같아요.

수정 관련해 당장 드는 제안 사항은 다음과 같아요. 수정하실 때 참고해 주세요.

  • 권한 모델을 개편하면서 기존에 사용했던 findEvaluatorPool()같은 JPQL 대신 EffectivePermission 을 활용하면 좋을 것 같아요.
  • 응답 평가자를 산출할 때 현재 평가 가능자 뿐만 아니라 이미 이 지원자를 평가한 admin 으로 두어야 평가 기간 중에 권한이 빠지더라도 평가 결과가 남아 있도록 할 수 있을 것 같습니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

말씀해주신 내용 반영했습니다!

  • findEvaluatorPool()의 role/teamName 기반 조회를 제거하고 EffectivePermissions 기반으로 평가 가능자를 판정하도록 변경했습니다.
  • 또한 권한이 변경되더라도 이미 평가를 작성한 Admin은 평가자 목록에 유지되도록 수정했습니다. 관련 테스트도 함께 보강했습니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

그리고 추가적으로 설계문서에 세부 규칙이 없던 엣지 케이스도 함께 보완했습니다.

  • soft-delete된 평가자는 새 평가는 할 수 없지만 기존 평가 기록은 집계/상세/면접 질문에 유지하도록 했고, 리뷰에서 말씀해주신 “권한이 변경돼도 기존 평가 결과는 남아 있어야 한다”는 방향이 soft-delete 된 평가자에도 적용을 하는게 맞다고 생각하였습니다.
  • 정회원 승격은 사용자 실수로 FAIL·PENDING 지원자가 MEMBER로 승격되는 것을 막기 위해, 기존 MEMBER_PROMOTION_WRITE 인가는 유지하면서 서버에서 finalDecision == PASS 여부를 추가 검증하도록 했습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 권한 모델 개편 - recruitment, user 도메인 적용

2 participants