docs: 계획 문서 및 변경 기록 업데이트

- erp-api-development-plan.md: ERP API 개발 계획 업데이트
- react-fcm-push-notification-plan.md: FCM 푸시 알림 계획 완료
- react-mock-remaining-tasks.md: Mock 데이터 잔여 작업 정리
- l2-permission-management-plan.md: L2 권한 관리 계획 추가
- simulator-ui-enhancement-plan.md: 시뮬레이터 UI 개선 계획 추가
- 20251230 FCM 푸시 알림 변경 기록 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-30 17:26:20 +09:00
parent 7d639bb584
commit b1362ee9cb
6 changed files with 957 additions and 29 deletions

View File

@@ -0,0 +1,95 @@
# 변경 내용 요약
**날짜:** 2025-12-30 14:30
**작업자:** Claude Code
**관련 문서:** docs/plans/react-fcm-push-notification-plan.md
## 📋 변경 개요
React 프로젝트에 FCM 푸시 알림 기능 추가. Capacitor 네이티브 앱(iOS/Android)에서 dev.sam.kr 웹뷰 로드 시 푸시 알림을 지원합니다.
- 포팅 원본: `mng/public/js/fcm.js`
- 백엔드 API 변경 없음 (기존 `/push/*` 엔드포인트 재사용)
## 📁 수정된 파일
### 신규 생성 (4개)
| 파일 | 용량 | 용도 |
|------|------|------|
| `react/src/lib/capacitor/fcm.ts` | 9.1KB | FCM 핵심 로직 (토큰 관리, 알림 처리) |
| `react/src/hooks/useFCM.ts` | 3.3KB | React 훅 (sonner 토스트 연동) |
| `react/src/contexts/FCMProvider.tsx` | 1.8KB | 앱 전역 FCM 초기화 Provider |
| `react/public/sounds/*.wav` | 1.6MB | 알림 사운드 (mng에서 복사) |
### 수정 (2개)
| 파일 | 변경 내용 |
|------|----------|
| `react/src/app/[locale]/(protected)/layout.tsx` | FCMProvider 추가 |
| `react/src/lib/auth/logout.ts` | 로그아웃 시 FCM 토큰 해제 연동 |
### 의존성 추가 (3개)
| 패키지 | 버전 | 용도 |
|--------|------|------|
| @capacitor/core | ^8.0.0 | Capacitor 코어 |
| @capacitor/push-notifications | ^8.0.0 | 푸시 알림 플러그인 |
| @capacitor/app | ^8.0.0 | 앱 상태 감지 |
## 🔧 상세 변경 사항
### 1. FCM 유틸리티 (fcm.ts)
**주요 함수:**
- `initializeFCM()`: FCM 초기화 (권한 요청, 토큰 발급, 리스너 등록)
- `unregisterFCMToken()`: 토큰 해제 (로그아웃 시)
- `isCapacitorNative()`: 네이티브 환경 체크
**특징:**
- Next.js 프록시 패턴 사용 (`/api/proxy/v1/push/*`)
- HttpOnly 쿠키 자동 포함 (credentials: 'include')
- 포그라운드 알림 콜백 지원
### 2. useFCM 훅
**기능:**
- 로그인 상태에서 자동 FCM 초기화
- 포그라운드 알림 → sonner 토스트
- 알림 타입별 스타일 (error, warning, success, info)
### 3. FCMProvider
**위치:** `(protected)/layout.tsx`
- RootProvider 안에서 FCM 초기화
- 인증된 페이지에서만 동작
### 4. 로그아웃 연동
**logout.ts 변경:**
```typescript
// 4. FCM 토큰 해제 (Capacitor 네이티브 앱에서만 실행)
if (isCapacitorNative()) {
await unregisterFCMToken();
console.log('[Logout] FCM token unregistered');
}
```
## ✅ 테스트 체크리스트
- [ ] Capacitor 앱에서 dev.sam.kr 로드 확인
- [ ] 로그인 후 FCM 토큰 등록 확인 (콘솔 로그)
- [ ] 포그라운드 알림 수신 → sonner 토스트 표시
- [ ] 알림 사운드 재생 확인
- [ ] 알림 클릭 → URL 이동 확인
- [ ] 로그아웃 → FCM 토큰 해제 확인
- [ ] 웹 브라우저에서는 FCM 로직 스킵 확인
## ⚠️ 배포 시 주의사항
1. **iOS**: Xcode에서 Push Notification Capability 활성화 필요
2. **Android**: google-services.json 설정 확인
3. **프록시**: `/api/proxy/v1/push/*` 라우트 존재 확인
## 🔗 관련 문서
- [FCM 연동 계획](../plans/react-fcm-push-notification-plan.md)
- [Capacitor Push Notifications](https://capacitorjs.com/docs/apis/push-notifications)
- [mng/public/js/fcm.js](../../mng/public/js/fcm.js) (포팅 원본)

View File

@@ -2,7 +2,7 @@
> **작성일**: 2025-12-17
> **기준 문서**: SAM_ERP_Storyboard_D0.8_251216
> **상태**: ✅ Phase 1 완료 | ✅ Phase 2 완료 | 🟡 Phase 3 진행중 (3/4: AI리포트 + 가지급금 + 바로빌)
> **상태**: ✅ Phase 1 완료 | ✅ Phase 2 완료 | Phase 3 완료 | ✅ Phase L 완료 (직급/직책) | 🟡 L-2 권한관리 React 연동 대기
---
@@ -478,6 +478,80 @@
---
## ⚙️ Phase L: 설정 및 기준정보 (2025-12-30)
> 참조: [`docs/plans/react-mock-remaining-tasks.md`](./react-mock-remaining-tasks.md) - Phase L 섹션
### L-2 권한관리 🟡
> 참조: [`docs/plans/l2-permission-management-plan.md`](./l2-permission-management-plan.md)
> **상태**: API 개발 완료, React 연동 대기
- [x] **테이블 수정**
- [x] `roles` 테이블에 `is_hidden` 컬럼 추가 마이그레이션
- [x] **API 엔드포인트** (9개)
- [x] `GET /v1/roles` - 역할 목록
- [x] `POST /v1/roles` - 역할 생성
- [x] `GET /v1/roles/{id}` - 역할 상세
- [x] `PATCH /v1/roles/{id}` - 역할 수정
- [x] `DELETE /v1/roles/{id}` - 역할 삭제
- [x] `GET /v1/roles/{id}/permissions` - 역할 권한 조회
- [x] `POST /v1/roles/{id}/permissions` - 권한 추가
- [x] `DELETE /v1/roles/{id}/permissions` - 권한 제거
- [x] `PUT /v1/roles/{id}/permissions/sync` - 권한 동기화
- [x] **Swagger 문서**
- [x] `RoleApi.php` 작성
- [x] `RolePermissionApi.php` 작성
- [ ] **React 연동**
- [ ] actions.ts 생성
- [ ] 컴포넌트 API 연동
- [ ] Mock 데이터 제거
---
### L-3 직급관리 ✅ + L-4 직책관리 ✅
> **완료일**: 2025-12-30
> **설계**: 직급(rank)과 직책(title)을 통합 `positions` 테이블로 구현
- [x] **테이블 생성**
- [x] `positions` 마이그레이션 (type 컬럼으로 rank/title 구분)
- [x] `common_codes`에 position_type 그룹 추가
- [x] **모델 생성**
- [x] `Position` 모델 (BelongsToTenant, SoftDeletes)
- [x] **서비스 구현**
- [x] `PositionService` 생성 (CRUD, reorder)
- [x] **API 엔드포인트** (6개)
- [x] `GET /v1/positions?type=rank` - 직급 목록
- [x] `GET /v1/positions?type=title` - 직책 목록
- [x] `POST /v1/positions` - 생성 (type 필수)
- [x] `PUT /v1/positions/{id}` - 수정
- [x] `DELETE /v1/positions/{id}` - 삭제
- [x] `POST /v1/positions/reorder` - 순서 변경 (bulk)
- [x] **Swagger 문서**
- [x] `PositionApi.php` 작성
- [x] **React 연동**
- [x] `lib/api/positions.ts` API 클라이언트
- [x] `RankManagement/` 컴포넌트 API 연동
- [x] `TitleManagement/` 컴포넌트 API 연동
- [x] 드래그 앤 드롭 순서 저장
---
### L-5 출퇴근설정 🟡
> **상태**: 부분 완료 - 부서 목록 API 연동 필요
- [x] 출퇴근 설정 API 연동 완료
- [ ] `MOCK_DEPARTMENTS``getDepartments()` API 연동 필요
---
## 💼 Phase 4: SaaS 기능 (별도 일정)
> ⚠️ **기존 코드베이스 분석 결과 반영** (2025-12-18)
@@ -685,6 +759,15 @@
- 고객센터: mng 게시판 기능(`Board`, `Post`, `BoardService`)으로 대체 가능
- 계획 문서 수정: 신규 개발 → 기존 모델 확장으로 변경
### 2025-12-30
- [x] **Phase L 설정 및 기준정보 개발**
- L-2 권한관리 API 개발 완료 (React 연동 대기)
- L-3 직급관리 + L-4 직책관리 완료 (통합 positions 테이블)
- 마이그레이션 2개, 모델 1개, 서비스 2개, 컨트롤러 2개
- API 엔드포인트 15개 (Role 9개 + Position 6개)
- Swagger 문서 3개 (RoleApi, RolePermissionApi, PositionApi)
- React API 클라이언트 및 컴포넌트 연동 (직급/직책)
### YYYY-MM-DD
- [ ] (작업 내용 기록)

View File

@@ -0,0 +1,378 @@
# L-2 권한관리 Mock → API 연동 계획
> **작성일**: 2025-12-30
> **목적**: React 권한관리 페이지의 Mock 데이터를 API 연동으로 전환
> **기준 문서**: mng.sam.kr/role-permissions
> **상태**: ✅ 완료 - Phase 1~4 전체 완료
---
## 📍 현재 진행 상태
| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | Phase 4 React 연동 완료 |
| **다음 작업** | 완료 (테스트 후 운영 배포) |
| **진행률** | 12/12 (100%) |
| **마지막 업데이트** | 2025-12-30
---
## 1. 개요
### 1.1 배경
현재 React의 권한관리 페이지(`/settings/permissions`)는 `localStorage``defaultPermissions` Mock 데이터를 사용하고 있습니다. mng 프로젝트에는 이미 완전한 역할-권한 관리 시스템이 구현되어 있으므로, api 프로젝트에 동일한 API를 개발하고 React에서 연동해야 합니다.
**문제점:**
- React는 `localStorage`에 권한 데이터 저장 (새로고침/브라우저 변경 시 데이터 손실)
- 실제 DB 연동 없음
- 역할 숨김(is_hidden) 기능이 DB 스키마에 없음
### 1.2 기준 원칙
```
┌─────────────────────────────────────────────────────────────────┐
│ 🎯 핵심 원칙 │
├─────────────────────────────────────────────────────────────────┤
│ 1. React → api.sam.kr만 호출 (mng 직접 호출 금지) │
│ 2. mng의 RoleService/RolePermissionService 로직 참조하여 api에 재구현 │
│ 3. Spatie Permission 패키지 활용 (기존 테이블 구조 유지) │
│ 4. Multi-tenant 지원 필수 (BelongsToTenant) │
└─────────────────────────────────────────────────────────────────┘
```
### 1.3 변경 승인 정책
| 분류 | 예시 | 승인 |
|------|------|------|
| ✅ 즉시 가능 | API 엔드포인트 추가, 타입 정의, 문서 수정 | 불필요 |
| ⚠️ 컨펌 필요 | DB 마이그레이션 (is_hidden 컬럼), 기존 API 수정 | **필수** |
| 🔴 금지 | roles 테이블 구조 대폭 변경, 기존 권한 삭제 | 별도 협의 |
### 1.4 준수 규칙
- `docs/quickstart/quick-start.md` - 빠른 시작 가이드
- `docs/standards/api-rules.md` - API 개발 규칙
- `docs/standards/quality-checklist.md` - 품질 체크리스트
- `docs/specs/database-schema.md` - DB 스키마
---
## 2. 현재 상태 분석
### 2.1 mng 프로젝트 (기준)
| 파일 | 역할 | 주요 기능 |
|------|------|----------|
| `RoleController.php` | 역할 CRUD 화면 | index, create, edit |
| `RoleService.php` | 역할 비즈니스 로직 | getRoles, createRole, updateRole, deleteRole |
| `RolePermissionController.php` | 권한 매트릭스 화면 | index (테넌트별 역할 목록) |
| `RolePermissionService.php` | 권한 매트릭스 로직 | togglePermission, allowAll, denyAll, getMenuTree |
| `Role.php` (Model) | 역할 모델 | tenant, permissions, users 관계 |
**mng의 역할 필드:**
```php
$fillable = ['tenant_id', 'name', 'description', 'guard_name'];
```
**⚠️ 숨김 기능 없음**: mng에도 `is_hidden` 필드가 없음
### 2.2 React 프로젝트 (현재)
| 파일 | 현재 상태 | 문제점 |
|------|----------|--------|
| `index.tsx` | `localStorage` + `defaultPermissions` | 실제 DB 연동 없음 |
| `types.ts` | `Permission` 타입 정의 | `status: 'active' | 'hidden'` 있음 |
| `PermissionDetail.tsx` | 메뉴별 권한 설정 | Mock 데이터 사용 |
**React의 Permission 타입:**
```typescript
interface Permission {
id: number;
name: string;
status: 'active' | 'hidden'; // ← DB에 없음!
menuPermissions: MenuPermission[];
createdAt: string;
}
```
### 2.3 api 프로젝트 (현재)
- **Role 관련 API 없음** (개발 필요)
- `shared/Models/Role.php` 존재 여부 확인 필요
### 2.4 DB 스키마 (roles 테이블)
```sql
roles (11 컬럼):
- id (PK)
- tenant_id (FK tenants.id)
- name
- guard_name (default: 'web')
- description
- created_by, updated_by, deleted_by
- created_at, updated_at, deleted_at
-- ⚠️ is_hidden 컬럼 없음! 추가 필요
```
---
## 3. 대상 범위
### 3.1 Phase 1: DB 스키마 수정
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1.1 | roles 테이블에 `is_hidden` 컬럼 추가 | ✅ | `2025_12_30_160802_add_is_hidden_to_roles_table.php` 생성완료, 실행대기 |
| 1.2 | 기존 역할 데이터 기본값 설정 (is_hidden = false) | ✅ | 마이그레이션에 포함 |
### 3.2 Phase 2: api 프로젝트 - Role CRUD API
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 2.1 | Role 모델 생성/수정 | ✅ | shared/Models/Role.php |
| 2.2 | RoleService 생성 | ✅ | `api/app/Services/RoleService.php` |
| 2.3 | RoleController 생성 | ✅ | `api/app/Http/Controllers/Api/V1/RoleController.php` |
| 2.4 | RoleFormRequest 생성 | ⏳ | StoreRoleRequest, UpdateRoleRequest 미생성 |
| 2.5 | routes/api.php 라우트 추가 | ✅ | 5개 CRUD 라우트 등록완료 |
| 2.6 | Swagger 문서 작성 | ✅ | `api/app/Swagger/v1/RoleApi.php` |
### 3.3 Phase 3: api 프로젝트 - 권한 매트릭스 API
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 3.1 | RolePermissionController 생성 | ✅ | `api/app/Http/Controllers/Api/V1/RolePermissionController.php` |
| 3.2 | 권한 목록 조회 API | ✅ | GET /roles/{id}/permissions |
| 3.3 | 권한 부여 API | ✅ | POST /roles/{id}/permissions |
| 3.4 | 권한 회수/동기화 API | ✅ | DELETE, PUT /roles/{id}/permissions/sync |
| 3.5 | Swagger 문서 작성 | ✅ | `api/app/Swagger/v1/RolePermissionApi.php` |
### 3.4 Phase 4: React 연동 ✅
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 4.1 | actions.ts 생성 | ✅ | 12개 Server Actions (fetchRoles, createRole, updateRole, deleteRole 등) |
| 4.2 | types.ts 수정 | ✅ | ApiResponse, Role, RoleStats, MenuTreeItem, PermissionMatrix 타입 추가 |
| 4.3 | index.tsx 수정 (목록) | ✅ | localStorage → API 연동, 로딩/에러 상태, toast 알림 |
| 4.4 | PermissionDetailClient.tsx 수정 (상세/권한매트릭스) | ✅ | 역할 CRUD, 권한 토글, 전체 허용/거부/초기화 |
| 4.5 | Mock 데이터 제거 | ✅ | defaultPermissions 삭제, API 기반으로 전환 |
---
## 4. API 설계
### 4.1 Role CRUD API
| Method | Endpoint | 설명 | Request | Response |
|--------|----------|------|---------|----------|
| GET | `/api/v1/roles` | 역할 목록 | `?search=&is_hidden=` | `{ data: Role[], meta: Pagination }` |
| GET | `/api/v1/roles/{id}` | 역할 상세 | - | `{ data: Role }` |
| POST | `/api/v1/roles` | 역할 생성 | `{ name, description, is_hidden }` | `{ data: Role }` |
| PUT | `/api/v1/roles/{id}` | 역할 수정 | `{ name, description, is_hidden }` | `{ data: Role }` |
| DELETE | `/api/v1/roles/{id}` | 역할 삭제 | - | `{ message }` |
### 4.2 권한 매트릭스 API
| Method | Endpoint | 설명 | Request | Response |
|--------|----------|------|---------|----------|
| GET | `/api/v1/roles/{id}/menus` | 메뉴 트리 + 권한 상태 | - | `{ data: MenuWithPermissions[] }` |
| POST | `/api/v1/roles/{id}/permissions/toggle` | 권한 토글 | `{ menu_id, permission_type }` | `{ data: { value: boolean } }` |
| POST | `/api/v1/roles/{id}/permissions/allow-all` | 전체 허용 | - | `{ message }` |
| POST | `/api/v1/roles/{id}/permissions/deny-all` | 전체 거부 | - | `{ message }` |
| POST | `/api/v1/roles/{id}/permissions/reset` | 기본값 초기화 | - | `{ message }` |
### 4.3 Role 응답 타입
```typescript
interface Role {
id: number;
tenant_id: number;
name: string;
description: string | null;
guard_name: string;
is_hidden: boolean; // ← 신규 필드
permissions_count: number; // ← 권한 개수
users_count: number; // ← 사용자 수
created_at: string;
updated_at: string;
}
interface MenuWithPermissions {
id: number;
name: string;
parent_id: number | null;
depth: number;
has_children: boolean;
permissions: {
view: boolean;
create: boolean;
update: boolean;
delete: boolean;
approve: boolean;
export: boolean;
manage: boolean;
};
}
```
---
## 5. 상세 작업 내용
### 5.1 Phase 1: DB 스키마 수정 ✅
#### 1.1 roles 테이블에 is_hidden 컬럼 추가
- **상태**: ✅ 파일 생성완료 (실행 대기)
- **마이그레이션 파일**: `2025_12_30_160802_add_is_hidden_to_roles_table.php`
- **컬럼 정의**: `boolean is_hidden default false after description`
- **영향**: api, mng 모두 적용
### 5.2 Phase 2: Role CRUD API ✅
#### 생성된 파일
| 파일 | 경로 |
|------|------|
| RoleController | `api/app/Http/Controllers/Api/V1/RoleController.php` |
| RoleService | `api/app/Services/RoleService.php` |
| RoleApi Swagger | `api/app/Swagger/v1/RoleApi.php` |
#### 등록된 라우트 (5개)
```
GET /api/v1/roles → index
POST /api/v1/roles → store
GET /api/v1/roles/{id} → show
PATCH /api/v1/roles/{id} → update
DELETE /api/v1/roles/{id} → destroy
```
### 5.3 Phase 3: 권한 매트릭스 API ✅
#### 생성된 파일
| 파일 | 경로 |
|------|------|
| RolePermissionController | `api/app/Http/Controllers/Api/V1/RolePermissionController.php` |
| RolePermissionApi Swagger | `api/app/Swagger/v1/RolePermissionApi.php` |
#### 등록된 라우트 (4개)
```
GET /api/v1/roles/{id}/permissions → index
POST /api/v1/roles/{id}/permissions → grant
DELETE /api/v1/roles/{id}/permissions → revoke
PUT /api/v1/roles/{id}/permissions/sync → sync
```
---
## 6. 컨펌 대기 목록
> API 내부 로직 변경 등 승인 필요 항목
| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|---|------|----------|----------|------|
| 1 | is_hidden 컬럼 추가 | roles 테이블 마이그레이션 | api, mng | ⏳ 대기 |
---
## 7. 파일 구조 (예상)
### 7.1 api 프로젝트
```
api/app/
├── Http/
│ ├── Controllers/
│ │ └── RoleController.php ← 🆕 생성
│ └── Requests/
│ ├── StoreRoleRequest.php ← 🆕 생성
│ └── UpdateRoleRequest.php ← 🆕 생성
├── Models/
│ └── Role.php ← 🔄 수정 (is_hidden 추가)
└── Services/
├── RoleService.php ← 🆕 생성
└── RolePermissionService.php ← 🆕 생성
api/database/migrations/
└── xxxx_add_is_hidden_to_roles_table.php ← 🆕 생성
api/routes/
└── api.php ← 🔄 수정 (라우트 추가)
```
### 7.2 React 프로젝트
```
react/src/components/settings/PermissionManagement/
├── index.tsx ← 🔄 수정 (API 연동)
├── types.ts ← 🔄 수정 (타입 매핑)
├── actions.ts ← 🆕 생성
├── PermissionDetail.tsx ← 🔄 수정 (API 연동)
├── PermissionDetailClient.tsx ← 🔄 수정
└── PermissionDialog.tsx ← 🔄 수정
```
---
## 8. 변경 이력
| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|------|------|----------|------|------|
| 2025-12-30 | Phase 1~3 | API 개발 완료 (마이그레이션, Controller, Service, Swagger, 라우트) | 다수 | ✅ |
| 2025-12-30 | Phase 4 | React 연동 완료 (actions.ts, types.ts, index.tsx, PermissionDetailClient.tsx) | react 4개 파일 | ✅ |
| 2025-12-30 | 문서 | 계획 문서 초안 작성 | - | - |
| 2025-12-30 | 문서 | Phase 4 완료 반영 업데이트 | - | - |
---
## 9. 참고 문서
- **빠른 시작**: `docs/quickstart/quick-start.md`
- **API 규칙**: `docs/standards/api-rules.md`
- **품질 체크리스트**: `docs/standards/quality-checklist.md`
- **DB 스키마**: `docs/specs/database-schema.md`
- **mng 권한관리**: `mng/app/Services/RoleService.php`, `RolePermissionService.php`
---
## 10. 세션 및 메모리 관리 정책 (Serena Optimized)
### 10.1 세션 시작 시 (Load Strategy)
```javascript
read_memory("l2-permission-state") // 1. 상태 파악
read_memory("l2-permission-snapshot") // 2. 사고 흐름 복구
```
### 10.2 Serena 메모리 구조
- `l2-permission-state`: { phase, progress, next_step, last_decision }
- `l2-permission-snapshot`: 현재까지의 논의 및 코드 변경점 요약
---
## 11. 검증 결과
> 작업 완료 후 이 섹션에 검증 결과 추가
### 11.1 테스트 케이스
| 입력값 | 예상 결과 | 실제 결과 | 상태 |
|--------|----------|----------|------|
| GET /api/v1/roles | 역할 목록 반환 | | ⏳ |
| POST /api/v1/roles | 역할 생성 | | ⏳ |
| PUT /api/v1/roles/{id} | 역할 수정 | | ⏳ |
| DELETE /api/v1/roles/{id} | 역할 삭제 | | ⏳ |
| GET /api/v1/roles/{id}/menus | 메뉴+권한 매트릭스 | | ⏳ |
| POST /api/v1/roles/{id}/permissions/toggle | 권한 토글 | | ⏳ |
### 11.2 성공 기준 달성 현황
| 기준 | 달성 | 비고 |
|------|------|------|
| localStorage 제거 | ⏳ | |
| 역할 CRUD API 동작 | ⏳ | |
| 권한 매트릭스 API 동작 | ⏳ | |
| 숨김 기능 동작 | ⏳ | |
---
*이 문서는 /sc:plan 스킬로 생성되었습니다.*

View File

@@ -3,7 +3,7 @@
> **작성일**: 2025-12-30
> **목적**: Capacitor 앱 웹뷰가 dev.sam.kr (Next.js)을 로드할 때 FCM 푸시 알림 지원
> **기준 문서**: mng/public/js/fcm.js (포팅 대상), api/app/Swagger/v1/PushApi.php
> **상태**: 📋 계획 수립 (Serena ID: react-fcm-state)
> **상태**: ✅ 구현 완료 (Serena ID: react-fcm-state)
---
@@ -11,9 +11,9 @@
| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | 분석 완료 |
| **다음 작업** | Phase 1: Capacitor 플러그인 설치 |
| **진행률** | 0/4 (0%) |
| **마지막 완료 작업** | Phase 4: 통합 완료 |
| **다음 작업** | 테스트 (Capacitor 앱에서 확인) |
| **진행률** | 4/4 (100%) |
| **마지막 업데이트** | 2025-12-30 |
---
@@ -83,38 +83,38 @@ Capacitor 앱 (웹뷰)
## 2. 대상 범위
### 2.1 Phase 1: Capacitor 플러그인 설치
### 2.1 Phase 1: Capacitor 플러그인 설치
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1.1 | @capacitor/push-notifications 설치 | | npm install |
| 1.2 | @capacitor/app 설치 | | 앱 상태 감지용 |
| 1.3 | capacitor.config.ts 확인/수정 | | 플러그인 설정 |
| 1.1 | @capacitor/push-notifications 설치 | | ^8.0.0 |
| 1.2 | @capacitor/app 설치 | | ^8.0.0 |
| 1.3 | @capacitor/core 설치 | | ^8.0.0 |
### 2.2 Phase 2: FCM 유틸리티 포팅
### 2.2 Phase 2: FCM 유틸리티 포팅
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 2.1 | lib/capacitor/fcm.ts 생성 | | 핵심 FCM 로직 |
| 2.2 | useFCM 훅 생성 | | React 훅 래퍼 |
| 2.3 | FCM Provider 생성 | | 앱 전역 초기화 |
| 2.1 | lib/capacitor/fcm.ts 생성 | | 9.1KB |
| 2.2 | useFCM 훅 생성 | | 3.3KB |
| 2.3 | FCM Provider 생성 | | contexts/FCMProvider.tsx |
### 2.3 Phase 3: 포그라운드 알림 UI
### 2.3 Phase 3: 포그라운드 알림 UI
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 3.1 | sonner 토스트 연동 | | 포그라운드 알림 표시 |
| 3.2 | 알림 사운드 재생 | | /sounds/*.wav |
| 3.3 | 클릭 시 URL 이동 | | router.push 사용 |
| 3.1 | sonner 토스트 연동 | | useFCM에서 처리 |
| 3.2 | 알림 사운드 재생 | | public/sounds/ |
| 3.3 | 클릭 시 URL 이동 | | window.location.href |
### 2.4 Phase 4: 통합 테스트
### 2.4 Phase 4: 통합
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 4.1 | 토큰 등록 테스트 | | API 호출 확인 |
| 4.2 | 포그라운드 알림 테스트 | | 토스트 + 사운드 |
| 4.3 | 백그라운드 알림 테스트 | ⏳ | 시스템 알림 |
| 4.4 | 알림 클릭 테스트 | ⏳ | URL 이동 |
| 4.1 | layout.tsx에 FCMProvider 추가 | | (protected)/layout.tsx |
| 4.2 | 로그아웃 시 토큰 해제 | | logout.ts 수정 |
| 4.3 | 토큰 등록 테스트 | ⏳ | Capacitor 앱에서 확인 필요 |
| 4.4 | 포그라운드/백그라운드 알림 테스트 | ⏳ | Capacitor 앱에서 확인 필요 |
---

View File

@@ -456,17 +456,155 @@ const formData = {
---
## 3. 잔여 Mock 파일 (삭제 대상)
### 2.3 Phase L: 설정 및 시스템 관리
> **참고**: 일부 mockData.ts는 유틸리티 함수(색상매핑, 판정함수)만 유지
> **상태**: 🔄 분석 완료 - 일부 API 연동 필요
#### 📋 React 연동 작업 현황
| # | 페이지 | React 경로 | Mock 데이터 | API 연동 | 상태 | 작업 계획 |
|---|--------|-----------|------------|---------|------|----------|
| L-1 | 계정관리 | `/settings/accounts` | ❌ | ✅ CRUD | ✅ 완료 | 데이터 확인 |
| L-2 | 권한관리 | `/settings/permissions` | ✅ defaultPermissions + localStorage | ❌ | 🔴 미연동 | API 개발 필요 |
| L-3 | 직급관리 | `/settings/ranks` | ❌ | ✅ positions API (type=rank) | ✅ 완료 | 통합 positions 테이블 |
| L-4 | 직책관리 | `/settings/titles` | ❌ | ✅ positions API (type=title) | ✅ 완료 | 통합 positions 테이블 |
| L-5 | 출퇴근설정 | `/settings/attendance-settings` | ✅ MOCK_DEPARTMENTS | 🔄 부분 | 🟡 부분완료 | 부서 API 연동 필요 |
| L-6 | 휴가정책 | `/settings/leave-policy` | ❌ | ✅ GET/PUT | ✅ 완료 | 데이터 확인 |
| L-7 | 근무일정 | `/settings/work-schedule` | ❌ | ✅ GET/PUT | ✅ 완료 | 데이터 확인 |
| L-8 | 알림설정 | `/settings/notification-settings` | ❌ (fallback만) | ✅ GET/PUT | ✅ 완료 | 데이터 확인 |
| L-9 | 팝업관리 | `/settings/popup-management` | ⚠️ MOCK_POPUPS (미사용) | ✅ CRUD | ✅ 완료 | Mock 제거 |
| L-10 | 회사정보 | `/company-info` | ❌ | ✅ GET/PUT | ✅ 완료 | 데이터 확인 |
| L-11 | 구독관리 | `/subscription` | ❌ | ✅ 조회/취소 | ✅ 완료 | 데이터 확인 |
#### 🛠️ 작업 계획 상세
**🔴 API 개발 필요 (1개)**
| 페이지 | 필요한 API | 모델/테이블 | 우선순위 |
|--------|-----------|------------|---------|
| L-2 권한관리 | `/api/v1/roles` CRUD | roles, role_permissions | 높음 |
**✅ API 개발 완료 (2개) - 2025-12-30**
| 페이지 | API | 모델/테이블 | 비고 |
|--------|-----|------------|------|
| L-3 직급관리 | `/api/v1/positions?type=rank` | positions | 통합 테이블 |
| L-4 직책관리 | `/api/v1/positions?type=title` | positions | 통합 테이블 |
**🟡 부분 연동 필요 (1개)**
| 페이지 | 현재 상태 | 필요 작업 |
|--------|----------|----------|
| L-5 출퇴근설정 | 설정 API 연동 완료 | 부서 목록 `getDepartments()` API 연동 필요 (MOCK_DEPARTMENTS 제거) |
**⚠️ Mock 제거 필요 (1개)**
| 파일 | 현재 상태 | 작업 |
|------|----------|------|
| `PopupManagement/types.ts` | MOCK_POPUPS 정의됨 (실제 미사용) | 불필요한 Mock 코드 제거 |
#### 📊 API 연동 완료 페이지 상세
| # | 페이지 | actions.ts 함수 | API Endpoint |
|---|--------|----------------|--------------|
| L-1 | 계정관리 | getBankAccounts, createBankAccount, updateBankAccount, deleteBankAccount | `/api/v1/bank-accounts` |
| L-6 | 휴가정책 | getLeavePolicy, updateLeavePolicy | `/api/v1/leave-policy` |
| L-7 | 근무일정 | getWorkSetting, updateWorkSetting | `/api/v1/settings/work` |
| L-8 | 알림설정 | getNotificationSettings, saveNotificationSettings | `/api/v1/settings/notifications` |
| L-9 | 팝업관리 | getPopups, getPopupById, createPopup, updatePopup, deletePopup | `/api/v1/popups` |
| L-10 | 회사정보 | getCompanyInfo, updateCompanyInfo | `/api/v1/tenants` |
| L-11 | 구독관리 | getSubscriptionData, cancelSubscription, requestDataExport | `/api/v1/subscriptions/*` |
#### 🗂️ 파일 구조
```
components/settings/
├── AccountManagement/
│ ├── index.tsx ← ✅ API 연동 완료
│ ├── actions.ts ← ✅ bank-accounts CRUD
│ ├── AccountDetail.tsx ← ✅ 상세/수정 API 연동
│ └── types.ts
├── PermissionManagement/
│ ├── index.tsx ← ❌ localStorage + defaultPermissions
│ ├── PermissionDetail.tsx
│ └── types.ts ← ❌ actions.ts 없음
├── RankManagement/
│ ├── index.tsx ← ✅ API 연동 완료 (positions API type=rank)
│ ├── RankDialog.tsx ← ✅ 수정 완료
│ └── types.ts ← ✅ 타입 정의 완료
├── TitleManagement/
│ ├── index.tsx ← ✅ API 연동 완료 (positions API type=title)
│ ├── TitleDialog.tsx ← ✅ 수정 완료
│ └── types.ts ← ✅ 타입 정의 완료
├── AttendanceSettingsManagement/
│ ├── index.tsx ← 🔄 부분 연동 (MOCK_DEPARTMENTS 사용)
│ ├── actions.ts ← ✅ 설정 API 연동
│ └── types.ts ← ✅ MOCK_DEPARTMENTS 정의
├── LeavePolicyManagement/
│ ├── index.tsx ← ✅ API 연동 완료
│ ├── actions.ts ← ✅ leave-policy GET/PUT
│ └── types.ts
├── WorkScheduleManagement/
│ ├── index.tsx ← ✅ API 연동 완료
│ ├── actions.ts ← ✅ settings/work GET/PUT
│ └── types.ts
├── NotificationSettings/
│ ├── index.tsx ← ✅ API 연동 완료
│ ├── actions.ts ← ✅ settings/notifications GET/PUT
│ └── types.ts
├── PopupManagement/
│ ├── index.tsx ← ✅ API 연동 완료
│ ├── PopupList.tsx ← ✅ 목록 API 연동
│ ├── PopupForm.tsx ← ✅ 등록/수정 API 연동
│ ├── actions.ts ← ✅ popups CRUD
│ └── types.ts ← ⚠️ MOCK_POPUPS (미사용, 제거 대상)
├── CompanyInfoManagement/
│ ├── index.tsx ← ✅ API 연동 완료
│ ├── actions.ts ← ✅ tenants GET/PUT
│ └── types.ts
└── SubscriptionManagement/
├── SubscriptionManagement.tsx ← ✅ API 연동 완료
├── actions.ts ← ✅ subscriptions API
└── types.ts
```
---
## 3. 잔여 Mock 파일 (정리 완료)
> **2025-12-29 정리 완료**: 모든 미사용 Mock 파일 삭제, 유틸리티만 유지
### 3.1 Production/Quality Mock 파일 (✅ 정리 완료)
**삭제된 파일 (4개):**
```
react/src/components/
├── production/ProductionDashboard/mockData.ts ← G-3 (유틸리티만 유지)
├── production/WorkOrders/mockData.ts ← G-1 (유틸리티만 유지)
├── production/WorkResults/mockData.ts ← G-2 (유틸리티만 유지)
── quality/InspectionManagement/mockData.ts ← G-5 (확인 필요)
└── reports/mockData.ts ← 확인 필요
├── production/ProductionDashboard/mockData.ts ← ✅ 삭제 (미사용)
├── production/WorkOrders/mockData.ts ← ✅ 삭제 (미사용)
├── production/WorkResults/mockData.ts ← ✅ 삭제 (미사용)
── reports/mockData.ts ← ✅ 삭제 (formatAmount 중복)
```
**유틸리티만 유지 (1개):**
```
react/src/components/
└── quality/InspectionManagement/mockData.ts ← ✅ 유틸리티만 유지
- inspectionItemsTemplate, inspectionTypeLabels
- statusColorMap, judgmentColorMap
- judgeMeasurement()
```
### 3.2 Settings Mock 데이터 (Phase L)
```
react/src/components/settings/
├── PermissionManagement/index.tsx ← defaultPermissions (하드코딩, 삭제 대상)
├── RankManagement/index.tsx ← defaultRanks (하드코딩, 삭제 대상)
├── TitleManagement/index.tsx ← defaultTitles (하드코딩, 삭제 대상)
├── AttendanceSettingsManagement/
│ └── types.ts ← MOCK_DEPARTMENTS (API 연동 필요)
└── PopupManagement/
└── types.ts ← MOCK_POPUPS (미사용, 제거 대상)
```
---
@@ -484,6 +622,8 @@ react/src/components/
| 날짜 | 작업 | 상세 내용 |
|------|------|----------|
| 2025-12-29 | 잔여 Mock 파일 정리 완료 | 미사용 Mock 파일 4개 삭제 (ProductionDashboard, WorkOrders, WorkResults, reports). InspectionManagement/mockData.ts 유틸리티만 유지 (inspectionItemsTemplate, statusColorMap, judgmentColorMap, judgeMeasurement). 304→68줄 감소 |
| 2025-12-29 | Phase L 설정 페이지 분석 완료 | 11개 설정 페이지 분석: 7개 API 연동 완료 (계정관리, 휴가정책, 근무일정, 알림설정, 팝업관리, 회사정보, 구독관리), 3개 API 개발 필요 (권한/직급/직책), 1개 부분 연동 필요 (출퇴근설정-부서). Mock 데이터: MOCK_DEPARTMENTS, MOCK_POPUPS, defaultPermissions/Ranks/Titles |
| 2025-12-29 | 검사 테이블 통합 및 출하 대시보드 수정 | **검사 시스템 통합**: 레거시 검사 모델 삭제 (MaterialInspection, MaterialInspectionItem, MaterialReceipt) → 통합 검사 모델 추가 (Inspection.php - IQC/PQC/FQC), 품목 입고 모델 추가 (ItemReceipt.php). **출하 대시보드**: ShipmentService stats() 프론트엔드 호환 필드 추가 (today_shipment_count, scheduled_count, shipping_count, urgent_count). 더미 데이터 tenant_id = 287로 수정 |
| 2025-12-29 | api 프로젝트 게시판 메뉴 자동 연동 | 테넌트 게시판 생성/수정/삭제 시 메뉴 자동 연동. `MenuService::createMenuForBoard()`, `updateMenuForBoard()`, `deleteMenuForBoard()` 추가. `BoardService`에서 호출. 부모 메뉴 `/board` 하위 배치 |
| 2025-12-29 | K-4 문의 댓글 API 연동 완료 | 댓글 CRUD API 연동 (getComments, createComment, updateComment, deleteComment). BoardComment 모델 replies() 추가, PostService user eager loading 추가, user.id localStorage 저장으로 본인 글 수정/삭제 버튼 표시 |

View File

@@ -0,0 +1,232 @@
# MNG 시뮬레이터 UI 개선 계획
> **작성일**: 2025-12-30
> **목적**: MNG 시뮬레이터를 Design 자동 견적 산출과 동일하게 개선
> **기준 문서**: `design/src/components/QuoteAutoCalculation.tsx`
> **상태**: 🔄 진행중 (Serena ID: simulator-ui-state)
---
## 📍 현재 진행 상태
| 항목 | 내용 |
|------|------|
| **마지막 완료 작업** | Phase 1 UI 레이아웃 수정 (단일행) |
| **다음 작업** | Phase 2 제품 드롭다운 데이터 로드 수정 |
| **진행률** | 6/10 (60%) |
| **마지막 업데이트** | 2025-12-30 19:00 |
### 🚨 현재 이슈
| 이슈 | 설명 | 상태 |
|------|------|------|
| 제품 드롭다운 비어있음 | FG 제품이 로드되지 않음 | ⏳ 조사 필요 |
---
## 1. 개요
### 1.1 배경
Design 자동 견적 산출(`localhost:3002` > 판매관리 > 견적관리 > 견적등록 > 자동 견적 산출)과
MNG 시뮬레이터(`mng.sam.kr/quote-formulas/simulator`)가 동일한 결과를 도출해야 함.
**현재 차이점:**
- Design: 프론트엔드에서 자체 계산 (`eval()`)
- MNG: 백엔드 API에서 계산 (`FormulaEvaluatorService`)
**목표:**
MNG 시뮬레이터 UI를 Design과 동일하게 맞추고, 동일한 입력에 동일한 결과가 나오도록 개선.
### 1.2 기준 원칙
```
┌─────────────────────────────────────────────────────────────────┐
│ 🎯 핵심 원칙 │
├─────────────────────────────────────────────────────────────────┤
│ 1. Design QuoteAutoCalculation UI를 MNG Blade로 구현 │
│ 2. 동일 입력 → 동일 결과 (Design과 MNG) │
│ 3. DB 데이터 기반 동적 제품 로드 │
│ 4. 기존 FormulaEvaluatorService 계산 로직 활용 │
└─────────────────────────────────────────────────────────────────┘
```
### 1.3 변경 승인 정책
| 분류 | 예시 | 승인 |
|------|------|------|
| ✅ 즉시 가능 | UI 필드 추가, 드롭다운 옵션, CSS 스타일 | 불필요 |
| ⚠️ 컨펌 필요 | 백엔드 API 변경, 계산 로직 수정 | **필수** |
| 🔴 금지 | DB 스키마 변경, 기존 API 삭제 | 별도 협의 |
---
## 2. Design vs MNG 비교 분석
### 2.1 입력 필드 비교
| 필드 | Design 변수명 | Design | MNG 현재 | MNG 목표 |
|------|--------------|:------:|:--------:|:--------:|
| 제품 선택 | selectedProductId | ✅ | ✅ | ✅ |
| 폭 | width | ✅ | ✅ (W0) | ✅ |
| 높이 | height | ✅ | ✅ (H0) | ✅ |
| 수량 | quantity | ✅ | ✅ (QTY) | ✅ |
### 2.2 Design 코드 분석
**파일**: `design/src/components/QuoteAutoCalculation.tsx`
```javascript
// 입력 상태
const [selectedProductId, setSelectedProductId] = useState("");
const [inputValues, setInputValues] = useState<Record<string, number>>({
width: 1000,
height: 2000,
quantity: 1
});
// 제품 목록 (FG 타입만 필터링)
const products = useMemo(() => {
return itemMasters.filter(item => item.itemType === 'FG');
}, [itemMasters]);
```
### 2.3 계산 방식 비교
| 항목 | Design | MNG |
|------|--------|-----|
| 계산 위치 | 프론트엔드 (`eval()`) | 백엔드 (`FormulaEvaluatorService`) |
| 데이터 소스 | `useData()` Context | DB API |
| BOM 규칙 | `formulaRules` | `quote_formulas` 테이블 |
| 단가 | `pricing` Context | DB 단가 테이블 |
---
## 3. 대상 범위
### 3.1 Phase 1: UI 입력 필드 (Design 기준)
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 1.1 | 제품 선택 드롭다운 | ✅ | FG 타입 제품 |
| 1.2 | 폭(width) 입력 필드 | ✅ | 기본값: 1000 |
| 1.3 | 높이(height) 입력 필드 | ✅ | 기본값: 2000 |
| 1.4 | 수량(quantity) 입력 필드 | ✅ | 기본값: 1 |
| 1.5 | UI 레이아웃 단일행 수정 | ✅ | flex-wrap |
### 3.2 Phase 2: 제품 데이터 로드 수정
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 2.1 | FG 제품 API 호출 확인 | ⏳ | 현재 빈 배열 반환 |
| 2.2 | tenant_id 확인 | ⏳ | 세션 기반 |
| 2.3 | 제품 드롭다운 데이터 바인딩 | ⏳ | - |
### 3.3 Phase 3: 계산 결과 검증
| # | 작업 항목 | 상태 | 비고 |
|---|----------|:----:|------|
| 3.1 | Design과 동일 입력으로 테스트 | ⏳ | width=1200, height=2400, qty=10 |
| 3.2 | BOM 구성 결과 비교 | ⏳ | 품목/수량 일치 여부 |
| 3.3 | 금액 계산 결과 비교 | ⏳ | 단가/총액 일치 여부 |
---
## 4. 상세 작업 내용
### 4.1 수정 대상 파일
| 파일 | 수정 내용 |
|------|----------|
| `simulator.blade.php` | UI 입력 필드 (Design 기준) |
| `FormulaEvaluatorService.php` | 계산 로직 (필요시) |
| `QuoteFormulaController.php` | API 파라미터 (필요시) |
### 4.2 UI 레이아웃 (Design 기준)
```
┌─────────────────────────────────────────────────────────────────┐
│ 완제품 BOM 시뮬레이션 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [제품 선택 ▼] [폭 width] [높이 height] [수량] [실행] │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 5. 컨펌 대기 목록
| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|---|------|----------|----------|------|
| 1 | 기존 추가 필드 제거 | PC, GT, MP, CT, WS, INSP 필드가 Design에 없음 | UI | ⚠️ 컨펌 필요 |
---
## 6. 변경 이력
| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|------|------|----------|------|------|
| 2025-12-30 | 초안 | 계획 문서 작성 | - | - |
| 2025-12-30 | Phase 1 | UI 입력 필드 추가 (PC, GT, MP, CT, WS, INSP) | simulator.blade.php | ✅ |
| 2025-12-30 | Phase 2 | 백엔드 변수 처리 및 디버그 로깅 개선 | FormulaEvaluatorService.php | ✅ |
| 2025-12-30 | 수정 | UI 레이아웃 단일행으로 변경 | simulator.blade.php | ✅ |
| 2025-12-30 | 수정 | 기준 문서 변경 (React → Design) | 계획 문서 | ✅ |
---
## 7. 참고 문서
- **Design 원본**: `design/src/components/QuoteAutoCalculation.tsx`
- **Design 가이드**: `design/src/QUOTE_AUTO_CALCULATION_GUIDE.md`
- **기존 시뮬레이터 계획**: `docs/plans/simulator-calculation-logic-mapping.md`
- **품질 체크리스트**: `docs/standards/quality-checklist.md`
---
## 8. 세션 및 메모리 관리 정책
### 8.1 Serena 메모리 구조
- `simulator-ui-state`: { phase, progress, next_step, last_decision }
- `simulator-ui-snapshot`: 현재까지의 코드 변경점 요약
### 8.2 세션 시작 시
```
read_memory("simulator-ui-state")
read_memory("simulator-ui-snapshot")
계획 문서 읽기
```
### 8.3 세션 종료 시
```
write_memory("simulator-ui-state")
계획 문서 업데이트
```
---
## 9. 검증 결과
> 작업 완료 후 이 섹션에 검증 결과 추가
### 9.1 테스트 케이스
| 입력값 | 예상 결과 | 실제 결과 | 상태 |
|--------|----------|----------|------|
| 스크린 제품, W=1200, H=2400, Q=10 | Design과 동일 | - | ⏳ |
### 9.2 성공 기준 달성 현황
| 기준 | 달성 | 비고 |
|------|------|------|
| Design과 동일한 입력 필드 | ⏳ | 제품/폭/높이/수량 |
| 제품 드롭다운 데이터 로드 | ❌ | 현재 비어있음 |
| Design과 동일한 계산 결과 | ⏳ | 검증 필요 |
---
*이 문서는 /sc:plan 스킬로 생성되었습니다.*