Files
sam-manage/CURRENT_WORKS.md
hskwon a332e0cee4 fix: Price 모델 items 테이블 참조 및 견적 시더 입력필드 추가
- Price.getSalesPriceByItemCode() products/materials → items 테이블 수정
- SeedQuoteFormulasCommand INPUT 카테고리 및 Design 사이트 동기화
  - PC(제품카테고리), PRODUCT_ID(제품명), GT(설치유형)
  - MP(모터전원), CT(제어기), QTY(수량) 필드 추가
- metadata에 field_type, options 정보 추가
2025-12-22 22:48:03 +09:00

1761 lines
65 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-12-17 (화) - API Explorer Phase 1 개발
### 주요 작업
**API Explorer (Swagger UI 대체 개발 도구)**
- OpenAPI 3.0 JSON 파싱 및 엔드포인트 표시
- 3-Panel 레이아웃 (사이드바, 요청, 응답)
- HTMX 기반 SPA 경험
- 즐겨찾기, 템플릿, 히스토리 관리
- 환경 설정 (API Key 암호화 저장)
### 생성된 파일
**Config**
- `config/api-explorer.php` - 설정 파일
**Migration (4개)**
- `2025_12_17_000001_create_api_bookmarks_table.php`
- `2025_12_17_000002_create_api_templates_table.php`
- `2025_12_17_000003_create_api_histories_table.php`
- `2025_12_17_000004_create_api_environments_table.php`
**Model (4개)**
- `app/Models/DevTools/ApiBookmark.php`
- `app/Models/DevTools/ApiTemplate.php`
- `app/Models/DevTools/ApiHistory.php`
- `app/Models/DevTools/ApiEnvironment.php`
**Service (3개)**
- `app/Services/ApiExplorer/OpenApiParserService.php` - OpenAPI 파싱
- `app/Services/ApiExplorer/ApiRequestService.php` - API 프록시 실행
- `app/Services/ApiExplorer/ApiExplorerService.php` - CRUD 로직
**Controller**
- `app/Http/Controllers/DevTools/ApiExplorerController.php`
**View (5개)**
- `resources/views/dev-tools/api-explorer/index.blade.php`
- `resources/views/dev-tools/api-explorer/partials/sidebar.blade.php`
- `resources/views/dev-tools/api-explorer/partials/request-panel.blade.php`
- `resources/views/dev-tools/api-explorer/partials/response-panel.blade.php`
- `resources/views/dev-tools/api-explorer/partials/history-drawer.blade.php`
**Route**
- `routes/web.php` - 23개 라우트 등록
### 접근 경로
```
/mng/dev-tools/api-explorer
```
### 다음 단계 (Phase 2-5)
- Phase 2: API 실행 기능 완성
- Phase 3: 즐겨찾기/템플릿 UI
- Phase 4: 히스토리/환경 관리
- Phase 5: UX 개선
---
## 2025-12-02 (월) - 메뉴/게시판/사용자 기능 확장
### 주요 작업
**1. 메뉴 관리 드래그 앤 드롭 기능**
- SortableJS 기반 같은 레벨 내 순서 변경
- Notion 스타일 좌우 드래그로 계층 이동
- → 오른쪽 드래그: 하위로 이동 (인덴트)
- ← 왼쪽 드래그: 상위로 이동 (아웃덴트)
- 시각적 피드백: 펄스 애니메이션, 색상 구분 (파란색/주황색)
- 드래그 인디케이터 툴팁
**2. 프로필 설정 페이지**
- `/profile` - 프로필 설정 페이지 추가
- 기본 정보 수정 (이름, 이메일)
- 비밀번호 변경 기능
- ProfileController, ProfileService 추가
**3. 최초 로그인 비밀번호 변경 강제**
- EnsurePasswordChanged 미들웨어
- must_change_password 필드 활용
- 최초 로그인 시 프로필 페이지로 리다이렉트
**4. 게시판 관리 기능 확장**
- 템플릿 기반 게시판 생성 (공지사항, FAQ, 자료실, 갤러리 등)
- config/board_templates.php 설정 파일
- SVG 아이콘 적용
**5. 게시글 파일 첨부 기능**
- 파일 업로드/다운로드/삭제
- 다중 파일 첨부 지원
- boards/{board_id}/posts/{post_id} 디렉토리 구조
**6. 일일 스크럼(Daily Logs) 기능**
- 스크럼 목록/상세/작성
- 날짜별 엔트리 관리
- DailyLogController, DailyLogService
- AdminPmDailyLog, AdminPmDailyLogEntry 모델
**7. 테넌트 관리 UI 개선**
- 목록/모달 UI 개선
- 모달 하단 버튼 플로팅 고정
### 수정된 파일
- `app/Http/Controllers/Api/Admin/MenuController.php` - move, reorder 메서드 추가
- `app/Services/MenuService.php` - moveMenu, reorderMenus 메서드 추가
- `resources/views/menus/index.blade.php` - 드래그 앤 드롭 JS/CSS
- `app/Http/Controllers/ProfileController.php` - 신규
- `app/Services/ProfileService.php` - 신규
- `app/Http/Middleware/EnsurePasswordChanged.php` - 신규
- `app/Services/BoardService.php` - 템플릿 생성 메서드 추가
- `app/Services/PostService.php` - 파일 첨부 로직 추가
- `resources/views/posts/*.blade.php` - 파일 첨부 UI
### API 엔드포인트 추가
- POST `/api/admin/menus/reorder` - 메뉴 순서 변경
- POST `/api/admin/menus/move` - 메뉴 계층 이동
- POST `/api/admin/boards/from-template` - 템플릿 기반 게시판 생성
- POST `/api/admin/posts/{id}/files` - 파일 업로드
- DELETE `/api/admin/posts/{id}/files/{fileId}` - 파일 삭제
---
## 2025-11-27 (수) - 시스템 게시판 관리 화면 개발
### 작업 목표
- mng에서 시스템 게시판 (is_system=true) 생성/수정/삭제 관리
- 게시판 커스텀 필드 관리 기능
### 추가된 파일
**Model**:
- `app/Models/Boards/Board.php` - 게시판 모델 (SoftDeletes, 스코프)
- `app/Models/Boards/BoardSetting.php` - 게시판 필드 설정 모델
**Service**:
- `app/Services/BoardService.php` - 게시판 비즈니스 로직
**Controller**:
- `app/Http/Controllers/BoardController.php` - Blade 뷰 컨트롤러
- `app/Http/Controllers/Api/Admin/BoardController.php` - API 컨트롤러 (HTMX)
**Views**:
- `resources/views/boards/index.blade.php` - 게시판 목록
- `resources/views/boards/create.blade.php` - 게시판 생성
- `resources/views/boards/edit.blade.php` - 게시판 수정 + 필드 관리
- `resources/views/boards/partials/table.blade.php` - 테이블 파셜
### 수정된 파일
- `routes/web.php` - boards.* 라우트 추가
- `routes/api.php` - api.admin.boards.* API 라우트 추가
### API 엔드포인트 (17개)
**게시판 관리**:
- GET `/api/admin/boards` - 목록 (HTMX)
- GET `/api/admin/boards/stats` - 통계
- POST `/api/admin/boards` - 생성
- GET `/api/admin/boards/{id}` - 조회
- PUT `/api/admin/boards/{id}` - 수정
- DELETE `/api/admin/boards/{id}` - 삭제 (Soft)
- POST `/api/admin/boards/{id}/restore` - 복원
- DELETE `/api/admin/boards/{id}/force` - 영구삭제
- POST `/api/admin/boards/{id}/toggle-active` - 활성/비활성 토글
**필드 관리**:
- GET `/api/admin/boards/{id}/fields` - 필드 목록
- POST `/api/admin/boards/{id}/fields` - 필드 추가
- PUT `/api/admin/boards/{id}/fields/{fieldId}` - 필드 수정
- DELETE `/api/admin/boards/{id}/fields/{fieldId}` - 필드 삭제
- POST `/api/admin/boards/{id}/fields/reorder` - 필드 순서 변경
**웹 라우트**:
- GET `/boards` - 목록 화면
- GET `/boards/create` - 생성 화면
- GET `/boards/{id}/edit` - 수정 화면
### 주요 기능
1. 시스템 게시판 CRUD (is_system=true 자동 설정)
2. 게시판 유형 자유 입력 (board_type)
3. 커스텀 필드 관리 (EAV 패턴)
4. SoftDeletes 지원 (복원/영구삭제)
5. HTMX 기반 테이블 로딩
### 다음 작업
- sam API 개발 (테넌트용 게시판 + 게시글 API)
- Swagger 문서화
- 테스트
---
## 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 포맷팅 통과
---
## 2025-11-27 (수) - 테넌트 정보 모달 팝업 기능 구현
### 주요 작업
- 테넌트 행 클릭 시 모달 팝업 오픈 기능 구현
- 모달 내 JS 함수 window 객체 등록 (동적 HTML 접근 문제 해결)
- 삭제된 테넌트 경고 배너 추가 (삭제일, 삭제자 표시)
- 복원 후 모달 내용 자동 새로고침
### 수정된 파일:
#### JavaScript
- `public/js/tenant-modal.js`
- `toggleModalMenuChildren`, `hideModalMenuDescendants` → `window` 객체에 등록
- 모달 오픈 시 구독정보 탭 자동 로드 (`switchTab('subscription')`)
- `isOpen()` 메서드 추가 (모달 상태 확인용)
#### Blade Views
- `resources/views/tenants/partials/table.blade.php`
- 행 클릭 시 모달 오픈: `onclick="TenantModal.open({{ $tenant->id }})"`
- 액션 버튼 우선권: `onclick="event.stopPropagation()"`
- `resources/views/tenants/partials/modal-info.blade.php`
- 삭제된 테넌트 경고 배너 추가 (빨간색 bg-red-50)
- 삭제일/삭제자 정보 표시
- 배너 내 복원 버튼 추가
- `resources/views/tenants/index.blade.php`
- `confirmRestore()`: 복원 후 모달 내용 새로고침 로직 추가
#### Models & Services
- `app/Models/Tenants/Tenant.php`
- `deleted_by` 컬럼 fillable 추가
- `deletedByUser()` 관계 추가 (삭제자 정보 조회)
- `app/Services/TenantService.php`
- `deleteTenant()`: deleted_by 기록
- `restoreTenant()`: deleted_by null 초기화
- `getTenantForModal()`: deletedByUser 관계 eager loading 추가
### 기술 상세:
**JS 함수 window 등록 (동적 HTML 문제 해결):**
```javascript
// Before: function toggleModalMenuChildren() {}
// After: window.toggleModalMenuChildren = function() {}
```
- 동적으로 로드된 HTML에서 함수 접근 가능
**행 클릭 + 액션 버튼 우선권:**
```html
<tr onclick="TenantModal.open({{ $tenant->id }})">
<td onclick="event.stopPropagation()">
<!-- 액션 버튼들 -->
</td>
</tr>
```
- `event.stopPropagation()`으로 버블링 방지
**삭제된 테넌트 경고 배너:**
- 빨간색 배경 (bg-red-50)
- 삭제일 + 삭제자 정보 표시
- 복원 버튼 포함
**복원 후 모달 새로고침:**
```javascript
if (TenantModal.isOpen() && TenantModal.currentTenantId === id) {
TenantModal.loadTenantInfo();
}
```
### 이슈 해결:
- **toggleModalMenuChildren not defined**: window 객체에 함수 등록으로 해결
- **복원 후 배너 미갱신**: `loadTenantInfo()` 호출 추가
### Git 커밋:
- ✅ `b32f6cf` "feat: 테넌트 정보 모달 팝업 기능 추가"
- 17 files changed, 1476 insertions(+), 4 deletions(-)
---
## 2025-12-01 (일) - 사용자 비밀번호 자동 생성 및 이메일 발송 기능
### 주요 작업
- 사용자 등록 시 비밀번호 입력 필드 제거 → 임의 비밀번호 자동 생성 후 이메일 발송
- 사용자 수정 페이지에 비밀번호 초기화 버튼 추가
- 사용자 모달에 비밀번호 초기화 버튼 추가
- 사용자 모달 프로필 이미지 없을 때 이름 첫글자 표시 (한글 지원: `mb_strtoupper`)
### 추가된 파일:
#### Mail
- `app/Mail/UserPasswordMail.php` - 비밀번호 알림 Mailable 클래스
- 신규 사용자 / 비밀번호 초기화 구분 (`$isNewUser`)
- 제목: `[SAM] 계정이 생성되었습니다` / `[SAM] 비밀번호가 초기화되었습니다`
- `resources/views/emails/user-password.blade.php` - 이메일 템플릿
- 스타일링된 HTML 이메일
- 사용자 이름, 이메일, 임시 비밀번호 표시
- 첫 로그인 후 비밀번호 변경 안내
### 수정된 파일:
#### Service
- `app/Services/UserService.php`
- `createUser()`: 비밀번호 자동 생성 + 이메일 발송
- `resetPassword()`: 비밀번호 초기화 + 이메일 발송 (신규 메서드)
- `generateRandomPassword()`: 8자리 임의 비밀번호 생성 (혼동 문자 제외: 0, O, l, 1, I)
- `sendPasswordMail()`: 이메일 발송 헬퍼 메서드
#### Controller
- `app/Http/Controllers/Api/Admin/UserController.php`
- `resetPassword()`: 비밀번호 초기화 엔드포인트 추가
- 슈퍼관리자 보호: 일반 관리자가 슈퍼관리자 비밀번호 초기화 불가
#### Request
- `app/Http/Requests/StoreUserRequest.php`
- password 필드 검증 주석 처리 (자동 생성으로 변경)
#### Routes
- `routes/api.php`
- `POST /api/admin/users/{id}/reset-password` 라우트 추가
#### Views
- `resources/views/users/create.blade.php`
- 비밀번호 입력 필드 제거 → 안내 메시지 표시
- "임시 비밀번호가 생성되어 사용자 이메일로 발송됩니다"
- `resources/views/users/edit.blade.php`
- 비밀번호 입력 필드 제거 → 초기화 버튼으로 변경
- HTMX 대신 Fetch API 사용 (버튼 상태 관리)
- `resources/views/users/partials/modal-info.blade.php`
- 프로필 이미지 없을 때: `strtoupper(substr())` → `mb_strtoupper(mb_substr())` (한글 지원)
- 비밀번호 초기화 버튼 추가 (삭제된 사용자 제외)
#### JavaScript
- `public/js/user-modal.js`
- `resetPassword()`: 비밀번호 초기화 메서드 추가
- confirm 다이얼로그 후 API 호출
### API 엔드포인트:
- `POST /api/admin/users/{id}/reset-password`
- 성공: `{ success: true, message: "비밀번호가 초기화되어 이메일로 발송되었습니다." }`
- 실패 (슈퍼관리자 보호): `{ success: false, message: "슈퍼관리자의 비밀번호는 초기화할 없습니다." }`
### 이메일 설정:
- Gmail SMTP 사용 (`smtp.gmail.com:587`)
- Google Groups 이메일 발신자 지원 (Gmail "다른 주소에서 메일 보내기" 설정 필요)
- 설정 가이드: `docs/SETUP_GUIDE.md` 참조
### 코드 품질:
- ✅ Laravel Pint 통과
- ✅ PHP 문법 검사 통과
### Git 커밋:
- ✅ `85cbe23` "feat: [users] 사용자 등록 시 비밀번호 자동 생성 및 이메일 발송"
---
## 2025-12-22 (일) - 견적 자동산출 시더 및 Price 모델 수정
### 주요 작업
**1. Price 모델 수정 (products → items 테이블)**
- `getSalesPriceByItemCode()` 메서드가 삭제된 `products`, `materials` 테이블 대신 통합된 `items` 테이블 조회하도록 수정
- 원인: products/materials 테이블이 items로 통합되었으나 MNG의 Price 모델은 미반영
**2. 견적수식 시더 입력 필드 추가**
- Design 사이트 견적 입력 폼과 동기화
- INPUT 카테고리 추가 (sort_order: 0)
- 새 입력 필드 6개 추가:
| 변수명 | 필드명 | 타입 | 옵션 |
|------------|-------------|--------|------|
| PC | 제품카테고리 | select | 스크린/철재 |
| PRODUCT_ID | 제품명 | select | PC에 따라 변경 |
| GT | 설치유형 | select | 벽면/천장/바닥 |
| MP | 모터전원 | select | 220V/380V |
| CT | 제어기 | select | 단독제어/연동제어 |
| QTY | 수량 | number | min: 1 |
- 기존 W0, H0 필드 metadata 보강
### 수정된 파일
**Models**
- `app/Models/Price.php` - getSalesPriceByItemCode() items 테이블 사용
**Console Commands**
- `app/Console/Commands/SeedQuoteFormulasCommand.php`
- INPUT 카테고리 추가
- Design 사이트 입력 필드 6개 추가 (PC, PRODUCT_ID, GT, MP, CT, QTY)
- metadata에 field_type, options 정보 추가
### 시더 실행 결과 (tenant: 287)
```
카테고리: 12개 (INPUT 추가)
수식: 24개 (이전 18개 + 새 input 6개)
범위: 18개
품목: 4개
```
### 시뮬레이터 접근
- URL: https://mng.sam.kr/quote-formulas/simulator
- 입력 필드 표시 (UI가 metadata 지원 )
---