Files
sam-docs/projects/mng-mobile-responsive/02-implementation-plan.md
hskwon 1bac39f38c docs: MNG 모바일 반응형 Phase 3 완료 문서 업데이트
- PROGRESS.md Phase 3 완료 표시
- 02-implementation-plan.md Phase 3 상세 내용 업데이트
2025-12-19 16:20:20 +09:00

10 KiB

MNG 모바일 반응형 구현 계획

작성일: 2025-12-19 최종 수정: 2025-12-19 상태: 진행 중 (Phase 1 완료)

1. 구현 전략

1.1 기본 방침

  • Mobile-First 아님: 기존 데스크톱 레이아웃 유지하며 모바일 대응 추가
  • 점진적 개선: 핵심 레이아웃부터 단계별 적용
  • 기존 코드 최소 변경: 새로운 반응형 클래스 추가 방식
  • 테이블 스와이프: 카드형 변환 없이 수평 스크롤 개선

1.2 Breakpoint 전략

< 640px (sm 미만):   모바일 - 사이드바 숨김, 햄버거 메뉴
640px - 1024px:      태블릿 - 접힌 사이드바 또는 오버레이
1024px+ (lg):        데스크톱 - 전체 레이아웃 (현재 상태)

2. Phase 구성

Phase 1: 핵심 레이아웃 (필수) 완료

목표: 모바일에서 기본 사용 가능하게 완료일: 2025-12-19 커밋: 093e98b

항목 작업 내용 파일 상태
1-1 사이드바 모바일 오버레이 sidebar.blade.php
1-2 햄버거 메뉴 버튼 추가 header.blade.php
1-3 레이아웃 반응형 조정 app.blade.php
1-4 모바일 오버레이 백드롭 app.blade.php

구현 내용:

  • 모바일 사이드바 슬라이드 인/아웃 애니메이션
  • 햄버거 버튼 + 모바일 로고 추가
  • 반투명 백드롭 오버레이
  • ESC 키 및 메뉴 클릭 시 자동 닫힘

Phase 2: 헤더 최적화 완료

목표: 헤더 요소들의 모바일 배치 완료일: 2025-12-19

항목 작업 내용 파일 상태
2-1 사이드바에 모바일 테넌트 셀렉터 sidebar.blade.php
2-2 헤더에 모바일 테넌트 뱃지 header.blade.php
2-3 사용자 메뉴 모바일 최적화 header.blade.php

구현 내용:

  • 사이드바 상단에 모바일 전용 테넌트 드롭다운 추가 (lg:hidden)
  • 헤더 로고 옆에 현재 테넌트 뱃지 표시 (클릭 시 사이드바 열림)
  • 사용자 메뉴 chevron 아이콘 모바일에서 숨김, 패딩 축소

Phase 3: 테이블 스와이프 완료

목표: 모든 테이블에 스와이프 기능 적용 완료일: 2025-12-19

항목 작업 내용 대상 파일 상태
3-1 테이블 래퍼 컴포넌트 생성 components/table-swipe.blade.php
3-2 CSS 스크롤바/터치 스타일 resources/css/app.css
3-3 11개 테이블 적용 각 모듈 테이블
3-4 스와이프 힌트 UI table-swipe 컴포넌트 내장

구현 내용:

  • <x-table-swipe> Anonymous Blade 컴포넌트
  • -webkit-overflow-scrolling: touch 터치 스크롤 최적화
  • sm(640px) 미만에서 좌우 화살표 애니메이션 힌트
  • 스크롤바 얇은 스타일 (4px height)

Phase 4: 폼/필터 반응형

목표: 필터 영역과 버튼 그룹 모바일 최적화

항목 작업 내용 적용 범위
4-1 필터 영역 flex-wrap 각 index 페이지
4-2 버튼 그룹 스택 배치 각 페이지 헤더
4-3 모바일 필터 접기/펼치기 선택적 적용

예상 작업량: 낮음 의존성: 없음

Phase 5: 제외 메뉴 처리

목표: 모바일에서 어려운 메뉴 안내/제한

항목 작업 내용
5-1 데스크톱 전용 배너 컴포넌트
5-2 권한 매트릭스 페이지 적용
5-3 Flow Tester 페이지 적용
5-4 R&D Labs 영역 처리

예상 작업량: 낮음 의존성: 없음


3. 상세 구현 방안

3.1 사이드바 모바일 (Phase 1-1)

변경 전:

<aside id="sidebar" class="sidebar w-64">

변경 후:

<!-- 모바일 오버레이 백드롭 -->
<div id="sidebar-backdrop"
     class="fixed inset-0 bg-black/50 z-40 lg:hidden hidden"
     onclick="closeMobileSidebar()">
</div>

<!-- 사이드바: 모바일에서 fixed + transform -->
<aside id="sidebar"
       class="sidebar fixed inset-y-0 left-0 z-50 w-64
              transform -translate-x-full lg:translate-x-0 lg:static
              transition-transform duration-300 ease-in-out">

JavaScript 추가:

function openMobileSidebar() {
    document.getElementById('sidebar').classList.remove('-translate-x-full');
    document.getElementById('sidebar-backdrop').classList.remove('hidden');
    document.body.classList.add('overflow-hidden');
}

function closeMobileSidebar() {
    document.getElementById('sidebar').classList.add('-translate-x-full');
    document.getElementById('sidebar-backdrop').classList.add('hidden');
    document.body.classList.remove('overflow-hidden');
}

