# MNG 레이아웃 패턴 가이드 **작성일:** 2025-01-24 **목적:** MNG 프로젝트의 표준 페이지 레이아웃 패턴 문서화 --- ## 📋 목차 1. [기본 레이아웃 구조](#1-기본-레이아웃-구조) 2. [Tenant Selector 패턴](#2-tenant-selector-패턴) 3. [페이지별 적용 가이드](#3-페이지별-적용-가이드) 4. [컨텐츠 영역 구조](#4-컨텐츠-영역-구조) 5. [체크리스트](#5-체크리스트) --- ## 1. 기본 레이아웃 구조 ### 1.1 전체 구조 ``` ┌─────────────────────────────────────────────────────┐ │ Header (상단) │ │ - 로고, 사용자 정보, 알림 등 │ ├──────────┬──────────────────────────────────────────┤ │ │ │ │ │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ 테넌트 선택 드롭다운 │ │ │ Sidebar │ │ [전체보기] [A회사] [B회사] │ │ │ │ └─────────────────────────────────┘ │ │ (좌측 │ │ │ 메뉴) │ │ │ │ 페이지 제목 [+ 버튼] │ │ │ │ │ │ │ │ │ [검색] [필터1] [필터2] [검색버튼] │ │ │ │ │ │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ 데이터 테이블 또는 컨텐츠 │ │ │ │ │ │ │ │ │ │ (HTMX 동적 로딩 영역) │ │ │ │ └─────────────────────────────────┘ │ │ │ │ └──────────┴──────────────────────────────────────────┘ ``` ### 1.2 레이아웃 파일 구조 ``` resources/views/ ├── layouts/ │ └── app.blade.php # 메인 레이아웃 ├── partials/ │ ├── sidebar.blade.php # 좌측 메뉴 │ ├── header.blade.php # 상단 헤더 │ ├── tenant-selector.blade.php # 테넌트 선택기 (공통) │ └── pagination.blade.php # 페이지네이션 └── [feature]/ ├── index.blade.php # 목록 페이지 ├── create.blade.php # 생성 페이지 ├── edit.blade.php # 수정 페이지 └── partials/ └── table.blade.php # HTMX 응답용 테이블 ``` --- ## 2. Tenant Selector 패턴 ### 2.1 역할과 목적 **Tenant Selector는 모든 데이터 관리 페이지 상단에 위치하는 공통 컴포넌트입니다.** - **목적**: 사용자가 특정 테넌트의 데이터만 필터링하여 볼 수 있도록 함 - **위치**: `@section('content')` 직후, 페이지 컨텐츠 최상단 - **예외**: 테넌트 관리 페이지 (`tenants/index.blade.php`)는 제외 ### 2.2 Tenant Selector 구조 **파일**: `resources/views/partials/tenant-selector.blade.php` ```blade
...
@csrf
@if(session('selected_tenant_id')) {{ $currentTenant->company_name }} 데이터만 표시 중 @else 전체 테넌트 데이터 표시 중 @endif
``` ### 2.3 Tenant Selector 동작 방식 1. **드롭다운 변경** → 폼 자동 제출 2. **POST /tenant/switch** → TenantController@switch 3. **세션 저장** → `session('selected_tenant_id')` 4. **페이지 리로드** → 선택된 테넌트 데이터만 표시 ### 2.4 백엔드 연동 **TenantController@switch** (예시): ```php public function switch(Request $request): RedirectResponse { $tenantId = $request->input('tenant_id'); if ($tenantId === 'all') { session()->forget('selected_tenant_id'); } else { session(['selected_tenant_id' => $tenantId]); } return redirect()->back(); } ``` **Service Layer** (자동 필터링): ```php public function getRoles(array $filters = []): LengthAwarePaginator { $tenantId = session('selected_tenant_id'); $query = Role::query(); // Tenant 필터링 if ($tenantId) { $query->where('tenant_id', $tenantId); } return $query->paginate(15); } ``` --- ## 3. 페이지별 적용 가이드 ### 3.1 일반 데이터 관리 페이지 (Tenant Selector 포함) **적용 대상**: 역할, 사용자, 부서, 제품, 자재, BOM, 카테고리 등 **템플릿 구조**: ```blade @extends('layouts.app') @section('title', '역할 관리') @section('content') @include('partials.tenant-selector')

🔑 역할 관리

+ 새 역할
@endsection ``` ### 3.2 테넌트 관리 페이지 (Tenant Selector 제외) **적용 대상**: `tenants/index.blade.php` **템플릿 구조**: ```blade @extends('layouts.app') @section('title', '테넌트 관리') @section('content')

🏢 테넌트 관리

+ 새 테넌트
@endsection ``` **이유**: 테넌트 관리는 모든 테넌트를 관리하는 페이지이므로 테넌트 필터링이 불필요 ### 3.3 대시보드 (Tenant Selector 포함) **템플릿 구조**: ```blade @extends('layouts.app') @section('title', '대시보드') @section('content') @include('partials.tenant-selector')

환영합니다!

@endsection ``` --- ## 4. 컨텐츠 영역 구조 ### 4.1 페이지 헤더 ```blade

[아이콘] 페이지 제목

+ 새 항목
``` **주의사항**: - Tenant Selector가 있는 경우 → `mt-6` 추가 (위쪽 여백) - Tenant Selector가 없는 경우 → `mt-6` 생략 ### 4.2 필터 영역 ```blade
``` ### 4.3 HTMX 동적 컨텐츠 영역 ```blade
``` --- ## 5. 체크리스트 ### 5.1 Tenant Selector 포함 여부 확인 **포함해야 하는 페이지** (✅): - [ ] 역할 관리 (`roles/index.blade.php`) - [ ] 사용자 관리 (`users/index.blade.php`) - [ ] 부서 관리 (`departments/index.blade.php`) - [ ] 제품 관리 (`products/index.blade.php`) - [ ] 자재 관리 (`materials/index.blade.php`) - [ ] BOM 관리 (`boms/index.blade.php`) - [ ] 카테고리 관리 (`categories/index.blade.php`) - [ ] 대시보드 (`dashboard/index.blade.php`) **제외해야 하는 페이지** (❌): - [ ] 테넌트 관리 (`tenants/index.blade.php`) - [ ] 시스템 설정 (전역 설정 페이지) - [ ] 감사 로그 (전체 시스템 로그) ### 5.2 레이아웃 구현 체크리스트 **페이지 구조**: - [ ] `@extends('layouts.app')` 상속 - [ ] `@section('title', '페이지 제목')` 정의 - [ ] `@section('content')` 내부 구조: - [ ] `@include('partials.tenant-selector')` (필요 시) - [ ] 페이지 헤더 (`mt-6` 여백 확인) - [ ] 필터 영역 - [ ] HTMX 동적 컨텐츠 영역 **스타일 일관성**: - [ ] 카드 스타일: `bg-white rounded-lg shadow-sm` - [ ] 버튼 스타일: `btn-primary`, `btn-secondary` - [ ] 간격 일관성: `mb-6`, `mt-6`, `p-4`, `p-6` **HTMX 설정**: - [ ] `hx-get` 엔드포인트 설정 - [ ] `hx-trigger="load, filterSubmit from:body"` 설정 - [ ] `hx-include="#filterForm"` 설정 - [ ] CSRF 토큰 헤더 포함 --- ## 6. 예시 코드 ### 6.1 완전한 페이지 예시 (Tenant Selector 포함) ```blade @extends('layouts.app') @section('title', '역할 관리') @section('content') @include('partials.tenant-selector')

🔑 역할 관리

+ 새 역할
@endsection @push('scripts') @endpush ``` ### 6.2 ViewComposer로 $globalTenants 자동 주입 **파일**: `app/Providers/ViewServiceProvider.php` ```php use Illuminate\Support\Facades\View; use App\Models\Tenant; public function boot(): void { // 모든 뷰에 $globalTenants 변수 자동 주입 View::composer('partials.tenant-selector', function ($view) { $view->with('globalTenants', Tenant::orderBy('company_name')->get()); }); } ``` --- ## 7. 주의사항 ### 7.1 Tenant Selector 관련 1. **ViewComposer 필수**: `$globalTenants` 변수가 자동으로 주입되도록 ViewComposer 설정 필요 2. **세션 관리**: `selected_tenant_id` 세션이 Service Layer에서 자동으로 필터링에 사용됨 3. **페이지 리로드**: 테넌트 변경 시 전체 페이지가 리로드되어 모든 데이터가 새로 로드됨 4. **HTMX 연동**: Tenant 변경 후 HTMX 테이블도 자동으로 새로 로드됨 ### 7.2 레이아웃 스타일 1. **컨테이너 없음**: `@section('content')` 내부에는 기본 컨테이너가 없음 - Tenant Selector는 자체 패딩(`p-6`) 포함 - 나머지 컨텐츠는 페이지별로 여백 조정 2. **간격 일관성**: - Tenant Selector 하단: `mb-6` (내부 카드에 포함) - 페이지 헤더: `mt-6 mb-6` (Tenant Selector가 있을 때) - 필터 영역: `mb-6` - 컨텐츠 영역: 별도 여백 불필요 3. **반응형 디자인**: Tailwind CSS 유틸리티 클래스 사용 --- **작성자:** Claude **최종 수정일:** 2025-01-24 **버전:** 1.0 **참고**: Dashboard, Tenant 관리 시스템 레이아웃 기반