Files
sam-manage/CURRENT_WORKS.md
hskwon fbd4fb728e feat: [api-explorer] Phase 1 기본 구조 및 OpenAPI 파싱 구현
- Config, Service, Controller, View 생성
- Model 4개 (admin_api_* 테이블 참조)
- 3-Panel 레이아웃 (sidebar, request, response)
- HTMX 기반 동적 UI
- 마이그레이션은 api/ 프로젝트에서 관리
2025-12-17 22:06:28 +09:00

63 KiB
Raw Blame History

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 커밋:

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-primarybg-primary text-white rounded-lg
    • cardbg-white rounded-lg shadow-xl
    • input input-borderedborder 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 토큰 자동 포함

사용법:

@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_iddepartments.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: 테넌트 관리

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:

  • 개선: 자동 선택 로직 수정
    // 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 로직:

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, hideModalMenuDescendantswindow 객체에 등록
    • 모달 오픈 시 구독정보 탭 자동 로드 (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 문제 해결):

// Before: function toggleModalMenuChildren() {}
// After: window.toggleModalMenuChildren = function() {}
  • 동적으로 로드된 HTML에서 함수 접근 가능

행 클릭 + 액션 버튼 우선권:

<tr onclick="TenantModal.open({{ $tenant->id }})">
  <td onclick="event.stopPropagation()">
    <!-- 액션 버튼들 -->
  </td>
</tr>
  • event.stopPropagation()으로 버블링 방지

삭제된 테넌트 경고 배너:

  • 빨간색 배경 (bg-red-50)
  • 삭제일 + 삭제자 정보 표시
  • 복원 버튼 포함

복원 후 모달 새로고침:

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] 사용자 등록 시 비밀번호 자동 생성 및 이메일 발송"