Files
sam-manage/CURRENT_WORKS.md
hskwon 7546771ee5 feat(mng): 개인 권한 관리 통합 매트릭스 구현
- 역할/부서/개인 권한을 통합하여 최종 유효 권한 표시
- 권한 소스별 색상 구분 UI (보라=역할, 파랑=부서, 녹색=개인허용, 빨강=개인거부)
- 스마트 토글 로직 (상속된 권한 오버라이드 지원)
- UserPermissionService: getRolePermissions(), getDepartmentPermissions(), getPersonalOverrides()
- 사용자 ID 뱃지 스타일 개선
2025-11-26 20:40:54 +09:00

1363 lines
51 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SAM MNG 작업 현황
## 2025-11-20 (수) - Phase 1-1: 인증 시스템 구현 완료
### 주요 작업
- MNG 프로젝트 인증 시스템 구현 (Laravel Sanctum 기반)
- DaisyUI를 사용한 로그인 UI 구현
- Service-First 아키텍처 적용
### 추가된 파일:
- `app/Services/AuthService.php` - 인증 비즈니스 로직 (login, logout, createToken)
- `app/Http/Requests/Auth/LoginRequest.php` - 로그인 검증 FormRequest
- `app/Http/Controllers/Auth/LoginController.php` - 로그인 컨트롤러 (세션 인증)
- `resources/views/auth/login.blade.php` - DaisyUI 기반 로그인 화면
- `resources/views/dashboard/index.blade.php` - 임시 대시보드
- `CURRENT_WORKS.md` - 작업 이력 추적 파일
### 수정된 파일:
- `routes/web.php` - 인증 라우트 추가 (login, logout, dashboard)
- `postcss.config.js` - Tailwind CSS 4.x 대응 (@tailwindcss/postcss)
### 작업 내용:
1. **DB 스키마 분석**
- API 프로젝트의 공유 DB 구조 확인 (users, personal_access_tokens, sessions)
- Multi-tenant 구조 파악 (tenant_id, user_tenants)
2. **인증 시스템 설계**
- Service-First 패턴 적용
- FormRequest를 통한 검증 분리
- 세션 기반 웹 인증 (향후 API 토큰 인증 준비)
3. **구현 완료**
- AuthService: 비즈니스 로직 캡슐화
- LoginRequest: 이메일/비밀번호 검증 및 한글 메시지
- LoginController: 로그인/로그아웃 처리
- Blade 템플릿: DaisyUI 단순 디자인
4. **Vite/PostCSS 설정**
- Tailwind CSS 4.x PostCSS 플러그인 설치
- 프로덕션 빌드 완료 (public/build/)
### 테스트 결과:
- ✅ 라우트 등록 확인: `/login` (GET, POST), `/logout` (POST), `/dashboard` (GET)
- ✅ 로그인 페이지 접근: https://mng.sam.kr/login (200 OK)
- ✅ Vite 빌드 성공: CSS (7.97 KB), JS (102.67 KB)
### 다음 단계:
- [ ] Phase 1-2: User 모델 생성 및 DB 연결 테스트
- [ ] Phase 1-3: 실제 로그인 테스트 (테스트 사용자 생성)
- [ ] Phase 2: 대시보드 구현 (메뉴, 사이드바)
---
## 2025-11-25 (월) - 권한 관리 시스템 Guard 선택 기능 추가
### 주요 작업
- 부서 권한 관리에 Guard 선택 기능 추가 (API/Web 분리)
- 역할 권한 관리에 Guard 선택 기능 추가 (API/Web 분리)
- 부서 권한 아키텍처 재설계 (Role 기반 → Department 직접 할당)
### 수정된 파일:
#### 부서 권한 관리
- `app/Models/Tenants/Department.php` - HasPermissions trait 추가
- `app/Services/DepartmentPermissionService.php` - 완전 재작성 (직접 할당 패턴)
- getDepartmentPermissionMatrix() - guard_name 필터링
- togglePermission() - guard_name으로 권한 생성
- propagateToChildren() - guard_name 전파
- allowAllPermissions() - guard_name 적용
- denyAllPermissions() - guard_name 필터링
- resetToDefaultPermissions() - guard_name 기본 권한 설정
- `app/Http/Controllers/Api/Admin/DepartmentPermissionController.php` - guard_name 처리
- getMatrix() - guard_name 파라미터 추가
- toggle() - guard_name 전달
- allowAll() - guard_name 전달
- denyAll() - guard_name 전달
- reset() - guard_name 전달
- `resources/views/department-permissions/index.blade.php` - Guard 선택기 UI
- Guard 선택 드롭다운 (API/Web)
- 모든 HTMX 요청에 guard_name 포함
- reloadPermissions() 함수 추가
- `resources/views/department-permissions/partials/permission-matrix.blade.php`
- 체크박스 hx-include에 guard_name 추가
#### 역할 권한 관리
- `app/Services/RolePermissionService.php` - guard_name 파라미터 추가
- getRolePermissionMatrix() - guard_name 필터링
- togglePermission() - guard_name으로 권한 생성
- propagateToChildren() - guard_name 전파
- allowAllPermissions() - guard_name 적용
- denyAllPermissions() - guard_name 필터링
- resetToDefaultPermissions() - guard_name 기본 권한 설정
- `app/Http/Controllers/Api/Admin/RolePermissionController.php` - guard_name 처리
- getMatrix() - guard_name 파라미터 추가
- toggle() - guard_name 전달
- allowAll() - guard_name 전달
- denyAll() - guard_name 전달
- reset() - guard_name 전달
- `resources/views/role-permissions/index.blade.php` - Guard 선택기 UI
- Guard 선택 드롭다운 (Web/API)
- 모든 HTMX 요청에 guard_name 포함
- reloadPermissions() 함수 추가
- `resources/views/role-permissions/partials/permission-matrix.blade.php`
- 체크박스 hx-include에 guard_name 추가
#### 라우트 및 기타
- `routes/api.php` - reset 엔드포인트 추가
- department-permissions/reset
- role-permissions/reset
- `docs/INDEX.md` - 문서 업데이트
### 작업 내용:
1. **부서 권한 아키텍처 재설계**
- 기존: Department → Role → Permission (잘못된 설계)
- 변경: Department → Permission (직접 할당)
- model_has_permissions 테이블 직접 사용
- HasPermissions trait 추가로 Spatie 기능 활용
2. **Guard 선택 기능 구현**
- API Guard: API 토큰 인증용 권한
- Web Guard: 웹 세션 인증용 권한
- Guard별 독립적인 권한 매트릭스 관리
3. **초기화(Reset) 기능 추가**
- 전체 허용: 모든 권한 부여
- 전체 거부: 모든 권한 제거
- 초기화: 조회(view) 권한만 부여 (기본 권한)
4. **UI/UX 개선**
- Guard 선택기를 "전체 허용" 버튼 앞으로 배치
- 시각적 구분선(Divider) 추가
- Guard 변경 시 자동 새로고침
### 코드 품질:
- ✅ Pint 포맷팅 통과
- ✅ Service-First 아키텍처 유지
- ✅ BelongsToTenant 스코프 적용
- ✅ FormRequest 검증 패턴 유지
### Git 커밋:
```bash
feat: 권한 관리 시스템에 Guard 선택 기능 추가
- 부서 권한 아키텍처 재설계 (Role → Department 직접 할당)
- Guard 선택 기능 구현 (API/Web 분리)
- 초기화(Reset) 기능 추가 (view 권한만 허용)
- UI 개선 (Guard 선택기 + 구분선)
```
- [ ] Phase 3: 사용자 관리 기능
### Git 커밋:
-`ece1f28` "feat: MNG 인증 시스템 구현"
-`b71e85a` "fix: Tailwind 3.x 다운그레이드 및 DaisyUI 적용"
### 이슈 해결:
- **문제**: Tailwind CSS 4.x에서 DaisyUI 플러그인 미적용
- **원인**: DaisyUI가 Tailwind 4.x를 완전히 지원하지 않음
- **해결**: Tailwind 3.4.17로 다운그레이드, PostCSS 설정 수정
- **결과**: DaisyUI 클래스 정상 적용 (74.82 KB CSS)
### 문서 업데이트 (2025-11-20):
- **api/CLAUDE.md**: shared/ 모델 참조 제거
- **변경 사항**:
- 저장소 구조: 5개 → 3개 (api, admin, mng 독립 운영)
- 모델 구조: shared/ → 각 프로젝트 독립 모델
- 워크플로우: shared 동기화 제거
- CURRENT_WORKS.md 위치: mng 추가
---
## 2025-11-20 (수) - CSS 브라우저 호환성 문제 해결
### 주요 작업
- DaisyUI oklch() 색상 함수 브라우저 호환성 문제 해결
- Pure Tailwind CSS로 전환하여 구형 브라우저 지원
### 문제 상황:
- **증상**: mng.sam.kr 로그인 페이지 CSS 스타일이 적용되지 않음
- **원인**: DaisyUI 5.5.5가 `oklch()` 색상 함수 사용 → Safari <15.4, Chrome <111 미지원
- **영향**: CSS 변수가 계산되지 않아 버튼, 카드 모든 컴포넌트 스타일 무효화
### 해결 과정:
1. **DaisyUI 설정 시도** (실패)
- Custom hex 테마 설정 DaisyUI가 여전히 oklch() 사용
- `themes: false` 설정 base CSS에서 oklch() 사용
2. **DaisyUI 완전 제거** (성공)
- `tailwind.config.js`에서 DaisyUI 플러그인 제거
- Pure Tailwind CSS + @tailwindcss/forms 사용
- Custom primary/secondary 색상 hex로 정의
3. **로그인 페이지 리팩토링**
- DaisyUI 클래스 Tailwind 유틸리티 클래스 변환
- `btn btn-primary` `bg-primary text-white rounded-lg`
- `card` `bg-white rounded-lg shadow-xl`
- `input input-bordered` `border border-gray-300 rounded-lg`
### 수정된 파일:
- `tailwind.config.js` - DaisyUI 제거, hex 색상 정의
- `resources/css/app.css` - CSS 변수 추가 (향후 제거 예정)
- `resources/views/auth/login.blade.php` - Tailwind 유틸리티 클래스로 변환
- `.env` - DB_HOST를 sam-mysql-1 127.0.0.1로 변경 (로컬 접근)
### 빌드 결과:
- **Before**: 74.82 KB (DaisyUI 포함, oklch() 사용)
- **After**: 23.15 KB (Pure Tailwind, hex 색상 사용)
- **파일**: `public/build/assets/app-L1Qg3jEH.css`
### 테스트 결과:
- 로그인 페이지 CSS 정상 적용
- 모든 브라우저 호환성 확보 (hex 색상 사용)
- 로그인 기능 정상 작동 (원격 DB 데이터 복원 )
### 기술적 결정:
- **CSS 프레임워크**: DaisyUI Pure Tailwind CSS
- **색상 시스템**: oklch() hex (#570df8, #f000b8)
- **컴포넌트 스타일**: 사전 정의 클래스 유틸리티 조합
- **향후 방향**: 로그인 페이지 기준으로 일관된 CSS 스타일 유지
### Git 커밋:
- `7b3505a` "fix: DaisyUI oklch() 브라우저 호환성 문제 해결"
---
## 2025-11-20 (수) - Phase 2: 레이아웃 구조화 및 메뉴 시스템 구현
### 주요 작업
- 좌측 사이드바 + 상단 헤더 레이아웃 구조 설계
- Blade 템플릿 컴포넌트 분리 (@extends/@section 패턴)
- SAM 프로젝트 기반 10개 메뉴 항목 구현
### 추가된 파일:
- `resources/views/layouts/app.blade.php` - 마스터 레이아웃 (sidebar + header + content)
- `resources/views/partials/sidebar.blade.php` - 좌측 사이드바 (256px, 메뉴 10개)
- `resources/views/partials/header.blade.php` - 상단 헤더 (64px, 페이지 타이틀 + 사용자 메뉴)
### 수정된 파일:
- `resources/views/dashboard/index.blade.php` - @extends 패턴으로 리팩토링
### 레이아웃 구조:
**전체 구조 (Flexbox):**
```
┌─────────────────────────────────────┐
│ ┌──────┐ ┌─────────────────────┐ │
│ │ │ │ Header (64px) │ │
│ │ Side │ ├─────────────────────┤ │
│ │ bar │ │ │ │
│ │(256) │ │ Main Content │ │
│ │ │ │ │ │
│ └──────┘ └─────────────────────┘ │
└─────────────────────────────────────┘
```
**사이드바 구조 (Flex Column):**
- 상단: 로고/브랜드 (h-16)
- 중단: 메뉴 영역 (flex-1, 스크롤 가능)
- 하단: 사용자 정보 (border-top)
**헤더 구조 (Flex Row):**
- 좌측: 페이지 제목 (@yield('page-title'))
- 우측: 알림 버튼 + 사용자 드롭다운 메뉴
### 메뉴 구조 (10개):
**조직 관리:**
1. 대시보드 (활성화됨, route 연결)
2. 사용자 관리
3. 권한 역할
4. 부서 관리
**제품/자재 관리:**
5. 제품 관리
6. 자재 관리
7. BOM 관리
8. 카테고리 관리
**시스템 관리:**
9. 시스템 설정
10. 감사 로그
### 메뉴 특징:
- **아이콘**: Heroicons (Tailwind 공식 아이콘 라이브러리)
- **활성 상태**: `request()->routeIs()` 체크 bg-primary + text-white
- **호버 효과**: hover:bg-gray-100
- **구분선**: 영역별 시각적 구분 (border-t border-gray-200)
- **반응형**: 메뉴 많아지면 스크롤 가능 (overflow-y-auto)
### 헤더 기능:
- **알림 버튼**: 플레이스홀더 (추후 구현)
- **사용자 드롭다운**:
- 사용자 정보 표시 (이름, 이메일)
- 프로필 설정 (링크 미연결)
- 계정 설정 (링크 미연결)
- 로그아웃 (route('logout') 연결)
- JavaScript 외부 클릭 감지로 자동 닫힘
### 사용자 정보 표시:
- **아바타**: 이름 글자 대문자 (bg-primary 원형)
- **이름**: `auth()->user()->name ?? 'User'`
- **이메일**: `auth()->user()->email`
- **위치**: 사이드바 하단, 헤더 우측
### CSS/디자인:
- **색상**: primary (#570df8), gray 팔레트
- **간격**: space-y-2 (메뉴), gap-3/4 (아이콘-텍스트)
- **패딩**: px-4 py-3 (메뉴), px-6 (헤더/메인)
- **라운드**: rounded-lg (버튼/메뉴)
- **그림자**: shadow-lg (사이드바), shadow-sm (헤더)
### 빌드 결과:
- **CSS**: 25.36 KB (gzip: 5.57 KB)
- **JS**: 102.67 KB (gzip: 32.86 KB)
- **파일**: `public/build/assets/app-BjNnnM4N.css`
### 기술적 결정:
- **레이아웃**: 좌측 사이드바 (admin.sam.kr Filament 패널과 일관성)
- **컴포넌트 분리**: layouts/ + partials/ 구조
- **Blade 패턴**: @extends/@section/@include/@yield/@stack
- **반응형**: 추후 모바일 대응 예정 (현재 데스크톱 우선)
### 개발 프로세스:
1. Phase 1: 레이아웃 구조 설계
2. Phase 2: 메뉴 리스트업
3. Phase 3: 컨텐츠 구성 (다음 단계)
### Git 커밋:
- `9367f61` "feat: 좌측 사이드바 레이아웃 메뉴 시스템 구현"
---
## 2025-11-21 (목) - 테넌트 선택 기능 구현
### 주요 작업
- admin 패널의 테넌트 전환 기능을 MNG로 이식
- Plain Laravel (Livewire 없이) 방식으로 구현
- ViewServiceProvider를 통한 전역 테넌트 데이터 제공
### 추가된 파일:
- `app/Models/Tenant.php` - 테넌트 모델 (SoftDeletes, active scope)
- `app/Http/Controllers/TenantController.php` - 테넌트 전환 컨트롤러
- `app/Providers/ViewServiceProvider.php` - 모든 뷰에 테넌트 목록 자동 제공
- `resources/views/partials/tenant-selector.blade.php` - 테넌트 선택 UI 컴포넌트
### 수정된 파일:
- `routes/web.php` - 테넌트 전환 라우트 추가 (`POST /tenant/switch`)
- `bootstrap/providers.php` - ViewServiceProvider 등록
- `resources/views/dashboard/index.blade.php` - 테넌트 선택기 포함
### 기능 상세:
**테넌트 선택기 구조:**
```
┌─────────────────────────────────────────────────┐
│ 좌측 우측 │
│ [아이콘] 테넌트 선택: [드롭다운] [상태 표시] │
└─────────────────────────────────────────────────┘
```
**UI 컴포넌트:**
- Welcome Card 위에 배치 (동일한 깊이)
- 좌측: 건물 아이콘 + "테넌트 선택" 라벨 + 셀렉트박스
- 우측: 현재 테넌트 정보 표시
- 특정 테넌트 선택: "○○ 데이터만 표시 " (primary 색상 뱃지)
- 전체 보기: "전체 테넌트 데이터 표시 " (회색 텍스트)
**동작 방식:**
1. 드롭다운 변경 자동 Form Submit (`onchange`)
2. `POST /tenant/switch` 라우트로 전송
3. Session에 `selected_tenant_id` 저장
4. 이전 페이지로 리다이렉트 (`redirect()->back()`)
**ViewServiceProvider 역할:**
- 모든 인증된 뷰에서 `$tenants` 변수 자동 사용 가능
- View Composer 패턴 적용 (`View::composer('*', ...)`)
- 활성 테넌트만 회사명 정렬
**Tenant 모델:**
- SoftDeletes trait 사용
- `active()` scope: 삭제되지 않은 테넌트만 조회
- `tenant_st_code` 컬럼 사용 (trial, none 등의 상태값)
### DB 스키마 분석:
- **테이블**: `tenants` (29개 컬럼)
- **주요 컬럼**:
- `id`, `company_name`, `code` (회사 기본 정보)
- `tenant_st_code` (상태: trial, none )
- `deleted_at` (SoftDelete)
- `storage_limit`, `storage_used` (용량 관리)
### 이슈 해결:
- **문제**: `is_active` 컬럼 없음 (SQLSTATE[42S22])
- **원인**: admin 패널과 DB 스키마 차이
- **해결**: `tenant_st_code` 사용 삭제되지 않은 모든 테넌트 표시
### 테스트 결과:
- 테넌트 모델 조회 성공 (7개 활성 테넛트)
- ViewServiceProvider 등록 완료
- 테넌트 선택기 UI 렌더링
- 브라우저 테스트 대기
### 빌드 결과:
- **CSS**: 25.58 KB (gzip: 5.61 KB)
- **파일**: `public/build/assets/app-CQyaIaRP.css`
### 기술적 결정:
- **Livewire 대신 Plain Laravel**: 심플함, 페이지 새로고침 방식
- **ViewServiceProvider**: 전역 데이터 제공 패턴
- **Session 기반**: `selected_tenant_id` 세션 저장
- **모든 페이지 공통**: `@include('partials.tenant-selector')` 사용
### Git 커밋:
- `661c5ad` "feat: 테넌트 선택 기능 구현"
---
## 2025-11-24 (일) - 테넌트 관리 페이지네이션 및 공통 컴포넌트화
### 주요 작업
- 테넌트 목록 페이지에 HTMX 호환 페이지네이션 추가
- 페이지네이션을 공통 컴포넌트로 분리하여 재사용성 향상
### 추가된 파일:
- `resources/views/partials/pagination.blade.php` - HTMX 호환 공통 페이지네이션 컴포넌트
### 수정된 파일:
- `resources/views/tenants/partials/table.blade.php` - 페이지네이션 코드 제거, 공통 컴포넌트 include로 대체
### 작업 배경:
**이전 세션 작업 내역 (2025-11-24):**
1. 테넌트 수정 HTMX URL 라우팅 문제 해결
2. UpdateTenantRequest 라우트 파라미터 수정 (`route('tenant')` `route('id')`)
3. HTMX 삭제/복원/영구삭제 기능에 CSRF 토큰 헤더 추가
4. TenantService::forceDeleteTenant() 외래키 제약 처리
5. `docs/TROUBLESHOOTING.md` 트러블슈팅 가이드 작성
6. 페이지네이션 추가 (1페이지만 있어도 항상 표시)
7. 페이지네이션을 공통 컴포넌트로 분리
### 페이지네이션 구현 상세:
**구조:**
- **모바일**: 이전/다음 버튼만 표시 (`sm:hidden`)
- **데스크톱**: 전체 페이지 번호 + 이전/다음 버튼 (`hidden sm:flex`)
**기능:**
- 개별 페이지 번호 버튼 클릭 가능 (1, 2, 3...)
- 현재 페이지 하이라이트 (파란색 배경)
- 비활성화된 버튼 회색 처리
- HTMX 동적 로딩 (페이지 새로고침 없음)
- 검색 필터 유지 (`hx-include`)
- CSRF 토큰 자동 포함
**사용법:**
```blade
@include('partials.pagination', [
'paginator' => $tenants, // LengthAwarePaginator 객체
'target' => '#tenant-table', // HTMX 타겟 ID
'includeForm' => '#filterForm' // 필터 폼 ID (선택)
])
```
**코드 개선:**
- 중복 코드 95줄 5줄 (include ) 간소화
- 유지보수성 향상 ( 곳만 수정하면 전체 적용)
- 다른 목록 페이지에서도 즉시 재사용 가능
### 기술적 특징:
**HTMX 통합:**
- `hx-get`: 페이지 URL 동적 로드
- `hx-target`: 교체할 DOM 영역 지정
- `hx-include`: 검색 필터 데이터 포함
- `hx-headers`: CSRF 토큰 자동 전달
**Laravel 페이지네이션 메서드:**
- `$paginator->total()`: 전체 데이터 개수
- `$paginator->firstItem()`: 현재 페이지 번째 항목 번호
- `$paginator->lastItem()`: 현재 페이지 마지막 항목 번호
- `$paginator->currentPage()`: 현재 페이지 번호
- `$paginator->lastPage()`: 마지막 페이지 번호
- `$paginator->getUrlRange(1, $lastPage)`: 페이지 URL 배열
- `$paginator->previousPageUrl()`: 이전 페이지 URL
- `$paginator->nextPageUrl()`: 다음 페이지 URL
- `$paginator->onFirstPage()`: 페이지 여부
- `$paginator->hasMorePages()`: 다음 페이지 존재 여부
**반응형 디자인:**
- 모바일: 간단한 이전/다음 네비게이션
- 데스크톱: 전체 페이지 번호 + 이전/다음
- Tailwind breakpoint: `sm:` (640px)
### 파일 구조:
```
resources/views/
├── partials/
│ ├── header.blade.php
│ ├── sidebar.blade.php
│ ├── tenant-selector.blade.php
│ └── pagination.blade.php ← 새로 추가된 공통 컴포넌트
└── tenants/
└── partials/
└── table.blade.php ← 페이지네이션 코드 제거, include로 대체
```
### 향후 활용:
공통 페이지네이션 컴포넌트는 다음 목록에서도 사용 가능:
- 사용자 목록
- 부서 목록
- 제품 목록
- 자재 목록
- BOM 목록
- 감사 로그 목록
### 다음 단계:
- [ ] 브라우저에서 페이지네이션 동작 확인
- [ ] 다른 목록 페이지에 페이지네이션 적용
- [ ] 페이지당 표시 개수 선택 기능 추가 고려
### Git 커밋:
- `43af1a5` "페이지네이션 기능 개선 공통화"
---
## 2025-11-24 (일) - Phase 4-2: 역할 관리 시스템 구현
### 주요 작업
- 역할 CRUD 완전 구현 (Spatie Permission 패키지 활용)
- 권한 선택 UI 구현 (체크박스, 전체 선택/해제)
- HTMX + API 패턴 적용
- 페이지네이션 공통 컴포넌트 생성
### 추가된 파일:
- `app/Services/RoleService.php` - 역할 비즈니스 로직 (Spatie Role 모델 사용)
- `app/Http/Controllers/RoleController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/RoleController.php` - HTMX API 컨트롤러
- `app/Http/Requests/StoreRoleRequest.php` - 역할 생성 검증
- `app/Http/Requests/UpdateRoleRequest.php` - 역할 수정 검증
- `resources/views/roles/index.blade.php` - 역할 목록 (HTMX 로딩)
- `resources/views/roles/create.blade.php` - 역할 생성
- `resources/views/roles/edit.blade.php` - 역할 수정
- `resources/views/roles/partials/table.blade.php` - 역할 테이블
- `resources/views/partials/pagination.blade.php` - 공통 페이지네이션 컴포넌트
### 수정된 파일:
- `resources/views/partials/sidebar.blade.php` - 역할 관리 메뉴 추가
- `routes/web.php` - 역할 관리 라우트 추가 (index, create, edit)
- `routes/api.php` - 역할 관리 API 라우트 추가 (CRUD)
### 기능 상세:
**역할 관리 CRUD:**
- 역할 목록: HTMX 동적 로딩, 검색 필터, 페이지네이션
- 역할 생성: 이름/설명 입력, 권한 선택 (체크박스)
- 역할 수정: 기존 정보 편집, 권한 변경
- 역할 삭제: Soft Delete (복구 가능)
**권한 선택 UI:**
- 그리드 레이아웃 (3열)
- 체크박스로 권한 선택
- 전체 선택/해제 버튼
- 현재 권한 개수 표시
**RoleService 주요 메서드:**
- `getRoles(filters, perPage)`: 역할 목록 조회 (페이지네이션)
- `getRoleById(id)`: 특정 역할 조회 (권한 포함)
- `createRole(data)`: 역할 생성 + 권한 동기화 (`syncPermissions()`)
- `updateRole(id, data)`: 역할 수정 + 권한 동기화
- `deleteRole(id)`: 역할 삭제 (권한/사용자 연결 해제)
- `isNameExists(name, excludeId)`: 역할 이름 중복 체크
- `getActiveRoles()`: 활성 역할 목록 (드롭다운용)
- `getRoleStats()`: 역할 통계 (전체 , 권한 있는 역할 )
**Spatie Permission 통합:**
- `Spatie\Permission\Models\Role` 모델 사용
- `syncPermissions()`: 역할-권한 동기화
- `permissions` 관계: 역할에 할당된 권한 조회
- Multi-tenant 지원: `tenant_id` 필터링
**HTMX 패턴:**
- 목록 화면: `hx-get="/api/admin/roles"` (필터 포함)
- 생성/수정: `hx-post`, `hx-put` (JSON 응답 리다이렉트)
- 삭제: `confirmDelete()` JavaScript HTMX DELETE 요청
**페이지네이션 컴포넌트:**
- 모바일: 이전/다음 버튼만
- 데스크톱: 전체 페이지 번호 표시
- HTMX 호환: `hx-get`, `hx-target`, `hx-include`
- 재사용 가능: `@include('partials.pagination', [...])`
### 테넌트 필터링:
- 세션에 `selected_tenant_id` 있으면 해당 테넌트만
- 없으면 전체 테넌트 데이터 표시
- 역할/권한 모두 테넌트 필터링 적용
### 빌드 결과:
- **변경 파일**: 17개
- **추가 코드**: +1331줄, -106줄
### Git 커밋:
- `5f50716` "feat: Phase 4-2 역할 관리 시스템 구현 (HTMX + API 패턴)"
---
## 2025-11-24 (일) - Phase 4-3: 부서 관리 시스템 구현
### 주요 작업
- 부서 CRUD 완전 구현 (계층 구조 지원)
- 활성/비활성 상태 관리
- HTMX + API 패턴 적용
### 추가된 파일:
- `app/Services/DepartmentService.php` - 부서 비즈니스 로직
- `app/Http/Controllers/DepartmentController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/DepartmentController.php` - HTMX API 컨트롤러
- `app/Http/Requests/StoreDepartmentRequest.php` - 부서 생성 검증
- `app/Http/Requests/UpdateDepartmentRequest.php` - 부서 수정 검증
- `resources/views/departments/index.blade.php` - 부서 목록
- `resources/views/departments/create.blade.php` - 부서 생성
- `resources/views/departments/edit.blade.php` - 부서 수정
- `resources/views/departments/partials/table.blade.php` - 부서 테이블
### 수정된 파일:
- `resources/views/partials/sidebar.blade.php` - 부서 관리 메뉴 추가
- `routes/web.php` - 부서 관리 라우트 추가
- `routes/api.php` - 부서 관리 API 라우트 추가
### 기능 상세:
**부서 계층 구조:**
- Self-referential relationship: `parent_id` `departments.id`
- 상위 부서 선택 가능 (드롭다운)
- 자기 자신을 상위 부서로 선택 방지 (FormRequest 검증)
- 하위 부서 존재 삭제 방지
**DepartmentService 주요 메서드:**
- `getDepartments(filters, perPage)`: 부서 목록 조회
- `getDepartmentById(id)`: 특정 부서 조회
- `createDepartment(data)`: 부서 생성
- `updateDepartment(id, data)`: 부서 수정
- `deleteDepartment(id)`: 부서 삭제 (하위 부서 체크)
- `getActiveDepartments()`: 활성 부서 목록 (드롭다운용)
- `getDepartmentTree()`: 계층 구조 트리 (향후 구현)
**활성 상태 관리:**
- `is_active` 컬럼: 활성(1) / 비활성(0)
- 활성 필터: `active` scope 적용
- UI: 활성 상태 뱃지 표시
**정렬 순서:**
- `sort_order` 컬럼: 표시 순서 지정
- 기본 정렬: `sort_order ASC`, `name ASC`
### 검증 규칙:
**StoreDepartmentRequest:**
- `name`: 필수, 최대 100자
- `parent_id`: 선택, 존재하는 부서 ID
- `sort_order`: 선택, 정수
- `is_active`: 불리언 (기본값: true)
**UpdateDepartmentRequest:**
- 위와 동일 + 자기 참조 방지
- `parent_id` 현재 부서 ID
### Git 커밋:
- `6738505` "feat: Phase 4-3 부서 관리 시스템 구현"
---
## 2025-11-24 (일) - 사용자 관리 기능 추가
### 주요 작업
- 사용자 CRUD 완전 구현
- UserService, FormRequest, Blade Views 생성
- MNG_CRITICAL_RULES.md 문서 추가
- 테이블 헤더 스타일 통일
### 추가된 파일:
- `app/Http/Controllers/UserController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/UserController.php` - HTMX API 컨트롤러
- `app/Http/Requests/StoreUserRequest.php` - 사용자 생성 검증
- `app/Http/Requests/UpdateUserRequest.php` - 사용자 수정 검증
- `resources/views/users/index.blade.php` - 사용자 목록
- `resources/views/users/create.blade.php` - 사용자 생성
- `resources/views/users/edit.blade.php` - 사용자 수정
- `resources/views/users/partials/table.blade.php` - 사용자 테이블
- `docs/MNG_CRITICAL_RULES.md` - MNG 프로젝트 핵심 규칙 문서
### 수정된 파일:
- `resources/views/partials/sidebar.blade.php` - 사용자 관리 메뉴 이동
- `routes/web.php` - 사용자 관리 라우트 추가
- `routes/api.php` - 사용자 관리 API 라우트 추가
- 테이블 헤더 스타일 통일 (tenants, roles, departments)
### 기능 상세:
**사용자 관리 CRUD:**
- 사용자 목록: 검색, 필터링 (역할, 부서, 활성 상태)
- 사용자 생성: 이름, 이메일, 비밀번호, 역할, 부서, 테넌트
- 사용자 수정: 정보 변경, 비밀번호 변경 (선택)
- 사용자 삭제: Soft Delete
**MNG_CRITICAL_RULES.md:**
- DB 마이그레이션 금지 (API 프로젝트에서만 실행)
- 모델 독립 운영 (admin, api, mng 각각 독립)
- Filament 의존성 제거
- Service-First 패턴 강제
- FormRequest 검증 필수
### Git 커밋:
- `0c86b39` "feat: 사용자 관리 기능 MNG 문서 추가"
---
## 2025-11-24 (일) - 사용자 관리 복구 및 영구삭제 기능 추가
### 주요 작업
- UserService에 복구/영구삭제 메서드 추가
- Audit 컬럼 처리 (created_by, updated_by, deleted_by)
- 삭제된 사용자 UI 표시
### 수정된 파일:
- `app/Services/UserService.php` - restoreUser(), forceDeleteUser() 추가
- `app/Http/Controllers/Api/Admin/UserController.php` - restore, forceDestroy 엔드포인트
- `resources/views/users/index.blade.php` - 삭제된 항목 필터 체크박스
- `resources/views/users/partials/table.blade.php` - 복원/영구삭제 버튼
- `routes/api.php` - restore, forceDestroy 라우트 추가
### 기능 상세:
**복구 기능:**
- Soft Delete된 사용자 복원
- `withTrashed()`: 삭제된 사용자 포함 조회
- UI: 삭제된 사용자에 "복원" 버튼 표시
**영구삭제 기능:**
- 물리적 삭제 (복구 불가)
- 권한 체크: 슈퍼관리자만 가능
- UI: 삭제된 사용자에 "영구삭제" 버튼 표시 (빨간색)
**Audit 컬럼 처리:**
- `created_by`: 생성자 ID
- `updated_by`: 수정자 ID
- `deleted_by`: 삭제자 ID
- 자동 기록: `auth()->id()`
### Git 커밋:
- `8940557` "사용자 관리 복구 영구삭제 기능 추가"
---
## 2025-11-24 (일) - 메뉴 관리 기능 개선
### 주요 작업
- 메뉴 트리 구조 완전 구현 (무제한 depth)
- 접기/펼치기 기능 (재귀적 처리)
- 활성/숨김 상태 토글 (실시간 업데이트)
- 테넌트 필터링 (마스터 메뉴 지원)
### 추가된 파일:
- `app/Services/MenuService.php` - 메뉴 비즈니스 로직 (트리 구조)
- `app/Http/Controllers/MenuController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/MenuController.php` - HTMX API 컨트롤러
- `app/Http/Requests/StoreMenuRequest.php` - 메뉴 생성 검증
- `app/Http/Requests/UpdateMenuRequest.php` - 메뉴 수정 검증
- `resources/views/menus/index.blade.php` - 메뉴 목록 (트리 구조)
- `resources/views/menus/create.blade.php` - 메뉴 생성
- `resources/views/menus/edit.blade.php` - 메뉴 수정
- `resources/views/menus/partials/table.blade.php` - 메뉴 트리 테이블
### 수정된 파일:
- `routes/web.php` - 메뉴 관리 라우트 추가
- `routes/api.php` - 메뉴 관리 API 라우트 추가 (tree, toggleActive, toggleHidden)
### 기능 상세:
**트리 구조:**
- 무제한 depth 지원
- 재귀적 렌더링 (Blade recursive include)
- 인덴트로 계층 표시
- 접기/펼치기 아이콘
**MenuService 주요 메서드:**
- `getMenus(filters)`: 메뉴 목록 (flat)
- `getMenuTree(filters)`: 트리 구조 메뉴 (재귀 쿼리)
- `createMenu(data)`: 메뉴 생성
- `updateMenu(id, data)`: 메뉴 수정
- `deleteMenu(id)`: 메뉴 삭제 (하위 메뉴 체크)
- `toggleActive(id)`: 활성 상태 토글
- `toggleHidden(id)`: 숨김 상태 토글
**토글 기능:**
- 활성/비활성: `is_active` 토글
- 숨김/표시: `is_hidden` 토글
- HTMX 실시간 업데이트 (페이지 새로고침 없음)
**테넌트 필터링:**
- 전체 선택: 마스터 메뉴만 표시 (`tenant_id IS NULL`)
- 특정 테넌트: 해당 테넌트 메뉴만
- 외부 메뉴 표시: `external_link` 컬럼
### Git 커밋:
- `79aebfa` "메뉴 관리 기능 개선"
---
## 📊 Phase 4 완료 요약 (2025-11-24)
### 구현된 모든 관리 기능:
** Phase 4-1: 테넌트 관리**
- CRUD, 복구/영구삭제, 페이지네이션
- 커밋: 575e9df, 0f21445, bc3777a
** Phase 4-2: 역할 관리**
- CRUD, 권한 할당/해제, Spatie Permission 통합
- 커밋: 5f50716
** Phase 4-3: 부서 관리**
- CRUD, 계층 구조, 활성 상태 관리
- 커밋: 6738505
** Phase 4-4: 사용자 관리**
- CRUD, 복구/영구삭제, 역할/부서 연결
- 커밋: 0c86b39, 8940557
** Phase 4-5: 메뉴 관리**
- CRUD, 트리 구조, 토글 기능
- 커밋: 79aebfa
### 공통 컴포넌트:
- `partials/pagination.blade.php` - 재사용 가능 페이지네이션
- `partials/tenant-selector.blade.php` - 테넌트 선택기
- `partials/sidebar.blade.php` - 좌측 메뉴
- `partials/header.blade.php` - 상단 헤더
### 공통 패턴:
- Service-First 아키텍처
- FormRequest 검증
- HTMX + API 패턴
- Multi-tenant 필터링
- Soft Delete + 복구/영구삭제
- Audit 로그 (created_by, updated_by, deleted_by)
### 문서:
- `docs/MNG_CRITICAL_RULES.md` - 핵심 규칙
- `docs/TROUBLESHOOTING.md` - 트러블슈팅 가이드
- `docs/INDEX.md` - 문서 인덱스
### 통계:
- **추가 파일**: 60개 이상
- **추가 코드**: 5,000줄 이상
- **커밋 **: 12개
- **작업 기간**: 2025-11-24 하루
---
## 📋 다음 단계 (Phase 5 이후)
### Phase 5: 제품/자재 관리
- [ ] 제품 관리 (Products)
- [ ] 자재 관리 (Materials)
- [ ] 카테고리 관리 (Categories)
### Phase 6: BOM 관리
- [ ] BOM 구조 (Bill of Materials)
- [ ] BOM 버전 관리
- [ ] BOM 트리
### Phase 7: 시스템 관리
- [ ] 감사 로그 (Audit Logs)
- [ ] 시스템 설정 (Settings)
- [ ] 알림 관리 (Notifications)
---
## 2025-11-25 (월) - Phase 4-4-2: 역할 권한 관리 기능 구현
### 주요 작업
- 역할-권한 매핑 관리 기능 완전 구현
- admin 패널의 역할 권한 관리를 MNG로 이식 (Livewire HTMX)
- 메뉴 기반 권한 체크박스 매트릭스 시스템
### 추가된 파일:
- `app/Services/RolePermissionService.php` - 역할 권한 비즈니스 로직
- `app/Http/Controllers/RolePermissionController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/RolePermissionController.php` - HTMX API 컨트롤러
- `resources/views/role-permissions/index.blade.php` - 메인 페이지
- `resources/views/role-permissions/partials/empty-state.blade.php` - 상태 화면
- `resources/views/role-permissions/partials/permission-matrix.blade.php` - 권한 매트릭스 테이블
### 수정된 파일:
- `resources/views/partials/sidebar.blade.php` - 역할 권한 관리 메뉴 활성화
- `routes/web.php` - 역할 권한 관리 라우트 추가
- `routes/api.php` - 역할 권한 관리 API 라우트 추가
### 기능 상세:
**RolePermissionService 주요 메서드:**
- `getRolePermissionMatrix(roleId, tenantId)`: 권한 매트릭스 조회
- `togglePermission(roleId, menuId, type, tenantId)`: 권한 토글
- `propagateToChildren(roleId, menuId, type, value, tenantId)`: 하위 메뉴 권한 전파
- `allowAllPermissions(roleId, tenantId)`: 모든 권한 허용
- `denyAllPermissions(roleId, tenantId)`: 모든 권한 거부
- `getMenuTree(tenantId)`: 메뉴 트리 조회
- `hasPermission(roleId, menuId, type)`: 권한 확인
**권한 유형 (7가지):**
- view (조회)
- create (생성)
- update (수정)
- delete (삭제)
- approve (승인)
- export (내보내기)
- manage (관리)
**UI 구조:**
1. **상단 툴바**
- 역할 선택 드롭다운 (HTMX 동적 로딩)
- 전체 허용 (녹색) / 전체 거부 (빨간색) / 초기화 (회색) 버튼
2. **권한 매트릭스 테이블**
- 행: 메뉴 목록 (계층 구조, "├─" 인덴트)
- 컬럼: 순번, 메뉴명, 상위 메뉴, URL, 순서 + 권한 체크박스 7개
- 체크박스: HTMX로 실시간 토글
3. **빈 상태**
- 역할 미선택 "역할을 선택해주세요" 메시지 표시
**HTMX 패턴:**
- 역할 변경: `hx-get="/api/admin/role-permissions/matrix"`
- 권한 토글: `hx-post="/api/admin/role-permissions/toggle"`
- 전체 허용: `hx-post="/api/admin/role-permissions/allow-all"`
- 전체 거부: `hx-post="/api/admin/role-permissions/deny-all"`
**계층적 권한 전파:**
- 부모 메뉴 권한 변경 하위 메뉴에 자동 전파
- 재귀적 처리로 모든 하위 메뉴에 동일 권한 적용
**테넌트 필터링:**
- 세션의 `selected_tenant_id` 기준으로 필터링
- 테넌트별 메뉴와 권한만 표시
### 기술 스택:
- Service-First 패턴
- HTMX (Livewire 대체)
- Plain Blade (Filament 컴포넌트 없음)
- Spatie Permission (role_has_permissions 테이블)
- Tailwind CSS
### Admin vs MNG 차이점:
| 항목 | Admin (Filament) | MNG (Plain Laravel) |
|------|------------------|---------------------|
| 프레임워크 | Livewire | HTMX |
| 컴포넌트 | Filament | Tailwind CSS |
| 메서드 | wire:click | hx-post |
| 모델 바인딩 | wire:model.live | JavaScript change |
### Git 커밋:
- 작업 완료, 커밋 대기
---
**최종 업데이트**: 2025-11-25 13:00
**현재 Phase**: Phase 4-4-2 완료, 브라우저 테스트 대기
**다음 작업**: 브라우저 동작 확인 오류 수정
## 2025-11-25 (월) - 부서 권한 관리 구현 시작
### 주요 작업
- 역할 권한 관리와 유사한 부서 권한 관리 구현
- admin 패널의 부서 권한 관리를 MNG로 이식 (Livewire HTMX)
### 문서 확인 완료:
- CURRENT_WORKS.md 백업 완료
- MNG_CRITICAL_RULES.md 확인 (금지사항 숙지)
- Department 마이그레이션 확인 (parent_id 계층 구조)
- Permission 통합 마이그레이션 확인
### DB 스키마 분석:
**중요 발견:**
- `department_permissions` 테이블 드롭됨 (2025_08_21 마이그레이션)
- `permission_overrides` 테이블 신설 (Spatie 표준화)
- Department 모델은 HasRoles trait 사용 (Spatie)
- permissionOverrides morphMany 관계 사용
**권한 관리 구조:**
- Spatie 표준: `model_has_permissions` (역할/부서 권한)
- 개별 오버라이드: `permission_overrides` (ALLOW/DENY)
- 부서는 model_type='App\Models\Tenants\Department' 사용
### 다음 작업:
- [ ] departments 테이블 전체 스키마 확인
- [ ] permission_overrides 테이블 구조 상세 파악
- [ ] 부서 권한 관리 UI/UX 설계
- [ ] DepartmentPermissionService 설계
- [ ] 권한 매트릭스 구현
---
### 추가된 파일:
- `app/Services/DepartmentPermissionService.php` - 부서 권한 비즈니스 로직
- `app/Http/Controllers/DepartmentPermissionController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/DepartmentPermissionController.php` - HTMX API 컨트롤러
- `resources/views/department-permissions/index.blade.php` - 메인 페이지
- `resources/views/department-permissions/partials/empty-state.blade.php` - 상태 화면
- `resources/views/department-permissions/partials/permission-matrix.blade.php` - 권한 매트릭스 테이블
### 수정된 파일:
- `routes/web.php` - 부서 권한 관리 라우트 추가
- `routes/api.php` - 부서 권한 관리 API 라우트 추가
- `resources/views/partials/sidebar.blade.php` - 부서 권한 관리 메뉴 활성화
### 기술 구조:
**권한 관리 방식:**
- Department 모델이 HasRoles trait 사용 (Spatie)
- `model_has_permissions` 테이블 사용 (model_type = 'App\\Models\\Tenants\\Department')
- 역할 권한 관리와 동일한 패턴 적용
- 하위 부서 권한 자동 전파 (재귀 처리)
**주요 메서드 (DepartmentPermissionService):**
- `getDepartmentPermissionMatrix()` - 부서별 권한 매트릭스 조회
- `togglePermission()` - 특정 메뉴 권한 토글
- `propagateToChildren()` - 하위 부서 권한 전파
- `allowAllPermissions()` - 모든 권한 허용
- `denyAllPermissions()` - 모든 권한 거부
- `getMenuTree()` - 메뉴 트리 조회 (depth 계산)
**UI 특징:**
- 부서 선택: 버튼 방식 (역할 권한 관리와 동일)
- 권한 매트릭스: 체크박스로 권한 토글
- 액션 버튼: 전체 허용/거부/초기화
- HTMX 실시간 업데이트
**테넌트 필터링:**
- 세션의 `selected_tenant_id` 기준으로 필터링
- 테넌트별 부서와 권한만 표시
### 다음 작업:
- [ ] 브라우저 테스트
- [ ] 권한 전파 동작 확인
- [ ] CSS 빌드 (필요 )
- [ ] 오류 수정 개선
---
## 2025-11-25 (월) - 부서 권한 체크박스 문제 해결
### 문제 상황:
- **증상**: 부서 권한 매트릭스의 체크박스 클릭 권한이 저장되지 않음
- **발견**: 역할 권한은 정상 작동, 부서 권한만 문제
- **사용자 피드백**:
1. 체크 저장
2. 나갔다 들어오면 체크 해제됨
3. 번째 부서가 자동 선택되지 않음
4. 클릭 기능이 작동하지 않음
### 근본 원인 발견 (code-workflow 스킬 사용):
**admin 패널 분석 결과:**
- Admin은 **부서별 전용 역할(Role)** 생성 방식 사용
- 부서 역할 매핑: `model_has_roles` 테이블
- 권한 저장: `role_has_permissions` 테이블 (Spatie)
- 역할명 패턴: "부서_{name}_권한"
**MNG 구현의 잘못된 접근:**
- `model_has_permissions` 테이블 직접 사용
- Department 모델에 permissions() 관계 추가
- 올바른 방법: admin과 동일하게 부서별 Role 생성
### 해결 방안:
#### 1. DepartmentPermissionService.php 완전 재작성
**새로운 메서드 추가:**
- `getDepartmentRole(departmentId)`: 부서 전용 역할 찾기/생성
- `model_has_roles` 테이블에서 부서-역할 매핑 조회
- 없으면 "부서_{name}_권한" 역할 자동 생성
- Department 모델에 역할 할당
**수정된 메서드:**
- `getDepartmentPermissionMatrix()`: role_has_permissions 테이블 조회로 변경
- `togglePermission()`: Spatie의 givePermissionTo/revokePermissionTo 사용
- `allowAllPermissions()`: 역할에 권한 부여
- `denyAllPermissions()`: 역할에서 권한 제거
- `propagateToChildren()`: 하위 부서의 역할에 권한 전파
#### 2. Department.php 모델 정리
- 제거: permissions() MorphToMany 관계
- 유지: HasRoles trait (Spatie)
- 유지: guard_name = 'web'
#### 3. View 파일 수정
**permission-matrix.blade.php:**
- 추가: `hx-trigger="click"` 속성
- 이유: 체크박스 클릭 즉시 HTMX 요청 발생
**index.blade.php:**
- 개선: 자동 선택 로직 수정
```javascript
// Before: firstButton.click() (HTMX 이벤트 미발생)
// After: selectDepartment(firstButton) + htmx.trigger(firstButton, 'click')
```
### 변경된 파일:
- `app/Services/DepartmentPermissionService.php` - 전면 재작성 (330줄)
- `app/Services/RolePermissionService.php` - Pint 자동 수정
- `app/Models/Tenants/Department.php` - permissions() 관계 제거
- `resources/views/department-permissions/index.blade.php` - 자동 선택 개선
- `resources/views/department-permissions/partials/permission-matrix.blade.php` - hx-trigger 추가
### 코드 품질:
- ✅ Laravel Pint 통과 (1개 스타일 이슈 자동 수정)
### 다음 단계:
- [ ] 브라우저 테스트 (체크박스 클릭, 권한 저장 확인)
- [ ] 자동 선택 동작 확인
- [ ] 하위 부서 권한 전파 동작 확인
- [ ] Git 커밋 (테스트 완료 후)
---
## 2025-11-25 (월) - guard_name 불일치 문제 해결 (code-workflow 스킬 사용)
### 🔍 근본 원인 재발견:
**Admin 패널 vs MNG 구현 차이:**
- **Admin**: guard_name = 'api', tenant_id 포함 (model_has_roles), Permission tenant_id = null
- **MNG (잘못된 구현)**: guard_name = 'web', tenant_id 누락, Permission tenant_id = $tenantId
**영향:**
- Spatie Permission은 guard_name이 일치해야 작동
- guard_name 불일치로 인해 hasPermissionTo(), givePermissionTo(), revokePermissionTo() 모두 실패
- 체크박스 클릭해도 권한이 저장되지 않는 근본 원인
### ✅ 해결 방안 (code-workflow 5단계):
#### 1단계: 분석 ✅
- MNG_CRITICAL_RULES.md, admin 구현 분석
- guard_name 불일치, tenant_id 누락 발견
#### 2단계: 수정 ✅
**DepartmentPermissionService.php:**
- line 44: guard_name 'web' → 'api'
- line 50-54: model_has_roles에 tenant_id 추가
- line 124: Permission guard_name 'web' → 'api', tenant_id null
- line 166: Permission guard_name 'web' → 'api', tenant_id null
- line 210: Permission guard_name 'web' → 'api', tenant_id null
**Department.php:**
- line 34: guard_name 'web' → 'api'
#### 3단계: 검증 ✅
- ✅ Laravel Pint: 2개 파일 통과
- ✅ 라우트 확인: API 라우트 정상
#### 4단계: 정리 ✅
- 임시 파일 없음
#### 5단계: 커밋 ⏳
- 대기 중 (브라우저 테스트 후)
### 변경된 파일:
- `app/Services/DepartmentPermissionService.php` - guard_name 통일, tenant_id 수정
- `app/Models/Tenants/Department.php` - guard_name 'api'로 변경
### 다음 단계:
- [ ] 브라우저 테스트 (권한 저장/조회 확인)
- [ ] 커밋 및 문서화
---
## 2025-11-26 (화) - 개인 권한 관리 구현 및 permission_overrides 테이블 통일
### 주요 작업
- 개인 권한 관리 (UserPermission) 기능 완전 구현
- 기존 model_has_permissions 테이블 → permission_overrides 테이블로 통일
- API AccessService와 동일한 테이블 구조 사용
### 추가된 파일:
- `app/Http/Controllers/UserPermissionController.php` - Blade 화면 컨트롤러
- `app/Http/Controllers/Api/Admin/UserPermissionController.php` - HTMX API 컨트롤러
- `resources/views/user-permissions/index.blade.php` - 메인 페이지
- `resources/views/user-permissions/partials/permission-matrix.blade.php` - 권한 매트릭스
- `resources/views/user-permissions/partials/empty-state.blade.php` - 빈 상태 화면
### 수정된 파일:
- `app/Services/UserPermissionService.php` - model_has_permissions → permission_overrides 테이블 사용
- `app/Services/DepartmentPermissionService.php` - model_has_permissions → permission_overrides 테이블 사용
- `routes/web.php` - 개인 권한 관리 라우트 추가
- `routes/api.php` - 개인 권한 관리 API 라우트 추가
- `resources/views/partials/sidebar.blade.php` - 개인 권한 관리 메뉴 링크 연결
### 기술 상세:
**permission_overrides 테이블 통일:**
- `model_type`: 폴리모픽 타입 (User, Department)
- `model_id`: 대상 ID
- `permission_id`: 권한 ID
- `effect`: 0=DENY, 1=ALLOW (현재 ALLOW만 관리)
- `effective_from`, `effective_to`: 유효 기간 지원
- Soft delete 지원 (deleted_at, deleted_by)
**권한 체크 우선순위 (API AccessService):**
1. 개인 DENY → 거부
2. Role 권한 (Spatie can) → 허용
3. 부서 ALLOW → 허용
4. 개인 ALLOW → 허용
5. 기본 → 거부
### 코드 품질:
- ✅ PHP 문법 검사 통과
- ✅ Pint 포맷팅 통과
---
## 2025-11-26 (화) - 역할/부서 권한 관리 테넌트별 그룹핑
### 주요 작업
- "전체" 테넌트 선택 시 역할/부서가 혼합 표시되는 문제 해결
- 테넌트별로 그룹핑하여 가독성 향상
### 수정된 파일:
- `app/Http/Controllers/RolePermissionController.php` - 테넌트별 역할 그룹핑 로직 추가
- `app/Http/Controllers/DepartmentPermissionController.php` - 테넌트별 부서 그룹핑 로직 추가
- `resources/views/role-permissions/index.blade.php` - 테넌트별 섹션 헤더 및 그룹핑 UI
- `resources/views/department-permissions/index.blade.php` - 테넌트별 섹션 헤더 및 그룹핑 UI
### 기술 구현:
**Controller 로직:**
```php
if ($tenantId && $tenantId !== 'all') {
// 특정 테넌트 선택 시 기존 방식
$roles = $rolesQuery->where('tenant_id', $tenantId)->get();
$rolesByTenant = null;
} else {
// 전체 선택 시 테넌트별 그룹핑
$roles = $rolesQuery->get();
$rolesByTenant = $roles->groupBy('tenant_id');
$tenantIds = $rolesByTenant->keys()->filter()->toArray();
$tenants = Tenant::whereIn('id', $tenantIds)->pluck('company_name', 'id');
}
```
**View UI:**
- 전체 테넌트 선택 시: 테넌트별 섹션으로 구분 (회색 라벨)
- 선택된 역할/부서 표시: `[테넌트명] 역할명 역할` 형식
- 기존 단일 테넌트 선택 시: 기존 UI 유지
### 이슈 해결:
- **문제**: `tenants` 테이블에 `name` 컬럼 없음 (SQL 에러)
- **원인**: 테넌트 테이블은 `company_name` 컬럼 사용
- **해결**: `pluck('name', 'id')` → `pluck('company_name', 'id')` 변경
### Git 커밋:
- ✅ `f029d78` "역할/부서 권한 관리 페이지 테넌트별 그룹핑 기능 추가"
### 문서화:
- ✅ `docs/[MNG-2025-11-26] role-department-permission-tenant-grouping.md` 작성
---
## 2025-11-26 (화) - 개인 권한 관리 3-state 토글 UI 구현
### 주요 작업
- 개인 권한 관리에서 허용/거부/미설정 3단계 상태 지원
- 체크박스 → 토글 버튼 UI로 변경
- 권한 상태 순환: 미설정 → 허용 → 거부 → 미설정
### 수정된 파일:
- `app/Services/UserPermissionService.php`
- `getUserPermissionMatrix()`: 3-state 지원 (null/'allow'/'deny' 반환)
- `togglePermission()`: 3단계 순환 로직 (null→allow→deny→null)
- `allowAllPermissions()`: DENY 레코드도 ALLOW로 변경
- `denyAllPermissions()`: ALLOW/DENY 모두 soft delete (미설정으로 초기화)
- `resources/views/user-permissions/partials/permission-matrix.blade.php`
- 체크박스 → 토글 버튼으로 변경
- 3가지 상태별 아이콘 및 색상:
- 미설정: (회색)
- 허용: ✓ (녹색)
- 거부: ✕ (빨간색)
- 범례 추가 (하단)
### UI/UX 변경사항:
**토글 버튼 디자인:**
```
미설정: bg-gray-100 text-gray-400 ()
허용: bg-green-100 text-green-600 (✓)
거부: bg-red-100 text-red-600 (✕)
```
**토글 순환:**
```
클릭 시: 미설정 → 허용 → 거부 → 미설정 (무한 순환)
```
**DB 상태:**
- 미설정: 레코드 없음 또는 soft delete (deleted_at)
- 허용: effect=1, deleted_at=null
- 거부: effect=0, deleted_at=null
### API AccessService 권한 체크 우선순위:
1. 개인 DENY → 즉시 거부
2. Role 권한 (Spatie can) → 허용
3. 부서 ALLOW → 허용
4. 개인 ALLOW → 허용
5. 기본 → 거부
### 코드 품질:
- ✅ PHP 문법 검사 통과
- ✅ Pint 포맷팅 통과
---
## 2025-11-26 (화) - 개인 권한 관리 통합 매트릭스 구현
### 주요 작업
- 역할/부서/개인 권한을 통합하여 최종 유효 권한 표시
- 권한 소스별 색상 구분 (역할=보라, 부서=파랑, 개인허용=녹색, 개인거부=빨강)
- 스마트 토글 로직 구현 (상속된 권한 오버라이드 지원)
### 수정된 파일:
- `app/Services/UserPermissionService.php` - 역할/부서/개인 권한 통합 조회
- `getRolePermissions()`: Spatie `model_has_roles` + `role_has_permissions` 조회
- `getDepartmentPermissions()`: `permission_overrides` 테이블 (Department 모델타입) 조회
- `getPersonalOverrides()`: `permission_overrides` 테이블 (User 모델타입) 조회
- `getUserPermissionMatrix()`: 모든 권한 소스 통합, 소스 정보 반환
- `togglePermission()`: 스마트 토글 로직
- `resources/views/user-permissions/index.blade.php` - 사용자 ID 뱃지 스타일 개선
- `resources/views/user-permissions/partials/permission-matrix.blade.php` - 5가지 상태 UI
### 기술 구현:
**권한 소스 우선순위 (표시용):**
1. 개인 DENY → 최우선 (빨간색)
2. 개인 ALLOW → 녹색
3. 역할 권한 (Spatie) → 보라색
4. 부서 권한 → 파란색
5. 미설정 → 회색
**스마트 토글 로직:**
```
- 역할/부서 권한 (개인 설정 없음) → 클릭 시 개인 DENY 추가 (오버라이드)
- 개인 DENY → 클릭 시 삭제 (상속된 권한 복원)
- 권한 없음 → 클릭 시 개인 ALLOW 추가
- 개인 ALLOW → 클릭 시 개인 DENY로 변경
```
**색상 코드:**
```
보라색 (bg-purple-100): 역할에서 상속된 권한
파란색 (bg-blue-100): 부서에서 상속된 권한
녹색 (bg-green-100): 개인 허용 설정
빨간색 (bg-red-100): 개인 거부 설정
회색 (bg-gray-100): 미설정
```
**UI 개선:**
- 사용자 선택 버튼: 이름 + 아이디 뱃지 (`&nbsp;` 패딩)
- 선택된 사용자 표시: 테두리 스타일 (`border border-blue-400`)
- 범례 업데이트: 5가지 상태 모두 표시
### 코드 품질:
- PHP 문법 검사 통과
- Pint 포맷팅 통과
---