테넌트 CRUD 기능 수정

주요 수정사항:
- UpdateTenantRequest: 라우트 파라미터 수정 (tenant → id)
- TenantService: 영구 삭제 시 관련 데이터 먼저 삭제 (FK 제약 해결)
- edit.blade.php: HTMX URL 전체 경로 사용 + 폼 fallback 추가
- index.blade.php: CSRF 토큰 추가 (삭제, 복원, 영구삭제)

버그 수정:
- 수정 시 302 리다이렉트 오류 해결 (code 유일성 검증 실패)
- 삭제 시 419 CSRF 토큰 오류 해결
- 영구 삭제 시 500 FK 제약 오류 해결
This commit is contained in:
2025-11-24 11:42:01 +09:00
parent f49cfd982a
commit bc3777ace5
4 changed files with 36 additions and 5 deletions

View File

@@ -20,7 +20,7 @@ public function authorize(): bool
*/
public function rules(): array
{
$tenantId = $this->route('tenant');
$tenantId = $this->route('id');
return [
// 기본 정보 (필수)

View File

@@ -104,6 +104,13 @@ public function restoreTenant(int $id): bool
public function forceDeleteTenant(int $id): bool
{
$tenant = Tenant::withTrashed()->findOrFail($id);
// 관련 데이터 먼저 삭제
$tenant->users()->detach(); // user_tenants 관계 삭제
$tenant->departments()->forceDelete(); // 부서 영구 삭제
$tenant->menus()->forceDelete(); // 메뉴 영구 삭제
$tenant->roles()->forceDelete(); // 역할 영구 삭제
return $tenant->forceDelete();
}

View File

@@ -15,9 +15,13 @@
<!-- 영역 -->
<div class="bg-white rounded-lg shadow-sm p-6">
<form id="tenantForm"
hx-put="/api/admin/tenants/{{ $tenant->id }}"
action="/api/admin/tenants/{{ $tenant->id }}"
method="POST"
hx-put="{{ url('/api/admin/tenants/' . $tenant->id) }}"
hx-headers='{"X-CSRF-TOKEN": "{{ csrf_token() }}"}'
hx-swap="none">
@method('PUT')
@csrf
<!-- 기본 정보 -->
<div class="mb-8">
@@ -186,7 +190,6 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition"
@endsection
@push('scripts')
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<script>
// HTMX 응답 처리
document.body.addEventListener('htmx:afterRequest', function(event) {

View File

@@ -90,7 +90,10 @@ class="bg-white rounded-lg shadow-sm overflow-hidden">
if (confirm(`"${name}" 테넌트를 삭제하시겠습니까?`)) {
htmx.ajax('DELETE', `/api/admin/tenants/${id}`, {
target: '#tenant-table',
swap: 'none'
swap: 'none',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
}).then(() => {
htmx.trigger('#tenant-table', 'filterSubmit');
});
@@ -102,7 +105,25 @@ class="bg-white rounded-lg shadow-sm overflow-hidden">
if (confirm(`"${name}" 테넌트를 복원하시겠습니까?`)) {
htmx.ajax('POST', `/api/admin/tenants/${id}/restore`, {
target: '#tenant-table',
swap: 'none'
swap: 'none',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
}).then(() => {
htmx.trigger('#tenant-table', 'filterSubmit');
});
}
};
// 영구삭제 확인
window.confirmForceDelete = function(id, name) {
if (confirm(`"${name}" 테넌트를 영구 삭제하시겠습니까?\n\n⚠ 이 작업은 되돌릴 수 없습니다!`)) {
htmx.ajax('DELETE', `/api/admin/tenants/${id}/force`, {
target: '#tenant-table',
swap: 'none',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
}).then(() => {
htmx.trigger('#tenant-table', 'filterSubmit');
});