- MENU_INTEGRATION_SYSTEM_DESIGN.md: 글로벌-테넌트 메뉴 연결 시스템 설계 - global_menu_id, is_customized 컬럼 추가 계획 - API 엔드포인트 설계 (글로벌/테넌트 메뉴 관리) - MNG 화면 설계 (복제, 동기화 기능) - 구현 Phase 1~4 계획 - MENU_INSERT_QUERIES.sql: PDF 기획서 기반 신규 메뉴 23개 INSERT 쿼리 - 인사관리 (근태/휴가/급여) - 전자결재 (기안함/결재함/참조함) - 게시판, 보고서, 계정정보, 회사정보, 구독관리, 결제내역, 고객센터 - 기준정보 관리 하위 8개 메뉴
374 lines
12 KiB
Markdown
374 lines
12 KiB
Markdown
# 메뉴 통합관리 시스템 설계서
|
|
|
|
> 작성일: 2025-12-01
|
|
> 상태: 설계 완료, 개발 대기
|
|
> 관련 문서: SAM_ERP_인사관리전자결재_Storyboard_D0.6_251201.pdf
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
### 1.1 배경
|
|
현재 테넌트 생성 시 글로벌 메뉴(tenant_id = NULL)를 완전히 복사하여 독립적인 테넌트 메뉴를 생성합니다. 이 방식은 원본과의 연결이 없어 관리가 어렵습니다.
|
|
|
|
### 1.2 목표
|
|
- 글로벌 메뉴와 테넌트 메뉴 간의 연결(링크) 시스템 구축
|
|
- 템플릿 복사 시에도 관계 유지
|
|
- 관리자에서 메뉴 추가/삭제/동기화 관리 용이하게
|
|
|
|
### 1.3 현재 구조 vs 목표 구조
|
|
|
|
**현재:**
|
|
```
|
|
글로벌 메뉴 (tenant_id = NULL)
|
|
↓ 완전 복사 (독립)
|
|
테넌트 메뉴 (tenant_id = X)
|
|
❌ 원본과의 연결 없음
|
|
```
|
|
|
|
**목표:**
|
|
```
|
|
글로벌 메뉴 (id=10)
|
|
↓ 복사 + 링크 유지
|
|
테넌트 메뉴 (id=100, global_menu_id=10)
|
|
✅ 원본 추적 가능
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 정책 결정 사항
|
|
|
|
| 항목 | 결정 내용 |
|
|
|------|----------|
|
|
| **글로벌 메뉴 삭제 시** | 테넌트 메뉴 유지 (`global_menu_id = NULL`로 변경) |
|
|
| **활성 메뉴 (is_active=1)** | 새 테넌트 생성 시 자동 복사 |
|
|
| **비활성 메뉴 (is_active=0)** | 테넌트가 수동으로 복제 가능 |
|
|
| **숨김 메뉴 (hidden=1)** | 복사되지만 테넌트에서 메뉴 안 보임 |
|
|
| **기존 데이터** | 신규 테넌트부터 적용 (기존 데이터 변경 없음) |
|
|
|
|
---
|
|
|
|
## 3. 테넌트 메뉴 기능 매트릭스
|
|
|
|
| 기능 | 설명 | API | MNG |
|
|
|------|------|-----|-----|
|
|
| **복제** | 글로벌 메뉴 → 테넌트 메뉴로 복제 | ✅ | ✅ |
|
|
| **추가** | 테넌트 자체 메뉴 생성 (global_menu_id = NULL) | ✅ | ✅ |
|
|
| **수정** | 메뉴명, URL, 아이콘, 정렬 등 수정 | ✅ | ✅ |
|
|
| **삭제** | 테넌트 메뉴 삭제 (소프트) | ✅ | ✅ |
|
|
| **숨김** | hidden 토글 | ✅ | ✅ |
|
|
| **복원** | 삭제된 메뉴 복원 | ✅ | ✅ |
|
|
| **동기화** | 글로벌 메뉴 변경사항 반영 | ✅ | ✅ |
|
|
|
|
---
|
|
|
|
## 4. DB 스키마 변경
|
|
|
|
### 4.1 마이그레이션
|
|
|
|
```sql
|
|
-- 1. global_menu_id 컬럼 추가
|
|
ALTER TABLE menus
|
|
ADD COLUMN global_menu_id BIGINT UNSIGNED NULL
|
|
COMMENT '원본 글로벌 메뉴 ID (복제된 메뉴인 경우)'
|
|
AFTER parent_id;
|
|
|
|
-- 2. is_customized 플래그 추가 (원본 대비 수정 여부)
|
|
ALTER TABLE menus
|
|
ADD COLUMN is_customized TINYINT(1) NOT NULL DEFAULT 0
|
|
COMMENT '테넌트가 커스터마이징 했는지 여부'
|
|
AFTER hidden;
|
|
|
|
-- 3. 인덱스 추가
|
|
ALTER TABLE menus ADD INDEX menus_global_menu_id_idx (global_menu_id);
|
|
ALTER TABLE menus ADD INDEX menus_tenant_global_idx (tenant_id, global_menu_id);
|
|
```
|
|
|
|
### 4.2 변경된 테이블 구조
|
|
|
|
```
|
|
menus
|
|
├── id (PK)
|
|
├── tenant_id (FK, NULL = 글로벌 메뉴)
|
|
├── parent_id (FK, 상위 메뉴)
|
|
├── global_menu_id (FK, 원본 글로벌 메뉴) ← 신규
|
|
├── name
|
|
├── url
|
|
├── icon
|
|
├── sort_order
|
|
├── is_active
|
|
├── hidden
|
|
├── is_customized ← 신규
|
|
├── is_external
|
|
├── external_url
|
|
├── created_by
|
|
├── updated_by
|
|
├── deleted_by
|
|
├── created_at
|
|
├── updated_at
|
|
└── deleted_at
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 메뉴 상태 플로우
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ 글로벌 메뉴 (tenant_id = NULL) │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ is_active=1, hidden=0 → 새 테넌트에 자동 복사 │
|
|
│ is_active=1, hidden=1 → 복사되지만 테넌트에서 안 보임 │
|
|
│ is_active=0 → 복사 안됨, 테넌트가 수동 복제 가능 │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ 테넌트 메뉴 (tenant_id = X) │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ global_menu_id = 10 → 글로벌 메뉴 #10에서 복제됨 │
|
|
│ global_menu_id = NULL → 테넌트가 직접 생성한 메뉴 │
|
|
│ is_customized = 1 → 테넌트가 내용 수정함 │
|
|
│ is_customized = 0 → 원본 그대로 │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 6. API 엔드포인트 설계
|
|
|
|
### 6.1 글로벌 메뉴 관리 (시스템 관리자용)
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/v1/admin/global-menus` | 글로벌 메뉴 목록 |
|
|
| POST | `/v1/admin/global-menus` | 글로벌 메뉴 생성 |
|
|
| PUT | `/v1/admin/global-menus/{id}` | 글로벌 메뉴 수정 |
|
|
| DELETE | `/v1/admin/global-menus/{id}` | 글로벌 메뉴 삭제 |
|
|
| POST | `/v1/admin/global-menus/{id}/sync-to-tenants` | 특정 메뉴를 모든 테넌트에 추가 |
|
|
|
|
### 6.2 테넌트 메뉴 관리 (테넌트 관리자용)
|
|
|
|
| Method | Endpoint | 설명 |
|
|
|--------|----------|------|
|
|
| GET | `/v1/menus` | 테넌트 메뉴 목록 (기존) |
|
|
| GET | `/v1/menus/available-global` | 복제 가능한 글로벌 메뉴 목록 |
|
|
| POST | `/v1/menus` | 테넌트 메뉴 생성 (기존) |
|
|
| POST | `/v1/menus/clone-global/{globalMenuId}` | 글로벌 메뉴 복제 |
|
|
| PUT | `/v1/menus/{id}` | 테넌트 메뉴 수정 (기존) |
|
|
| DELETE | `/v1/menus/{id}` | 테넌트 메뉴 삭제 (기존) |
|
|
| PATCH | `/v1/menus/{id}/toggle` | 상태 토글 (기존) |
|
|
| POST | `/v1/menus/{id}/restore` | 삭제된 메뉴 복원 |
|
|
| POST | `/v1/menus/{id}/sync-from-global` | 글로벌 원본과 동기화 |
|
|
| POST | `/v1/menus/reorder` | 메뉴 순서 변경 (기존) |
|
|
|
|
---
|
|
|
|
## 7. 서비스 메서드 설계
|
|
|
|
### 7.1 MenuService.php 추가 메서드
|
|
|
|
```php
|
|
/**
|
|
* 복제 가능한 글로벌 메뉴 목록
|
|
* - 테넌트가 아직 복제하지 않은 글로벌 메뉴
|
|
*/
|
|
public function getAvailableGlobalMenus(int $tenantId): Collection
|
|
|
|
/**
|
|
* 글로벌 메뉴를 테넌트로 복제
|
|
*/
|
|
public function cloneFromGlobal(int $globalMenuId, int $tenantId): Menu
|
|
|
|
/**
|
|
* 글로벌 원본과 동기화 (이름, URL, 아이콘 등 업데이트)
|
|
*/
|
|
public function syncFromGlobal(int $menuId): Menu
|
|
|
|
/**
|
|
* 삭제된 메뉴 복원
|
|
*/
|
|
public function restore(int $menuId): Menu
|
|
```
|
|
|
|
### 7.2 GlobalMenuService.php (신규)
|
|
|
|
```php
|
|
/**
|
|
* 글로벌 메뉴 생성
|
|
*/
|
|
public function store(array $data): Menu
|
|
|
|
/**
|
|
* 글로벌 메뉴 수정
|
|
*/
|
|
public function update(int $id, array $data): Menu
|
|
|
|
/**
|
|
* 글로벌 메뉴 삭제 (연결된 테넌트 메뉴의 global_menu_id를 NULL로)
|
|
*/
|
|
public function destroy(int $id): bool
|
|
|
|
/**
|
|
* 특정 글로벌 메뉴를 모든 테넌트에 추가
|
|
*/
|
|
public function syncToAllTenants(int $globalMenuId): int
|
|
```
|
|
|
|
---
|
|
|
|
## 8. MNG 화면 설계
|
|
|
|
### 8.1 글로벌 메뉴 관리 (시스템 관리자)
|
|
|
|
```
|
|
/mng/global-menus
|
|
├── 목록 화면
|
|
│ ├── 트리 구조로 표시
|
|
│ ├── 활성/비활성/숨김 상태 표시
|
|
│ ├── 연결된 테넌트 수 표시
|
|
│ └── 추가/수정/삭제 버튼
|
|
│
|
|
├── 생성/수정 모달
|
|
│ ├── 메뉴명, URL, 아이콘
|
|
│ ├── 상위 메뉴 선택
|
|
│ ├── 활성 여부, 숨김 여부
|
|
│ └── 정렬 순서
|
|
│
|
|
└── 테넌트 동기화 모달
|
|
├── 대상 테넌트 선택 (전체/선택)
|
|
└── 동기화 실행
|
|
```
|
|
|
|
### 8.2 테넌트 메뉴 관리 (테넌트 관리자)
|
|
|
|
```
|
|
/mng/menus
|
|
├── 목록 화면
|
|
│ ├── 트리 구조로 표시
|
|
│ ├── 글로벌 연결 여부 표시 (🔗 아이콘)
|
|
│ ├── 커스터마이징 여부 표시 (✏️ 아이콘)
|
|
│ └── 추가/수정/삭제/숨김 버튼
|
|
│
|
|
├── 글로벌 메뉴 복제 모달
|
|
│ ├── 복제 가능한 글로벌 메뉴 목록
|
|
│ ├── 체크박스 선택
|
|
│ └── 일괄 복제 버튼
|
|
│
|
|
├── 생성/수정 모달
|
|
│ ├── 메뉴명, URL, 아이콘
|
|
│ ├── 상위 메뉴 선택
|
|
│ └── 정렬 순서
|
|
│
|
|
└── 동기화 모달
|
|
├── 원본과 비교 (diff 표시)
|
|
└── 동기화 실행 버튼
|
|
```
|
|
|
|
---
|
|
|
|
## 9. 변경 영향도 분석
|
|
|
|
| 파일 | 변경 내용 | 영향도 |
|
|
|------|----------|--------|
|
|
| `database/migrations/` | global_menu_id, is_customized 추가 | 🔴 높음 |
|
|
| `app/Models/Commons/Menu.php` | fillable, 관계 메서드 추가 | 🟡 중간 |
|
|
| `app/Services/MenuService.php` | 복제, 동기화, 복원 메서드 추가 | 🟡 중간 |
|
|
| `app/Services/MenuBootstrapService.php` | global_menu_id 저장 로직 추가 | 🟡 중간 |
|
|
| `app/Services/GlobalMenuService.php` | 신규 생성 | 🟢 낮음 |
|
|
| `app/Http/Controllers/Api/V1/MenuController.php` | 엔드포인트 추가 | 🟡 중간 |
|
|
| `app/Http/Controllers/Api/Admin/GlobalMenuController.php` | 신규 생성 | 🟢 낮음 |
|
|
| `routes/api.php` | 라우트 추가 | 🟡 중간 |
|
|
| `mng/` | 뷰, 컨트롤러 생성 | 🟢 낮음 |
|
|
|
|
---
|
|
|
|
## 10. 구현 계획
|
|
|
|
### Phase 1: DB 및 모델 (1일)
|
|
- [ ] 마이그레이션 생성 (`global_menu_id`, `is_customized`)
|
|
- [ ] Menu 모델 수정 (fillable, 관계 메서드)
|
|
- [ ] MenuBootstrapService 수정 (복사 시 global_menu_id 저장)
|
|
|
|
### Phase 2: API 서비스 (1-2일)
|
|
- [ ] GlobalMenuService 생성
|
|
- [ ] MenuService 메서드 추가
|
|
- [ ] `getAvailableGlobalMenus()`
|
|
- [ ] `cloneFromGlobal()`
|
|
- [ ] `syncFromGlobal()`
|
|
- [ ] `restore()`
|
|
- [ ] GlobalMenuController 생성
|
|
- [ ] MenuController 엔드포인트 추가
|
|
- [ ] 라우트 등록
|
|
|
|
### Phase 3: MNG 화면 (2-3일)
|
|
- [ ] 글로벌 메뉴 관리 화면
|
|
- [ ] 목록 (트리 구조)
|
|
- [ ] 생성/수정/삭제
|
|
- [ ] 테넌트 동기화
|
|
- [ ] 테넌트 메뉴 관리 화면 개선
|
|
- [ ] 글로벌 연결 표시
|
|
- [ ] 복제 기능
|
|
- [ ] 동기화 기능
|
|
|
|
### Phase 4: 테스트 (1일)
|
|
- [ ] 유닛 테스트
|
|
- [ ] 통합 테스트
|
|
|
|
---
|
|
|
|
## 11. 관련 파일 위치
|
|
|
|
```
|
|
API 프로젝트: /Users/hskwon/Works/@KD_SAM/SAM/api/
|
|
|
|
├─ app/Models/Commons/
|
|
│ └─ Menu.php # Menu 모델
|
|
│
|
|
├─ app/Models/Scopes/
|
|
│ └─ TenantScope.php # 테넌트 격리 스코프
|
|
│
|
|
├─ app/Traits/
|
|
│ └─ BelongsToTenant.php # 테넌트 자동 격리 트레이트
|
|
│
|
|
├─ app/Services/
|
|
│ ├─ MenuService.php # 메뉴 CRUD 서비스
|
|
│ ├─ MenuBootstrapService.php # 메뉴 복사(부트스트랩) 서비스
|
|
│ └─ RegisterService.php # 회원가입 서비스 (메뉴 복사 호출)
|
|
│
|
|
├─ app/Http/Controllers/Api/V1/
|
|
│ └─ MenuController.php # 메뉴 API 컨트롤러
|
|
│
|
|
├─ app/Observers/
|
|
│ └─ MenuObserver.php # 메뉴 이벤트 옵저버 (권한 자동 생성)
|
|
│
|
|
└─ database/migrations/
|
|
├─ 2025_08_15_000000_create_authz_structures.php
|
|
├─ 2025_08_15_000200_drop_slug_from_menus_table.php
|
|
└─ 2025_11_12_160656_add_performance_indexes_to_menus_table.php
|
|
|
|
MNG 프로젝트: /Users/hskwon/Works/@KD_SAM/SAM/mng/
|
|
(구현 예정)
|
|
```
|
|
|
|
---
|
|
|
|
## 12. 메뉴 추가 SQL (참고)
|
|
|
|
PDF 문서에서 추출한 신규 메뉴 SQL은 별도 파일 참조:
|
|
- `claudedocs/MENU_INSERT_QUERIES.sql`
|
|
|
|
---
|
|
|
|
## 13. 다음 작업
|
|
|
|
1. Phase 1 시작: 마이그레이션 생성
|
|
2. Menu 모델 수정
|
|
3. MenuBootstrapService 수정
|
|
|
|
---
|
|
|
|
## 변경 이력
|
|
|
|
| 날짜 | 작성자 | 내용 |
|
|
|------|--------|------|
|
|
| 2025-12-01 | Claude | 초안 작성 | |