From 1cbaf1b87385a830fc401c2335cb326f4137ae90 Mon Sep 17 00:00:00 2001 From: kent Date: Sun, 21 Dec 2025 15:13:01 +0900 Subject: [PATCH] =?UTF-8?q?refactor(dev-tools):=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20=ED=86=B5=ED=95=A9=20=EB=B0=8F=20?= =?UTF-8?q?=ED=85=8C=EB=84=8C=ED=8A=B8=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 인증 모달 통합 - api-explorer, flow-tester, api-logs 3개 페이지의 인증 UI 통합 - 공유 컴포넌트 생성: auth-modal.blade.php, auth-scripts.blade.php - sessionStorage 기반으로 페이지 간 인증 상태 공유 - DevToolsAuth 글로벌 JavaScript API 제공 ## 테넌트 사용자 조회 개선 - 시스템 헤더에서 선택한 테넌트의 사용자 목록 표시 - 관리자가 모든 테넌트의 사용자 조회 가능 (소속 무관) - session('selected_tenant_id')로 Tenant 모델 직접 조회 - 테넌트 미선택 시 안내 메시지 표시 ## 버그 수정 - /users 페이지 HTMX swap 오류 수정 (JSON→HTML 직접 반환) - 사용자 이름 JavaScript 이스케이프 처리 (@js() 사용) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../Controllers/Api/Admin/UserController.php | 6 +- .../DevTools/ApiExplorerController.php | 41 +- .../DevTools/FlowTesterController.php | 2 +- app/Models/Admin/AdminApiFlow.php | 18 +- resources/views/api-logs/index.blade.php | 164 +++----- resources/views/auth/login.blade.php | 2 +- .../dev-tools/api-explorer/index.blade.php | 246 +---------- .../dev-tools/flow-tester/index.blade.php | 264 +----------- .../dev-tools/partials/auth-modal.blade.php | 89 ++++ .../dev-tools/partials/auth-scripts.blade.php | 389 ++++++++++++++++++ resources/views/users/index.blade.php | 7 +- .../views/users/partials/table.blade.php | 8 +- 12 files changed, 604 insertions(+), 632 deletions(-) create mode 100644 resources/views/dev-tools/partials/auth-modal.blade.php create mode 100644 resources/views/dev-tools/partials/auth-scripts.blade.php diff --git a/app/Http/Controllers/Api/Admin/UserController.php b/app/Http/Controllers/Api/Admin/UserController.php index 2a27b70d..020680f4 100644 --- a/app/Http/Controllers/Api/Admin/UserController.php +++ b/app/Http/Controllers/Api/Admin/UserController.php @@ -19,18 +19,18 @@ public function __construct( /** * 사용자 목록 조회 */ - public function index(Request $request): JsonResponse + public function index(Request $request): JsonResponse|\Illuminate\Http\Response { $users = $this->userService->getUsers( $request->all(), $request->integer('per_page', 10) ); - // HTMX 요청인 경우 HTML 반환 + // HTMX 요청인 경우 HTML 직접 반환 if ($request->header('HX-Request')) { $html = view('users.partials.table', compact('users'))->render(); - return response()->json(['html' => $html]); + return response($html)->header('Content-Type', 'text/html'); } // 일반 API 요청인 경우 JSON 반환 diff --git a/app/Http/Controllers/DevTools/ApiExplorerController.php b/app/Http/Controllers/DevTools/ApiExplorerController.php index 1026d43a..d3b9286d 100644 --- a/app/Http/Controllers/DevTools/ApiExplorerController.php +++ b/app/Http/Controllers/DevTools/ApiExplorerController.php @@ -447,31 +447,50 @@ public function setDefaultEnvironment(int $id): JsonResponse /** * 현재 테넌트의 사용자 목록 + * 시스템 헤더에서 선택한 테넌트 기준 (session('selected_tenant_id')) + * 관리자는 자신이 속하지 않은 테넌트의 사용자도 볼 수 있어야 함 */ public function users(): JsonResponse { - // user_tenants 피벗 테이블에서 기본 테넌트 조회 - $defaultTenant = \DB::table('user_tenants') - ->where('user_id', auth()->id()) - ->where('is_default', true) - ->first(); + // 세션에서 직접 테넌트 ID 조회 (관리자가 선택한 테넌트) + $selectedTenantId = session('selected_tenant_id'); - if (!$defaultTenant) { + if (!$selectedTenantId) { + // 테넌트가 선택되지 않은 경우 로그인 사용자의 기본 테넌트 사용 + $currentTenant = auth()->user()->tenants() + ->where('is_default', true) + ->first() ?? auth()->user()->tenants()->first(); + + if (!$currentTenant) { + return response()->json([]); + } + + $selectedTenantId = $currentTenant->id; + } + + // Tenant 모델에서 직접 조회 (사용자의 테넌트 관계와 무관하게) + $tenant = \App\Models\Tenants\Tenant::find($selectedTenantId); + + if (!$tenant) { return response()->json([]); } - $tenantId = $defaultTenant->tenant_id; - // 해당 테넌트에 속한 사용자 목록 조회 - $users = \App\Models\User::whereHas('tenants', function ($query) use ($tenantId) { - $query->where('tenant_id', $tenantId); + $users = \App\Models\User::whereHas('tenants', function ($query) use ($selectedTenantId) { + $query->where('tenant_id', $selectedTenantId); }) ->select(['id', 'name', 'email']) ->orderBy('name') ->limit(100) ->get(); - return response()->json($users); + return response()->json([ + 'tenant' => [ + 'id' => $tenant->id, + 'name' => $tenant->company_name, + ], + 'users' => $users, + ]); } /** diff --git a/app/Http/Controllers/DevTools/FlowTesterController.php b/app/Http/Controllers/DevTools/FlowTesterController.php index 0f5ed537..2042a752 100644 --- a/app/Http/Controllers/DevTools/FlowTesterController.php +++ b/app/Http/Controllers/DevTools/FlowTesterController.php @@ -21,7 +21,7 @@ class FlowTesterController extends Controller */ public function index(): View { - $flows = AdminApiFlow::with(['runs' => fn ($q) => $q->latest()->limit(1)]) + $flows = AdminApiFlow::with('latestRun') ->orderByDesc('created_at') ->paginate(20); diff --git a/app/Models/Admin/AdminApiFlow.php b/app/Models/Admin/AdminApiFlow.php index 6aaf801d..05249a90 100644 --- a/app/Models/Admin/AdminApiFlow.php +++ b/app/Models/Admin/AdminApiFlow.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\HasOne; /** * API Flow Tester - 플로우 정의 모델 @@ -83,9 +84,22 @@ public function updater(): BelongsTo } /** - * 최근 실행 결과 조회 + * 관계: 최신 실행 기록 (서브쿼리 방식 - window function 회피) */ - public function latestRun(): ?AdminApiFlowRun + public function latestRun(): HasOne + { + return $this->hasOne(AdminApiFlowRun::class, 'flow_id') + ->whereIn('id', function ($query) { + $query->selectRaw('MAX(id)') + ->from('admin_api_flow_runs') + ->groupBy('flow_id'); + }); + } + + /** + * 최근 실행 결과 조회 (단일 조회용) + */ + public function getLatestRunResult(): ?AdminApiFlowRun { return $this->runs()->latest('created_at')->first(); } diff --git a/resources/views/api-logs/index.blade.php b/resources/views/api-logs/index.blade.php index 19c4b90a..c434d19b 100644 --- a/resources/views/api-logs/index.blade.php +++ b/resources/views/api-logs/index.blade.php @@ -7,6 +7,13 @@