// ESC 키로 닫기
document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') closeMobileSidebar();
});

3.2 헤더 햄버거 버튼 (Phase 1-2)

<header class="h-16 flex items-center justify-between px-4 lg:px-6">
    <div class="flex items-center gap-2 lg:gap-4">
        <!-- 모바일 햄버거 -->
        <button onclick="openMobileSidebar()"
                class="p-2 rounded-lg hover:bg-gray-100 lg:hidden">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                      d="M4 6h16M4 12h16M4 18h16"/>
            </svg>
        </button>

        <!-- 모바일 로고 -->
        <span class="text-xl font-bold lg:hidden">SAM</span>

        <!-- 데스크톱 테넌트 셀렉터 (기존 유지) -->
        <div class="hidden lg:flex items-center gap-4">
            ...
        </div>
    </div>

3.3 테이블 스와이프 래퍼 (Phase 3-1)

새 컴포넌트: components/table-swipe.blade.php

@props(['showHint' => true])

<div class="relative">
    <!-- 스와이프 가능한 컨테이너 -->
    <div class="overflow-x-auto -mx-4 sm:mx-0 scrollbar-thin">
        <div class="inline-block min-w-full align-middle px-4 sm:px-0">
            {{ $slot }}
        </div>
    </div>

    <!-- 스와이프 힌트 (모바일에서만) -->
    @if($showHint)
    <div class="sm:hidden flex items-center justify-center gap-2 mt-2 text-xs text-gray-400">
        <svg class="w-4 h-4 animate-bounce-x" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16l-4-4m0 0l4-4m-4 4h18"/>
        </svg>
        <span>좌우로 스와이프</span>
        <svg class="w-4 h-4 animate-bounce-x" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
        </svg>
    </div>
    @endif
</div>

<style>
    @keyframes bounce-x {
        0%, 100% { transform: translateX(0); }
        50% { transform: translateX(3px); }
    }
    .animate-bounce-x {
        animation: bounce-x 1s ease-in-out infinite;
    }
</style>

적용 예시:

<!-- 변경 전 -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden">
    <table class="w-full">...</table>
</div>

<!-- 변경 후 -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden">
    <x-table-swipe>
        <table class="min-w-full">...</table>
    </x-table-swipe>
</div>

3.4 데스크톱 전용 배너 (Phase 5-1)

새 컴포넌트: components/desktop-only-banner.blade.php

<div class="lg:hidden bg-amber-50 border border-amber-200 rounded-lg p-4 mb-4">
    <div class="flex items-center gap-3">
        <svg class="w-6 h-6 text-amber-600 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                  d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
        </svg>
        <div>
            <p class="font-medium text-amber-800">데스크톱 환경 권장</p>
            <p class="text-sm text-amber-600">이 기능은 넓은 화면에서 더 잘 동작합니다.</p>
        </div>
    </div>
</div>

4. CSS 추가 사항

4.1 tailwind.config.js 수정 (선택)

module.exports = {
  theme: {
    extend: {
      // 필요시 추가 breakpoint
      screens: {
        'xs': '375px',  // 소형 모바일
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
  ],
}

4.2 app.css 추가

/* 스크롤바 스타일링 (선택) */
.scrollbar-thin::-webkit-scrollbar {
    height: 4px;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
    background-color: #d1d5db;
    border-radius: 2px;
}
.scrollbar-thin::-webkit-scrollbar-track {
    background-color: #f3f4f6;
}

/* 모바일 사이드바 오버레이 */
.sidebar-mobile-open {
    transform: translateX(0) !important;
}

/* 터치 스크롤 최적화 */
.overflow-x-auto {
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
}

5. 테스트 체크리스트

5.1 디바이스별 테스트

  • iPhone SE (375px)
  • iPhone 14 (390px)
  • iPhone 14 Pro Max (430px)
  • iPad Mini (768px)
  • iPad Pro (1024px)
  • 데스크톱 (1280px+)

5.2 기능별 테스트

  • 사이드바 열기/닫기
  • 햄버거 메뉴 동작
  • 테이블 스와이프
  • 테넌트 선택
  • 사용자 메뉴 드롭다운
  • 폼 입력
  • 필터 동작

5.3 성능 테스트

  • 초기 로딩 속도
  • 스크롤 부드러움
  • 애니메이션 프레임 드랍

6. 롤백 계획

각 Phase는 독립적으로 롤백 가능하도록 설계:

  • Git 브랜치: feature/mng-mobile-responsive
  • 각 Phase 완료 시 태그: v-mobile-phase-1, v-mobile-phase-2
  • 문제 발생 시 해당 Phase만 되돌리기

7. 추가 고려사항

7.1 Alpine.js 도입 검토

현재 vanilla JS로 구현 중이지만, Alpine.js 도입 시:

  • 더 선언적인 코드
  • x-show, x-transition 활용
  • 기존 HTMX와 호환

결정 필요: Alpine.js 추가 vs vanilla JS 유지

7.2 PWA 고려

모바일 경험 개선을 위해 PWA 기능 추가 검토:

  • manifest.json
  • 서비스 워커
  • 오프라인 기본 페이지

8. 진행 현황

Phase 상태 완료일
Phase 1 완료 2025-12-19
Phase 2 완료 2025-12-19
Phase 3 완료 2025-12-19
Phase 4 대기 -
Phase 5 대기 -