이동된 파일: - 2025-12-02_file-attachment-feature.md - ai-config-설정.md - archive-restore-feature-analysis.md - barobill-members-migration.md - super-admin-protection.md - 명함추출로직.md - 모달창_생성시_유의사항.md - 상품관리정보.md - 수당지급.md - 영업파트너구조.md - 홈택스 매입매출 조회성공.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.0 KiB
6.0 KiB
Super Admin Protection Feature
날짜: 2025-12-01 작업자: Claude Code 요청: 슈퍼관리자 보호 및 복원/영구삭제 권한 분리
1. 요구사항
1.1 슈퍼관리자 보호
- 일반관리자는 슈퍼관리자를 볼 수 없음 (목록에서 숨김)
- 일반관리자는 슈퍼관리자를 수정/삭제할 수 없음
- 슈퍼관리자만 다른 슈퍼관리자를 관리 가능
1.2 복원/영구삭제 권한 분리
- 복원 (Restore): 일반관리자도 가능
- 영구삭제 (Force Delete): 슈퍼관리자 전용
2. 구현 내용
2.1 라우트 수정 (routes/api.php)
8개 엔티티의 restore 라우트를 super.admin 미들웨어 밖으로 이동:
| 엔티티 | 라인 | 복원 라우트 | 영구삭제 라우트 |
|---|---|---|---|
| Tenants | 42-48 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| Departments | 76-82 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| Users | 93-99 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| Menus | 117-123 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| Boards | 151-157 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| PM Projects | 234-240 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| PM Tasks | 260-266 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
| PM Issues | 292-298 | POST /{id}/restore |
DELETE /{id}/force (super.admin) |
패턴:
// 복원 (일반관리자 가능)
Route::post('/{id}/restore', [Controller::class, 'restore'])->name('restore');
// 슈퍼관리자 전용 액션 (영구삭제)
Route::middleware('super.admin')->group(function () {
Route::delete('/{id}/force', [Controller::class, 'forceDestroy'])->name('forceDestroy');
});
2.2 서비스 레이어 수정
app/Services/UserService.php
public function canAccessUser(int $targetUserId): bool
{
// withTrashed()를 사용하여 soft-deleted 사용자도 확인 (복원 시 필요)
$targetUser = User::withTrashed()->find($targetUserId);
$currentUser = auth()->user();
// 대상 사용자가 슈퍼관리자이고 현재 사용자가 슈퍼관리자가 아니면 접근 불가
if ($targetUser?->is_super_admin && ! $currentUser?->is_super_admin) {
return false;
}
return true;
}
app/Services/UserPermissionService.php
public function canModifyUser(int $targetUserId): bool
{
// withTrashed()를 사용하여 일관성 유지
$targetUser = User::withTrashed()->find($targetUserId);
$currentUser = auth()->user();
if ($targetUser?->is_super_admin && ! $currentUser?->is_super_admin) {
return false;
}
return true;
}
핵심 수정: User::find() → User::withTrashed()->find()
- Soft-deleted 사용자도 조회 가능하게 변경
- 복원 작업 시 권한 체크가 정상 작동
2.3 뷰 레이어 수정
6개 테이블 뷰에 권한별 버튼 표시 로직 적용:
| 파일 | 복원 버튼 | 영구삭제 버튼 |
|---|---|---|
users/partials/table.blade.php |
$canModify 체크 |
is_super_admin 체크 |
users/partials/modal-info.blade.php |
슈퍼관리자이거나 대상이 일반사용자 | - |
departments/partials/table.blade.php |
항상 표시 | is_super_admin 체크 |
menus/partials/table.blade.php |
항상 표시 | is_super_admin 체크 |
boards/partials/table.blade.php |
항상 표시 | is_super_admin 체크 |
tenants/partials/table.blade.php |
항상 표시 | is_super_admin 체크 |
project-management/projects/partials/table.blade.php |
항상 표시 | is_super_admin 체크 |
Blade 패턴:
@if($item->deleted_at)
<!-- 삭제된 항목 - 복원은 일반관리자도 가능, 영구삭제는 슈퍼관리자만 -->
<button onclick="confirmRestore({{ $item->id }}, '{{ $item->name }}')">
복원
</button>
@if(auth()->user()?->is_super_admin)
<button onclick="confirmForceDelete({{ $item->id }}, '{{ $item->name }}')">
영구삭제
</button>
@endif
@endif
3. 수정된 파일 목록
라우트
routes/api.php- 8개 엔티티 restore 라우트 분리
서비스
app/Services/UserService.php-canAccessUser()withTrashed 적용app/Services/UserPermissionService.php-canModifyUser()withTrashed 적용
뷰 (Blade)
resources/views/users/partials/table.blade.phpresources/views/users/partials/modal-info.blade.phpresources/views/departments/partials/table.blade.phpresources/views/menus/partials/table.blade.phpresources/views/boards/partials/table.blade.phpresources/views/tenants/partials/table.blade.phpresources/views/project-management/projects/partials/table.blade.php
4. 테스트 시나리오
4.1 일반관리자 테스트
- 사용자 목록에서 슈퍼관리자가 보이지 않음
- 삭제된 사용자 복원 가능
- 삭제된 부서/메뉴/게시판/테넌트/프로젝트 복원 가능
- 영구삭제 버튼이 보이지 않음
- 슈퍼관리자 수정/삭제 불가 (API 레벨)
4.2 슈퍼관리자 테스트
- 모든 사용자 조회 가능 (슈퍼관리자 포함)
- 삭제된 항목 복원 가능
- 영구삭제 가능
- 다른 슈퍼관리자 관리 가능
5. 이슈 해결
5.1 302 Found 에러
문제: 일반관리자가 복원 API 호출 시 302 리다이렉트 발생
원인: restore 라우트가 super.admin 미들웨어 내부에 있었음
해결: restore 라우트를 미들웨어 밖으로 이동
5.2 Soft-deleted 사용자 권한 체크 실패
문제: User::find()가 soft-deleted 사용자를 조회하지 못함
원인: Eloquent 기본 동작으로 soft-deleted 레코드 제외
해결: User::withTrashed()->find() 사용
6. 관련 문서
claudedocs/archive-restore-feature-analysis.md- 아카이브/복원 기능 분석CURRENT_WORKS.md- 작업 히스토리