API 요청 로그

+ +
@csrf
- -
- -
- - -
-
- - -
- - - @if($savedToken ?? false) -

✅ 세션에 저장된 토큰이 자동으로 입력되었습니다.

- @endif -
- - - - - + + @include('dev-tools.partials.auth-modal')
@@ -402,6 +320,9 @@ class="w-full border rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-5 @endsection @push('scripts') +{{-- 공유 인증 스크립트 --}} +@include('dev-tools.partials.auth-scripts') + @endpush diff --git a/resources/views/dev-tools/partials/auth-modal.blade.php b/resources/views/dev-tools/partials/auth-modal.blade.php new file mode 100644 index 00000000..20d2f8d1 --- /dev/null +++ b/resources/views/dev-tools/partials/auth-modal.blade.php @@ -0,0 +1,89 @@ +{{-- + Dev Tools 공유 인증 모달 + 사용법: @include('dev-tools.partials.auth-modal') +--}} + + + diff --git a/resources/views/dev-tools/partials/auth-scripts.blade.php b/resources/views/dev-tools/partials/auth-scripts.blade.php new file mode 100644 index 00000000..d0452664 --- /dev/null +++ b/resources/views/dev-tools/partials/auth-scripts.blade.php @@ -0,0 +1,389 @@ +{{-- + Dev Tools 공유 인증 스크립트 + 사용법: @include('dev-tools.partials.auth-scripts') + + 제공 API: + - DevToolsAuth.openModal() : 인증 모달 열기 + - DevToolsAuth.closeModal() : 인증 모달 닫기 + - DevToolsAuth.getToken() : 현재 토큰 반환 + - DevToolsAuth.getUserId() : 현재 사용자 ID 반환 + - DevToolsAuth.isAuthenticated() : 인증 여부 반환 + - DevToolsAuth.getAuthPayload() : API 요청용 인증 페이로드 반환 + - DevToolsAuth.onAuthChange(callback) : 인증 상태 변경 콜백 등록 +--}} + + diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php index 1710f741..4e66daef 100644 --- a/resources/views/users/index.blade.php +++ b/resources/views/users/index.blade.php @@ -61,13 +61,10 @@ class="bg-white rounded-lg shadow-sm overflow-hidden"> htmx.trigger('#user-table', 'filterSubmit'); }); - // HTMX 응답 처리 + // HTMX 응답 후 필요한 초기화 처리 document.body.addEventListener('htmx:afterSwap', function(event) { if (event.detail.target.id === 'user-table') { - const response = JSON.parse(event.detail.xhr.response); - if (response.html) { - event.detail.target.innerHTML = response.html; - } + // 필요시 테이블 로드 후 초기화 작업 } }); diff --git a/resources/views/users/partials/table.blade.php b/resources/views/users/partials/table.blade.php index e097942d..ea5a90cc 100644 --- a/resources/views/users/partials/table.blade.php +++ b/resources/views/users/partials/table.blade.php @@ -99,13 +99,13 @@ @if($user->deleted_at) @if($canModify) - @endif @if(auth()->user()?->is_super_admin) - @@ -115,7 +115,7 @@ class="text-red-600 hover:text-red-900"> @endif @elseif($canModify) - @else