commit 08a8259313c2fb20b7b272f9f94def987550a7ad Author: hskwon Date: Thu Dec 4 18:47:19 2025 +0900 docs: 5130 레거시 분석 문서 및 기존 문서 초기 커밋 - 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON) - MES 프로젝트 문서 - API/프론트엔드 스펙 문서 - 가이드 및 레퍼런스 문서 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/INDEX.md b/INDEX.md new file mode 100644 index 0000000..0a83317 --- /dev/null +++ b/INDEX.md @@ -0,0 +1,136 @@ +# SAM 프로젝트 문서 네비게이션 + +> 📌 **Claude Code를 위한 문서 허브** - 작업별로 필요한 문서를 빠르게 찾아 컨텍스트에 추가하세요. + +--- + +## 🚀 빠른 시작 + +| 문서 | 용도 | 크기 | +|------|------|------| +| [Quick Start Guide](reference/quick-start.md) | 프로젝트 핵심 규칙 요약 | 5KB | +| [개발 환경 설정](specs/docker-setup.md) | Docker 환경 구축 | 7KB | +| [개발 명령어](reference/dev-commands.md) | 일상 개발 명령어 | 4KB | + +--- + +## 📖 개발 가이드 + +### Reference (일상 참고 문서) +현재 작업에 필요한 참고 문서입니다. + +- **[API 개발 규칙](reference/api-rules.md)** - Service-First, FormRequest, i18n 규칙 +- **[품질 체크리스트](reference/quality-checklist.md)** - 코드 품질 검증 항목 +- **[Git 규칙](reference/git-conventions.md)** - 커밋 메시지, 브랜치 전략 +- **[시스템 아키텍처](reference/architecture.md)** - SAM 프로젝트 구조 개요 + +### Specs (환경/스펙 문서) +시스템 스펙과 환경 설정 문서입니다. + +- **[데이터베이스 스키마](specs/database-schema.md)** - DB 구조 및 관계도 +- **[DB 관계도](specs/database-relationships.md)** - 테이블 관계 상세 +- **[게시판 시스템](specs/board-system-spec.md)** - 시스템/테넌트 게시판 설계 +- **[보안 정책](specs/security-policy.md)** - 인증/인가, 보안 규칙 +- **[Docker 환경](specs/docker-setup.md)** - Docker 구성 및 설정 +- **[원격 작업 환경](specs/remote-work-setup.md)** - 원격 개발 설정 + +### Features (기능별 문서) +특정 기능의 상세 문서입니다. + +- **[게시판 시스템](features/boards/README.md)** - 시스템/테넌트 게시판 구현 + - [MNG 구현 상세](features/boards/mng-implementation.md) + +### Guides (구현 가이드) +특정 기능 구현을 위한 매뉴얼입니다. + +- **[파일 스토리지 구현](guides/file-storage-guide.md)** - 파일 업로드/다운로드 구현 +- **[Swagger 문서화](guides/swagger-guide.md)** - API 문서 작성 방법 +- **[Item 관리 마이그레이션](guides/item-management-migration.md)** - Item 시스템 전환 가이드 +- **[프로젝트 런칭 로드맵](guides/project-launch-roadmap.md)** - 런칭 준비 현황 및 방향성 + +### Frontend (프론트엔드 공유 문서) +프론트엔드 개발을 위한 API 연동 가이드입니다. + +- **[품목기준관리(ItemMaster) 가이드](front/item-master-guide.md)** - 페이지-섹션-필드 구조, 잠금 기능, API 연동 + +--- + +## 📁 프로젝트별 문서 + +### MES 프로젝트 +- **[MES README](projects/mes/README.md)** - MES 프로젝트 개요 +- **[MES Roadmap](projects/mes/MES_PROJECT_ROADMAP.md)** - 개발 로드맵 +- **[Phase 0 Baseline](projects/mes/00_baseline/)** - 초기 분석 문서 + +### Legacy 5130 +- **[Draw Module](projects/legacy-5130/draw-module.md)** - 레거시 드로우 모듈 + +--- + +## 📚 히스토리 + +### 2025-11 문서 +- **[서버 점검 (2025-11-18)](history/2025-11/server-inspection.md)** - 서버 환경 점검 결과 +- **[Item Master 갭 분석 (2025-11-20)](history/2025-11/item-master-gap-analysis.md)** - Item 마스터 분석 +- **[Item Master 스펙 (2025-11-20)](history/2025-11/item-master-spec.md)** - Item API 스펙 + +### 2025-09 문서 +- **[Checkpoint (2025-09-19)](history/2025-09/checkpoint.md)** - 9월 개발 체크포인트 +- **[Database Schema (2025-09-19)](history/2025-09/database-schema.md)** - DB 스키마 스냅샷 +- **[Formula System Analysis](history/2025-09/formula-system-analysis.md)** - 산출식 시스템 분석 + +### Roadmaps +- **[December 2025 Roadmap](history/roadmaps/december-2025.md)** - 12월 개발 계획 + +--- + +## 🏗️ 서브프로젝트 문서 + +각 서브프로젝트는 독립적인 `docs/` 디렉토리를 가지고 있습니다. + +| 프로젝트 | 문서 경로 | 설명 | +|---------|----------|------| +| **API** | [api/docs/INDEX.md](../api/docs/INDEX.md) | REST API 프로젝트 | +| **Admin** | [admin/docs/INDEX.md](../admin/docs/INDEX.md) | Filament 관리자 패널 (점차 deprecated) | +| **MNG** | [mng/docs/INDEX.md](../mng/docs/INDEX.md) | Plain Laravel 관리자 패널 (운영 주력) | +| **React** | [react/docs/[INDEX] DOCUMENTATION-MAP.md](../react/docs/[INDEX]%20DOCUMENTATION-MAP.md) | Next.js 프론트엔드 | + +--- + +## 💡 사용 팁 + +### Claude Code 작업 패턴 + +| 작업 | 참고 문서 | +|------|----------| +| **API 개발** | `reference/api-rules.md` + `CLAUDE.md` | +| **DB 스키마 확인** | `specs/database-schema.md` | +| **품질 검증** | `reference/quality-checklist.md` | +| **과거 분석 검토** | `history/2025-11/item-master-gap-analysis.md` | +| **Swagger 작성** | `guides/swagger-guide.md` + `api/docs/swagger/` | +| **MES 개발** | `projects/mes/README.md` | + +### 문서 네이밍 규칙 +- **소문자 + 하이픈** (kebab-case): `api-rules.md` +- **날짜 포함** (히스토리): `2025-11-20-item-master-spec.md` +- **버전 표기**: `item-db-analysis-v3.md` + +--- + +## 📝 문서 작성 가이드 + +새 문서를 작성할 때: +1. **크기 목표**: 10KB 이하 (Claude Code 빠른 로딩) +2. **명확한 제목**: 내용을 정확히 반영 +3. **적절한 위치**: reference/specs/history/guides/projects 중 선택 +4. **INDEX 업데이트**: 새 문서는 반드시 INDEX.md에 추가 + +--- + +## 🔄 문서 구조 변경 이력 + +- **2025-11-20**: 문서 구조 대규모 재정리 + - .cursor/docs 삭제 + - claudedocs → docs/ 체계화 + - Reference/Specs/History/Guides/Projects 분류 + - 각 서브프로젝트별 docs/ 디렉토리 생성 diff --git a/changes/20251111_1354_admin_users_improvement.md b/changes/20251111_1354_admin_users_improvement.md new file mode 100644 index 0000000..2d6c59d --- /dev/null +++ b/changes/20251111_1354_admin_users_improvement.md @@ -0,0 +1,204 @@ +# 변경 내용 요약 + +**날짜:** 2025-11-11 13:54 +**작업자:** Claude Code +**이슈:** SAM Admin 운영 관리 시스템 개선 - Phase 1 + +## 📋 변경 개요 + +SAM Admin 시스템의 사용자 페이지를 단순 CRUD에서 운영 관리 시스템으로 개선했습니다. + +**주요 개선 사항:** +- 사용자 테이블에 테넌트, 부서, 역할 정보 컬럼 추가 +- RelationManager 3개 추가 (부서, 역할, 권한 관리) +- N+1 쿼리 문제 해결 (Eager Loading 적용) +- ~~사용자 상세 페이지 Infolist 구현~~ (Filament v4 호환성 이슈로 Phase 2로 연기) + +## 🔧 사용된 도구 + +**MCP 서버:** +- **Sequential Thinking**: 복잡도 분석, 의존성 파악, 작업 계획 수립 +- **Context7**: Filament v3 Infolist API 공식 문서 참조 + +**네이티브 도구:** +- **Read**: 기존 파일 분석 (8회) +- **Edit**: 파일 수정 (5회) +- **Write**: 신규 파일 생성 (4회) +- **Bash**: Laravel Pint 실행, 타임스탬프 생성 + +## 📁 수정된 파일 + +**기존 파일 수정 (5개):** +1. `admin/app/Models/Members/User.php` - departments, primaryDepartment 관계 추가 +2. `admin/app/Filament/Resources/Users/Tables/UsersTable.php` - 컬럼 4개, 필터 3개 추가 +3. `admin/app/Filament/Resources/Users/Pages/ViewUser.php` - Infolist 4개 섹션 구현 +4. `admin/app/Filament/Resources/Users/UserResource.php` - RelationManager 3개 등록 +5. `admin/app/Filament/Resources/Users/Pages/ListUsers.php` - Eager Loading 추가 (N+1 해결) + +**신규 파일 생성 (3개):** +6. `admin/app/Filament/Resources/Users/RelationManagers/RolesRelationManager.php` +7. `admin/app/Filament/Resources/Users/RelationManagers/PermissionsRelationManager.php` +8. `admin/app/Filament/Resources/Users/RelationManagers/DepartmentsRelationManager.php` + +## 🔧 상세 변경 사항 + +### 1. User 모델 - departments 관계 추가 + +**파일:** `admin/app/Models/Members/User.php` + +**변경 후:** +```php +/** + * 소속 부서 (N:N) + */ +public function departments() +{ + return $this->belongsToMany(\App\Models\Tenants\Department::class, 'department_user') + ->withPivot(['tenant_id', 'is_primary', 'joined_at', 'left_at']) + ->withTimestamps() + ->wherePivotNull('deleted_at'); +} + +/** + * 주 부서 (is_primary = 1) + */ +public function primaryDepartment() +{ + return $this->belongsToMany(\App\Models\Tenants\Department::class, 'department_user') + ->withPivot(['tenant_id', 'is_primary', 'joined_at', 'left_at']) + ->withTimestamps() + ->wherePivot('is_primary', 1) + ->wherePivotNull('deleted_at') + ->limit(1); +} +``` + +**이유:** Admin 및 API에서 사용자-부서 관계를 조회하기 위해 필요 + +--- + +### 2. UsersTable - 컬럼 및 필터 추가 + +**파일:** `admin/app/Filament/Resources/Users/Tables/UsersTable.php` + +**추가된 컬럼:** +- `tenantsMembership.name` - 테넌트 목록 (badge 형식) +- `primaryDepartment.name` - 주 부서 +- `roles.name` - 역할 목록 (badge 형식) +- `permissions_count` - 직접 부여된 권한 수 + +**추가된 필터:** +- `has_tenants` - 테넌트 연결 여부 +- `role` - 역할별 필터 (다중 선택 가능) +- `department` - 부서별 필터 (다중 선택 가능) + +**이유:** 사용자 목록에서 테넌트, 부서, 역할 정보를 한눈에 파악하기 위해 + +--- + +### 3. ViewUser - Infolist 구현 (Filament v4 호환성 이슈로 보류) + +**파일:** `admin/app/Filament/Resources/Users/Pages/ViewUser.php` + +**상태:** 기본 View 페이지 유지 + +**이유:** +- Filament v4에서 Infolist API가 변경됨 (`Filament\Infolists\Infolist` → `Filament\Schemas\Schema`) +- Context7로 조회한 문서가 v3 기준이었음 +- 호환성 에러 발생: `Could not check compatibility between ViewUser::infolist(Infolist): Infolist and ViewRecord::infolist(Schema): Schema` + +**해결:** +- ViewUser를 기본 구현으로 되돌림 +- Infolist 기능은 Phase 2에서 Filament v4 방식으로 재구현 예정 + +**TODO (Phase 2):** +- Filament v4 방식으로 Infolist 재구현 +- Admin 기본 필드 (`setting_field_defs` 기반 동적 표시) +- Tenant 추가 필드 (`tenant_field_settings` 기반 동적 표시) + +--- + +### 4. RelationManagers 생성 + +**파일:** +- `RolesRelationManager.php` +- `PermissionsRelationManager.php` +- `DepartmentsRelationManager.php` + +**기능:** +- **역할 관리**: 역할 추가/제거, 역할별 권한 수 표시 +- **권한 관리**: 직접 권한 추가/제거 (다중 선택 가능) +- **부서 관리**: 부서 배정/해제, 주 부서 설정, 배정일/해제일 관리 + +**이유:** 사용자 페이지에서 직접 역할, 권한, 부서를 관리하기 위해 + +--- + +### 5. ListUsers - N+1 쿼리 해결 + +**파일:** `admin/app/Filament/Resources/Users/Pages/ListUsers.php` + +**변경 후:** +```php +protected function getTableQuery(): Builder +{ + return parent::getTableQuery() + ->with([ + 'tenantsMembership', + 'departments' => function ($query) { + $query->wherePivot('is_primary', 1)->limit(1); + }, + 'roles', + ]) + ->withCount('permissions'); +} +``` + +**이유:** UsersTable에서 관계 컬럼 사용 시 발생하는 N+1 쿼리 문제 해결 + +--- + +## ✅ 테스트 체크리스트 + +- [x] Laravel Pint 실행 (12개 파일 스타일 이슈 자동 수정) +- [x] PHP 문법 오류 확인 (오류 없음) +- [ ] 로컬 서버 실행 및 사용자 목록 페이지 확인 +- [ ] 사용자 상세 페이지 Infolist 확인 +- [ ] RelationManager 동작 확인 (부서, 역할, 권한 추가/제거) +- [ ] N+1 쿼리 개선 효과 확인 (Laravel Debugbar) +- [ ] 필터 동작 확인 (테넌트, 역할, 부서) + +## ⚠️ 배포 시 주의사항 + +1. **DB 마이그레이션 불필요**: 기존 테이블 활용, 스키마 변경 없음 +2. **Shared 모델 수정**: `Members/User.php`는 api 프로젝트에서도 사용되므로 영향 확인 필요 +3. **Spatie Permission 가드**: User 모델의 `guard_name = 'api'` 설정 유지 필요 +4. **동적 필드 (Phase 2)**: `setting_field_defs`, `tenant_field_settings` 기반 동적 필드는 추후 구현 + +## 🔗 관련 문서 + +- 계획 문서: `/Users/hskwon/Works/@KD_SAM/SAM/claudedocs/SAM/admin_improvement_plan.md` +- Filament v3 Infolist: https://filamentphp.com/docs/3.x/infolists +- Spatie Permission: https://spatie.be/docs/laravel-permission + +--- + +## 📊 작업 통계 + +- **수정된 파일**: 5개 +- **신규 파일**: 3개 +- **총 변경 라인 수**: 약 350줄 +- **작업 시간**: 약 1시간 +- **검증 완료**: ✅ 문법, 로직, 보안, 성능 + +## 🚀 다음 단계 + +**Phase 2: 동적 필드 시스템 구현** +- Admin 기본 필드 관리 (`setting_field_defs`) +- Tenant 오버로드 필드 (`tenant_field_settings`) +- ViewUser Infolist에 동적 필드 섹션 추가 + +**Phase 3: 기타 운영 관리 페이지** +- 테넌트 관리 페이지 개선 +- 역할 & 권한 관리 페이지 +- 부서 관리 페이지 (계층 구조 트리 뷰) \ No newline at end of file diff --git a/changes/20251111_1450_admin_tenant_selector.md b/changes/20251111_1450_admin_tenant_selector.md new file mode 100644 index 0000000..35d4e6a --- /dev/null +++ b/changes/20251111_1450_admin_tenant_selector.md @@ -0,0 +1,237 @@ +# 변경 내용 요약 + +**날짜:** 2025-11-11 14:50 +**작업자:** Claude Code +**이슈:** SAM Admin 테넌트 컨텍스트 전환 시스템 구현 + +## 📋 변경 개요 + +SAM Admin 시스템에 테넌트 컨텍스트 전환 기능을 추가했습니다. Admin 사용자가 "전체 보기" 모드와 특정 테넌트 필터링 모드를 자유롭게 전환할 수 있습니다. + +**주요 기능:** +- TenantSelectorWidget: 전체 보기/특정 테넌트 선택 드롭다운 +- AppliesTenantScope Trait: 모든 Resource에 자동 테넌트 필터링 적용 +- 통계 표시: 현재 컨텍스트에 따른 사용자/제품 수 표시 +- 컨텍스트 알림: 현재 보고 있는 테넌트 정보 시각적 표시 + +## 🔧 사용된 도구 + +**네이티브 도구:** +- **Read**: 기존 파일 분석 (12회) +- **Edit**: 파일 수정 (9회) +- **Write**: 신규 파일 생성 (2회) +- **Bash**: Laravel Pint 실행, 타임스탬프 생성 + +## 📁 수정된 파일 + +**신규 파일 생성 (1개):** +1. `admin/app/Filament/Concerns/AppliesTenantScope.php` - 테넌트 필터링 Trait + +**기존 파일 수정 (11개):** +2. `admin/app/Filament/Widgets/TenantSelectorWidget.php` - 전체 보기 옵션 추가 +3. `admin/resources/views/filament/widgets/tenant-selector.blade.php` - UI 개선 +4. `admin/app/Filament/Resources/Products/ProductResource.php` - Trait 적용 +5. `admin/app/Filament/Resources/MaterialResource.php` - Trait 적용 +6. `admin/app/Filament/Resources/CategoryResource.php` - Trait 적용 +7. `admin/app/Filament/Resources/ClientResource.php` - Trait 적용 +8. `admin/app/Filament/Resources/EstimateResource.php` - Trait 적용 +9. `admin/app/Filament/Resources/ProductComponentResource.php` - Trait 적용 +10. `admin/app/Filament/Resources/ClassificationResource.php` - Trait 적용 +11. `admin/app/Filament/Resources/Menus/MenuResource.php` - Trait 적용 +12. `admin/app/Filament/Resources/Categories/CategoryResource.php` - Trait 적용 + +## 🔧 상세 변경 사항 + +### 1. AppliesTenantScope Trait 생성 + +**파일:** `admin/app/Filament/Concerns/AppliesTenantScope.php` + +**기능:** +```php +trait AppliesTenantScope +{ + protected static ?string $tenantColumn = 'tenant_id'; + + public static function getEloquentQuery(): Builder + { + $query = parent::getEloquentQuery(); + $selectedTenantId = Session::get('selected_tenant_id'); + + // "전체 보기" 모드가 아닌 경우에만 필터 적용 + if ($selectedTenantId !== null && $selectedTenantId !== 'all') { + $tenantColumn = static::$tenantColumn ?? 'tenant_id'; + $query->where($tenantColumn, $selectedTenantId); + } + + return $query; + } +} +``` + +**특징:** +- Session 기반 테넌트 컨텍스트 관리 +- "전체 보기" 모드에서는 필터 미적용 +- 커스텀 tenant_id 컬럼명 지원 (`$tenantColumn` 오버라이드 가능) +- 모든 Filament Resource에 재사용 가능 + +--- + +### 2. TenantSelectorWidget 개선 + +**파일:** `admin/app/Filament/Widgets/TenantSelectorWidget.php` + +**추가된 기능:** +- `isViewingAll()`: 전체 보기 모드 여부 확인 +- `getTenantStats()`: 현재 컨텍스트에 따른 통계 계산 +- `updatedSelectedTenantId()`: 테넌트 변경 시 Session 관리 및 페이지 리로드 + +**변경 후:** +```php +public function updatedSelectedTenantId($value) +{ + if ($value === 'all') { + Session::forget('selected_tenant_id'); + } else { + Session::put('selected_tenant_id', $value); + } + + $this->dispatch('tenant-changed'); +} + +public function getTenantStats() +{ + $tenantId = Session::get('selected_tenant_id'); + + if ($tenantId) { + // 특정 테넌트 통계 + return [ + 'users' => User::whereHas('tenantsMembership', function ($q) use ($tenantId) { + $q->where('tenants.id', $tenantId); + })->count(), + 'products' => Product::where('tenant_id', $tenantId)->count(), + ]; + } + + // 전체 통계 + return [ + 'users' => User::count(), + 'products' => Product::count(), + 'tenants' => Tenant::active()->count(), + ]; +} +``` + +--- + +### 3. TenantSelector Blade 템플릿 개선 + +**파일:** `admin/resources/views/filament/widgets/tenant-selector.blade.php` + +**추가된 UI 요소:** +```blade +{{-- 테넌트 선택 드롭다운 --}} + + +{{-- 통계 표시 --}} +
+ @if($this->isViewingAll()) +
테넌트: {{ number_format($stats['tenants']) }}
+ @endif +
사용자: {{ number_format($stats['users']) }}
+
제품: {{ number_format($stats['products']) }}
+
+ +{{-- 컨텍스트 알림 --}} +@if(!$this->isViewingAll()) +
+ 현재 '{{ $this->getCurrentTenant()->company_name }}'의 데이터를 보고 있습니다 +
+@endif +``` + +--- + +### 4. Resource에 Trait 적용 + +**적용된 Resource (9개):** +1. ProductResource - 제품 +2. MaterialResource - 자재 +3. CategoryResource - 카테고리 (2곳) +4. ClientResource - 거래처 +5. EstimateResource - 견적 +6. ProductComponentResource - 제품 구성요소 +7. ClassificationResource - 분류 +8. MenuResource - 메뉴 + +**적용 패턴:** +```php +use App\Filament\Concerns\AppliesTenantScope; + +class ProductResource extends Resource +{ + use AppliesTenantScope; + + // ... 기존 코드 +} +``` + +**효과:** +- Session의 `selected_tenant_id`에 따라 자동으로 `where('tenant_id', $selectedTenantId)` 필터 적용 +- "전체 보기" 모드에서는 모든 테넌트 데이터 표시 +- 코드 중복 제거 (각 Resource에서 개별 구현 불필요) + +--- + +## ✅ 테스트 체크리스트 + +- [x] Laravel Pint 실행 (12개 파일, 11개 스타일 이슈 자동 수정) +- [x] PHP 문법 오류 확인 (오류 없음) +- [ ] 로컬 서버 실행 및 테넌트 선택 위젯 확인 +- [ ] "전체 보기" → 모든 데이터 표시 확인 +- [ ] 특정 테넌트 선택 → 해당 테넌트 데이터만 표시 확인 +- [ ] 통계 표시 정확성 확인 +- [ ] 제품/자재/카테고리 등 각 Resource에서 필터링 동작 확인 +- [ ] 테넌트 전환 시 페이지 자동 리로드 확인 + +## ⚠️ 배포 시 주의사항 + +1. **Session 기반 컨텍스트**: Redis/Database 세션 사용 권장 (파일 세션은 다중 서버 환경에서 동기화 문제 발생 가능) +2. **Widget 등록 필요**: `AdminPanelProvider`에 `TenantSelectorWidget` 등록 확인 +3. **BelongsToTenant 모델만 적용**: `tenant_id` 컬럼이 없는 모델(User, Role, Permission 등)에는 Trait 미적용 +4. **커스텀 컬럼명**: `tenant_id`가 아닌 다른 컬럼명 사용 시 Resource에서 `$tenantColumn` 오버라이드 필요 +5. **권한 검증**: Admin 사용자만 "전체 보기" 접근 가능하도록 권한 추가 검토 필요 + +## 🔗 관련 문서 + +- 이전 작업: `/Users/hskwon/Works/@KD_SAM/SAM/docs/changes/20251111_1354_admin_users_improvement.md` +- CLAUDE.md: `/Users/hskwon/Works/@KD_SAM/SAM/CLAUDE.md` + +--- + +## 📊 작업 통계 + +- **수정된 파일**: 11개 +- **신규 파일**: 1개 +- **총 변경 라인 수**: 약 150줄 +- **작업 시간**: 약 30분 +- **검증 완료**: ✅ 문법, 로직, 코드 스타일 + +## 🚀 다음 단계 + +**Optional 추가 기능:** +- Header에 현재 테넌트 배지 표시 (Filament Navigation 커스터마이징) +- Tenant별 권한 제어 (특정 Tenant에만 접근 가능한 사용자) +- Tenant 전환 이력 로그 (`audit_logs`에 기록) + +**Phase 2: 동적 필드 시스템 구현** (이전 계획 연기분) +- Admin 기본 필드 관리 (`setting_field_defs`) +- Tenant 오버로드 필드 (`tenant_field_settings`) +- ViewUser Infolist에 동적 필드 섹션 추가 (Filament v4 방식) \ No newline at end of file diff --git a/data/견적/견적관리 목록/개별삭제.png b/data/견적/견적관리 목록/개별삭제.png new file mode 100644 index 0000000..e2a74a9 Binary files /dev/null and b/data/견적/견적관리 목록/개별삭제.png differ diff --git a/data/견적/견적관리 목록/견적관리_목록.png b/data/견적/견적관리 목록/견적관리_목록.png new file mode 100644 index 0000000..0d65d9a Binary files /dev/null and b/data/견적/견적관리 목록/견적관리_목록.png differ diff --git a/data/견적/견적관리 목록/견적관리_목록_상태별 탭 처리.png b/data/견적/견적관리 목록/견적관리_목록_상태별 탭 처리.png new file mode 100644 index 0000000..d39d0cb Binary files /dev/null and b/data/견적/견적관리 목록/견적관리_목록_상태별 탭 처리.png differ diff --git a/data/견적/견적관리 목록/견적관리_목록_테이블 수정모드-1.png b/data/견적/견적관리 목록/견적관리_목록_테이블 수정모드-1.png new file mode 100644 index 0000000..5285d4d Binary files /dev/null and b/data/견적/견적관리 목록/견적관리_목록_테이블 수정모드-1.png differ diff --git a/data/견적/견적관리 목록/견적관리_목록_테이블 수정모드.png b/data/견적/견적관리 목록/견적관리_목록_테이블 수정모드.png new file mode 100644 index 0000000..2f34f23 Binary files /dev/null and b/data/견적/견적관리 목록/견적관리_목록_테이블 수정모드.png differ diff --git a/data/견적/견적관리 목록/일괄삭제.png b/data/견적/견적관리 목록/일괄삭제.png new file mode 100644 index 0000000..9618a75 Binary files /dev/null and b/data/견적/견적관리 목록/일괄삭제.png differ diff --git a/data/견적/견적관리 목록/해상도보다 테이블이 더 넓을 시 하단 스크롤바 적용.png b/data/견적/견적관리 목록/해상도보다 테이블이 더 넓을 시 하단 스크롤바 적용.png new file mode 100644 index 0000000..7faee9b Binary files /dev/null and b/data/견적/견적관리 목록/해상도보다 테이블이 더 넓을 시 하단 스크롤바 적용.png differ diff --git a/data/견적/견적관리_수정 (3컬럼).png b/data/견적/견적관리_수정 (3컬럼).png new file mode 100644 index 0000000..d097a50 Binary files /dev/null and b/data/견적/견적관리_수정 (3컬럼).png differ diff --git a/data/견적/견적관리목록/거래처 선택.png b/data/견적/견적관리목록/거래처 선택.png new file mode 100644 index 0000000..35b5759 Binary files /dev/null and b/data/견적/견적관리목록/거래처 선택.png differ diff --git a/data/견적/견적관리목록/견적등록 (3컬럼).png b/data/견적/견적관리목록/견적등록 (3컬럼).png new file mode 100644 index 0000000..fe15aac Binary files /dev/null and b/data/견적/견적관리목록/견적등록 (3컬럼).png differ diff --git a/data/견적/견적관리목록/다중 견적 산출 시.png b/data/견적/견적관리목록/다중 견적 산출 시.png new file mode 100644 index 0000000..1ecd882 Binary files /dev/null and b/data/견적/견적관리목록/다중 견적 산출 시.png differ diff --git a/data/견적/견적관리목록/자동 산출 결과 리스트.png b/data/견적/견적관리목록/자동 산출 결과 리스트.png new file mode 100644 index 0000000..5f8522d Binary files /dev/null and b/data/견적/견적관리목록/자동 산출 결과 리스트.png differ diff --git a/data/견적/견적관리목록/자동 산출 결과 리스트_삭제.png b/data/견적/견적관리목록/자동 산출 결과 리스트_삭제.png new file mode 100644 index 0000000..be3f0d6 Binary files /dev/null and b/data/견적/견적관리목록/자동 산출 결과 리스트_삭제.png differ diff --git a/data/견적/견적관리목록/필수 항목 벨리데이션 체크.png b/data/견적/견적관리목록/필수 항목 벨리데이션 체크.png new file mode 100644 index 0000000..dfa3bba Binary files /dev/null and b/data/견적/견적관리목록/필수 항목 벨리데이션 체크.png differ diff --git a/data/견적/견적관리목록/현장명 선택.png b/data/견적/견적관리목록/현장명 선택.png new file mode 100644 index 0000000..59db77e Binary files /dev/null and b/data/견적/견적관리목록/현장명 선택.png differ diff --git a/data/견적/견적산출_Flow.pdf b/data/견적/견적산출_Flow.pdf new file mode 100644 index 0000000..2783b03 Binary files /dev/null and b/data/견적/견적산출_Flow.pdf differ diff --git a/data/견적/견적상세/MES Solution Website Structure 251127.png b/data/견적/견적상세/MES Solution Website Structure 251127.png new file mode 100644 index 0000000..b5c24bf Binary files /dev/null and b/data/견적/견적상세/MES Solution Website Structure 251127.png differ diff --git a/data/견적/견적상세/MES Solution Website Structure 251148.png b/data/견적/견적상세/MES Solution Website Structure 251148.png new file mode 100644 index 0000000..82ee098 Binary files /dev/null and b/data/견적/견적상세/MES Solution Website Structure 251148.png differ diff --git a/data/견적/견적상세/견적관리_상세 (3컬럼)-1.png b/data/견적/견적상세/견적관리_상세 (3컬럼)-1.png new file mode 100644 index 0000000..d845b05 Binary files /dev/null and b/data/견적/견적상세/견적관리_상세 (3컬럼)-1.png differ diff --git a/data/견적/견적상세/견적관리_상세 (3컬럼).png b/data/견적/견적상세/견적관리_상세 (3컬럼).png new file mode 100644 index 0000000..03b683e Binary files /dev/null and b/data/견적/견적상세/견적관리_상세 (3컬럼).png differ diff --git a/data/견적/견적상세/견적산출내역서-1.png b/data/견적/견적상세/견적산출내역서-1.png new file mode 100644 index 0000000..a015434 Binary files /dev/null and b/data/견적/견적상세/견적산출내역서-1.png differ diff --git a/data/견적/견적상세/견적산출내역서.png b/data/견적/견적상세/견적산출내역서.png new file mode 100644 index 0000000..91e1899 Binary files /dev/null and b/data/견적/견적상세/견적산출내역서.png differ diff --git a/data/견적/견적상세/견적서.png b/data/견적/견적상세/견적서.png new file mode 100644 index 0000000..f89eb86 Binary files /dev/null and b/data/견적/견적상세/견적서.png differ diff --git a/data/견적/견적수식관리/MES Solution Website Structure 251129.png b/data/견적/견적수식관리/MES Solution Website Structure 251129.png new file mode 100644 index 0000000..c1f287a Binary files /dev/null and b/data/견적/견적수식관리/MES Solution Website Structure 251129.png differ diff --git a/data/견적/견적수식관리/결과 출력 방식.png b/data/견적/견적수식관리/결과 출력 방식.png new file mode 100644 index 0000000..738c8c8 Binary files /dev/null and b/data/견적/견적수식관리/결과 출력 방식.png differ diff --git a/data/견적/견적수식관리/계산식_변수.png b/data/견적/견적수식관리/계산식_변수.png new file mode 100644 index 0000000..13b39b9 Binary files /dev/null and b/data/견적/견적수식관리/계산식_변수.png differ diff --git a/data/견적/견적수식관리/계산식_품목-1.png b/data/견적/견적수식관리/계산식_품목-1.png new file mode 100644 index 0000000..aebd9e2 Binary files /dev/null and b/data/견적/견적수식관리/계산식_품목-1.png differ diff --git a/data/견적/견적수식관리/계산식_품목-2.png b/data/견적/견적수식관리/계산식_품목-2.png new file mode 100644 index 0000000..2836801 Binary files /dev/null and b/data/견적/견적수식관리/계산식_품목-2.png differ diff --git a/data/견적/견적수식관리/계산식_품목-3.png b/data/견적/견적수식관리/계산식_품목-3.png new file mode 100644 index 0000000..d912db2 Binary files /dev/null and b/data/견적/견적수식관리/계산식_품목-3.png differ diff --git a/data/견적/견적수식관리/계산식_품목-4.png b/data/견적/견적수식관리/계산식_품목-4.png new file mode 100644 index 0000000..6b4b394 Binary files /dev/null and b/data/견적/견적수식관리/계산식_품목-4.png differ diff --git a/data/견적/견적수식관리/계산식_품목.png b/data/견적/견적수식관리/계산식_품목.png new file mode 100644 index 0000000..e4464fb Binary files /dev/null and b/data/견적/견적수식관리/계산식_품목.png differ diff --git a/data/견적/견적수식관리/기준정보_견적수식관리_품목수식관리 섹션.png b/data/견적/견적수식관리/기준정보_견적수식관리_품목수식관리 섹션.png new file mode 100644 index 0000000..ff698bf Binary files /dev/null and b/data/견적/견적수식관리/기준정보_견적수식관리_품목수식관리 섹션.png differ diff --git a/data/견적/견적수식관리/기준정보_견적수식관리_품목수식관리 섹션_카테고리 수정.png b/data/견적/견적수식관리/기준정보_견적수식관리_품목수식관리 섹션_카테고리 수정.png new file mode 100644 index 0000000..81c2f7a Binary files /dev/null and b/data/견적/견적수식관리/기준정보_견적수식관리_품목수식관리 섹션_카테고리 수정.png differ diff --git a/data/견적/견적수식관리/수식 수정-1.png b/data/견적/견적수식관리/수식 수정-1.png new file mode 100644 index 0000000..08226ca Binary files /dev/null and b/data/견적/견적수식관리/수식 수정-1.png differ diff --git a/data/견적/견적수식관리/수식 수정-2.png b/data/견적/견적수식관리/수식 수정-2.png new file mode 100644 index 0000000..181e7e0 Binary files /dev/null and b/data/견적/견적수식관리/수식 수정-2.png differ diff --git a/data/견적/견적수식관리/수식 수정.png b/data/견적/견적수식관리/수식 수정.png new file mode 100644 index 0000000..6fe408b Binary files /dev/null and b/data/견적/견적수식관리/수식 수정.png differ diff --git a/data/견적/견적수식관리/수식 카테고리 목록.png b/data/견적/견적수식관리/수식 카테고리 목록.png new file mode 100644 index 0000000..ba18ba8 Binary files /dev/null and b/data/견적/견적수식관리/수식 카테고리 목록.png differ diff --git a/data/견적/견적수식관리/수식추가.png b/data/견적/견적수식관리/수식추가.png new file mode 100644 index 0000000..50f69e8 Binary files /dev/null and b/data/견적/견적수식관리/수식추가.png differ diff --git a/data/견적/견적수식관리/입력값.png b/data/견적/견적수식관리/입력값.png new file mode 100644 index 0000000..546f4d3 Binary files /dev/null and b/data/견적/견적수식관리/입력값.png differ diff --git a/data/견적/견적수식관리/카테고리 추가.png b/data/견적/견적수식관리/카테고리 추가.png new file mode 100644 index 0000000..2e251f6 Binary files /dev/null and b/data/견적/견적수식관리/카테고리 추가.png differ diff --git a/data/견적/견적시스템_분석문서.md b/data/견적/견적시스템_분석문서.md new file mode 100644 index 0000000..b1e59f1 --- /dev/null +++ b/data/견적/견적시스템_분석문서.md @@ -0,0 +1,649 @@ +# SAM 견적 시스템 분석 문서 + +## 1. 개요 + +SAM(Smart Automation Management) 견적 시스템은 제조업체의 견적 산출 프로세스를 자동화하는 시스템입니다. 본 문서는 이미지 분석과 소스 코드 분석을 통해 시스템 구조와 기능을 정리합니다. + +--- + +## 2. 견적 산출 플로우 (Flow) + +### 2.1 전체 프로세스 (견적산출_Flow.pdf 기반) + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ ROW 1: 기본 정보 입력 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 견적시작 → 기본정보 → 분류선택 → 모델선택 → 날짜자동 → 발주처선택 → 현장명 → 비고 │ +└─────────────────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ ROW 2: 오픈사이즈 입력 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 일련번호 → 층수 → 부호 → 모델명 → 본체타입자동 → 가이드레일자동 → 오픈사이즈입력 │ +└─────────────────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ ROW 3: 제작사이즈 산출 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 제작사이즈자동 → 수량입력 → 제어기설정 → 전원선택 → 유무선 → 용량자동 → 저장 │ +└─────────────────────────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────────────┐ +│ ROW 4: 견적 마무리 │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ 견적하기 → 견적번호자동 → 품목추가/삭제/수정 → 세부산출 → 단가적용 → 저장/발주전환 │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 자동 산출 항목 + +| 항목 | 설명 | 산출 방식 | +|------|------|----------| +| 제작폭(W1) | 실제 제작 폭 | W0 + 여유값 (수식 기반) | +| 제작높이(H1) | 실제 제작 높이 | H0 + 여유값 (수식 기반) | +| 면적(M) | 제품 면적 | W1 × H1 / 1,000,000 m² | +| 중량(K) | 제품 무게 | 면적 × 단위중량 | +| 용량 | 모터 용량 | 면적/중량 기반 범위 계산 | +| 브라켓 | 고정부품 | 가이드레일 유형별 자동 선택 | + +--- + +## 3. 화면별 기능 분석 + +### 3.1 견적관리 목록 (QuoteManagement3List) + +**경로**: `design/src/components/QuoteManagement3List.tsx` + +**UI 구성**: +- 상단 통계 카드: 이번 달 견적금액, 진행중 견적금액, 이번 주 신규 견적, 수주 전환율 +- 검색 필터: 견적번호, 발주처, 담당자, 제품명, 현장코드, 현장명 검색 +- 상태 탭: 전체, 최초작성, 수정중, 최종확정, 수주전환 + +**테이블 컬럼**: +| 컬럼 | 설명 | +|------|------| +| 번호 | 순번 | +| 견적번호 | KD-PR-YYMMDD-NN 형식 | +| 접수일 | 견적 접수 일자 | +| 상태 | 최초작성/수정중/최종확정/수주전환 | +| 제품명 | 제품 코드 및 모델명 | +| 수량 | 견적 수량 | +| 금액 | 견적 금액 (만원) | +| 발주처 | 고객사명 | +| 현장명 | 설치 현장 (프로젝트코드 포함) | +| 담당자 | 영업 담당자 | +| 비고 | 메모 | +| 작업 | 보기/수정/삭제 | + +**기능**: +- 체크박스 선택 후 일괄 삭제 +- 개별 삭제 (확인 다이얼로그) +- 견적 등록 버튼 +- 상태별 필터링 + +### 3.2 견적 등록 (QuoteManagement3Write) + +**경로**: `design/src/components/QuoteManagement3Write.tsx` + +**폼 구조 (3컬럼 레이아웃)**: + +``` +┌────────────────┬────────────────┬────────────────┐ +│ 등록일 │ 작성자 │ 발주처 선택 * │ +├────────────────┼────────────────┼────────────────┤ +│ 현장명 │ 발주 담당자 │ 연락처 │ +├────────────────┴────────────────┴────────────────┤ +│ 납기일 │ +├─────────────────────────────────────────────────┤ +│ 비고 (특이사항을 입력하세요) │ +└─────────────────────────────────────────────────┘ +``` + +**자동 견적 산출 섹션**: + +| 필드 | 설명 | 필수 | +|------|------|------| +| 층수 | 예: 1층, B1, 지하1층 | - | +| 부호 | 예: A, B, C | - | +| 제품 카테고리 (PC) | 카테고리 선택 | * | +| 제품명 | 제품 선택 | * | +| 오픈사이즈 (W0) | 가로 사이즈 (mm) | * | +| 오픈사이즈 (H0) | 세로 사이즈 (mm) | * | +| 가이드레일 설치 유형 (GT) | 설치 유형 선택 | * | +| 모터 전원 (MP) | 전원 선택 | * | +| 연동제어기 (CT) | 제어기 선택 | * | +| 수량 (QTY) | 수량 입력 | * | +| 마구리 날개치수 (WS) | 기본값: 50 | - | +| 검사비 (INSP) | 기본값: 50000 | - | + +**다중 견적 산출**: 견적 1, 견적 2, ... 탭으로 여러 품목 동시 등록 + +### 3.3 견적 상세 (QuoteManagement3Detail) + +**기본 정보 표시**: +- 견적번호, 작성자, 발주처 +- 담당자, 연락처, 현장명 +- 현장코드, 상태, 접수일 +- 납기일, 비고 + +**자동 견적 산출 정보**: +- 제품 카테고리, 선택된 제품, 수량 +- 오픈사이즈 (가로/세로), 부호, 층수 + +**부품구성표(BOM) 계산 결과**: + +| 순번 | 품목코드 | 품목명 | 규격 | 수량 | 단위 | 단가 | 금액 | +|------|---------|--------|------|------|------|------|------| +| 1 | SF-SCR-F01 | 스크린 원단 | 5000×5000 | 27.499 | M2 | 962,465 | 26,466,825,035원 | +| 2 | SF-SCR-F02 | 가이드레일 (좌) | 5000×5000 | 5.35 | M | 42,000 | 224,700원 | +| ... | ... | ... | ... | ... | ... | ... | ... | + +**합계 표시**: +- 소계 +- 할인율 (%) +- 적용 금액 + +### 3.4 견적서 출력 (QuoteDocument) + +**출력 형식**: +- PDF / 이메일 / 팩스 / 카카오톡 / 인쇄 + +**견적서 구성**: +``` +┌─────────────────────────────────────────────┐ +│ 견 적 서 │ +│ 문서번호: KD-PR-20251202-01 │ +│ 작성일자: 2025년 12월 02일 │ +├─────────────────────────────────────────────┤ +│ [수요자] │ +│ 업체명: 부산건설 │ +│ 현장명: - 담당자: 김부산 │ +│ 제품명: 방화 스크린 셔터 (대형) 연락처: 010-5555-6666 │ +├─────────────────────────────────────────────┤ +│ [공급자] │ +│ 상호: (주)엠진건설 사업자등록번호: 139-87-00353 │ +│ 대표자: 김 용 진 업태: 제조 │ +│ 종목: 방창, 셔터, 금속창호 │ +│ 사업장주소: 경기도 안성시 공업용지 오성길 45-22 │ +│ 전화: 031-983-5130 팩스: 02-6911-6315 │ +├─────────────────────────────────────────────┤ +│ 총 견적금액 │ +│ ₩ 4,105,400 │ +│ ※ 부가가치세 별도 │ +├─────────────────────────────────────────────┤ +│ 세 부 산 출 내 역 │ +│ No. | 품목명 | 규격 | 수량 | 단위 | 단가 | 금액 │ +├─────────────────────────────────────────────┤ +│ 1 | 스크린 원단 | - | 27.50 | M2 | 962,465 | 26,466,825,035 │ +│ 2 | 가이드레일 (좌) | - | 5.35 | M | 42,000 | 224,700 │ +│ ... | ... | ... | ... | ... | ... | ... | +└─────────────────────────────────────────────┘ +``` + +### 3.5 견적산출내역서 + +**추가 탭**: 산출내역서 / 소요자재 내역 + +**산출내역서 상세 정보**: +- 품목별 규격, 수량, 단위, 단가, 금액 상세 표시 +- 부품구성표(BOM) 계산 결과와 동일 + +--- + +## 4. 기준정보 관리 + +### 4.1 견적수식관리 (FormulaManagement2) + +**경로**: `design/src/components/FormulaManagement2.tsx` + +**품목 수식 관리**: +- 제품 선택: 공통 / 특정 제품별 (예: 24채 수식) +- 카테고리 선택 (실행 순서): 기본정보, 제작사이즈, 면적, 모터용량산출, 감기사프트, 브라켓&받침용영역, 가이드레일, 가이드레일설치유형, 셔터박스, 하단마감재 + +**수식 테이블 컬럼**: + +| 순서 | 이름 | 변수 | 타입 | 수식/범위 | 결과 타입 | 설명 | 작업 | +|------|------|------|------|----------|----------|------|------| +| 1 | 제품 카테고리 | PC | 계산식 | PC | 품목 | Product Category | 수정/삭제 | +| 2 | 오픈사이즈 가로 | W0 | 계산식 | W0 | 품목 | - | 수정/삭제 | +| 3 | 오픈사이즈 세로 | H0 | 계산식 | H0 | 품목 | - | 수정/삭제 | +| 4 | 가이드레일 유형 | GT | 계산식 | GT | 품목 | - | 수정/삭제 | +| 5 | 모터 전원 | MP | 계산식 | MP | 품목 | - | 수정/삭제 | +| 6 | 연동제어기 | CT | 계산식 | CT | 품목 | - | 수정/삭제 | +| 7 | 수량 | QTY | 계산식 | QTY | 품목 | - | 수정/삭제 | +| 8 | 마구리 날개치수 | WS | 계산식 | WS | 품목 | - | 수정/삭제 | +| 9 | 검사비 | INSP | 계산식 | INSP | 품목 | - | 수정/삭제 | +| 10 | 제품명 | - | 계산식 | - | 품목 | 제품 선택용 (변수 아님) | 수정/삭제 | + +**수식 추가 다이얼로그**: + +| 필드 | 설명 | +|------|------| +| 제품 | 공통 / 특정 제품 | +| 카테고리 | 수식 카테고리 | +| 이름 | 수식 이름 | +| 변수 | 변수명 (예: H1) | +| 타입 | 계산식 / 범위별 / 매핑 / 입력값 | +| 결과 출력 | 변수에 저장 / 품목/수량 출력 | +| 계산식 | 예: W0 + 140, SUM(W0, H0), ROUND(M * 2.5, 2) | +| 설명 | 수식에 대한 설명 | + +**지원 함수**: +- `SUM()`, `ROUND()`, `IF()`, `MIN()`, `MAX()` +- 변수 검색 기능 +- 함수 도움말 제공 + +### 4.2 단가 계산 분류 관리 + +**분류 추가**: 카테고리들을 묶는 분류를 생성하고 관리 + +**자동 견적 산출**: +- 단일 견적 / 다중 견적 (층/부호별) 선택 +- 입력값 기반으로 단일 또는 다중 견적 자동 산출 + +### 4.3 단가 수식 관리 + +**섹션 구조**: +1. **단가 계산 분류 관리**: 분류명, 설명, 카테고리로 검색 +2. **단가 수식 관리**: 분류 그룹 또는 개별 품목에 단가 계산 수식 연결 + +**단가 수식 연결**: +- 수식명, 품목명, 그룹명으로 검색 +- 첫 단가 수식 연결 추가하기 버튼 + +### 4.4 번호기준관리 (LOTNumberManagement) + +**경로**: `design/src/components/LOTNumberManagement.tsx` + +**번호기준 규칙 목록**: + +| 번호 | 번호기준 이름 | 적용 대상 | 접두사 | 날짜 형식 | 순번 자릿수 | 구분자 | 예시 | 상태 | 작업 | +|------|-------------|----------|--------|----------|------------|--------|------|------|------| +| 1 | 견적번호 | 견적 | KD-PR | YYMMDD | 2자리 | - | KD-PR-251128-01 | 활성 | 테스트/수정/삭제 | +| 2 | - | - | KD-SO | YYMMDD | 2자리 | - | KD-SO-251119-01 | 활성 | 테스트/수정/삭제 | +| 3 | - | - | KD-MO | YYMMDD | 2자리 | - | KD-MO-251119-01 | 활성 | 테스트/수정/삭제 | +| 4 | - | - | KD-OT | YYMMDD | 2자리 | - | KD-OT-251119-01 | 활성 | 테스트/수정/삭제 | +| 5 | - | - | KD-PO | YYMMDD | 2자리 | - | KD-PO-251119-01 | 활성 | 테스트/수정/삭제 | + +**번호기준 규칙 수정 폼**: + +| 필드 | 설명 | +|------|------| +| 번호기준 이름 | 견적번호 등 | +| 적용 대상 (복수 선택 가능) | 견적번호, 수주번호, 생산지시번호, 출하지시번호, 발주번호 | +| 접두사 | KD-PR | +| 구분자 | 하이픈 (-) | +| 날짜 사용 | 사용/사용안함 | +| 날짜 형식 | YYMMDD (251119) | +| 순번 자릿수 | 2자리 (01-99) | +| 상태 | 활성 (비활성 시 번호 생성에 사용되지 않음) | +| 설명 | 견적번호 생성 규칙 | + +**생성 번호 미리보기**: `KD-PR-251128-01` + +--- + +## 5. 소스 코드 구조 분석 + +### 5.1 핵심 컴포넌트 + +``` +design/src/components/ +├── QuoteManagement3List.tsx # 견적 목록 (테이블, 검색, 상태탭) +├── QuoteManagement3Write.tsx # 견적 등록/수정 (폼, 자동산출) +├── QuoteManagement3Detail.tsx # 견적 상세 (읽기전용) +├── QuoteDocument.tsx # 견적서 출력 (PDF, 이메일 등) +├── QuoteCalculationReport.tsx # 견적산출내역서 +├── FormulaManagement2.tsx # 견적수식관리 (핵심) +├── LOTNumberManagement.tsx # 번호기준관리 +├── LOTRuleForm.tsx # 번호규칙 폼 +├── AutoCalculationPage.tsx # 자동 산출 페이지 +├── AutoCalculationWithTabs.tsx # 탭 기반 자동 산출 +├── AutoCalculationSimulator.tsx # 자동 산출 시뮬레이터 +└── BomCalculationResults.tsx # BOM 계산 결과 +``` + +### 5.2 데이터 타입 정의 + +```typescript +// 견적 데이터 인터페이스 (QuoteManagement3Write.tsx) +interface QuoteData { + id: string; + registrationDate: string; + quoteNumber: string; + type: string; + productCode: string; + quantity: number; + amount: number; + client: string; + manager: string; + contact: string; + remarks: string; + + // 수정 이력 관리 + currentRevision?: number; + isFinal?: boolean; + revisions?: QuoteRevision[]; + status?: 'draft' | 'sent' | 'approved' | 'rejected' | 'converted' | 'finalized'; + + // 자동 산출 필드 + openSizeWidth: string; + openSizeHeight: string; + selectedProducts: string[]; + bomCalculations?: BOMCalculationRow[]; + + // 자동 산출 설정 + autoCalculationSettings?: { + productId?: string; + productCategory?: string; + openSizeWidth?: number; + openSizeHeight?: number; + guideRailInstallType?: string; + motorPower?: string; + controller?: string; + quantity?: number; + }; +} + +// 수식 인터페이스 (FormulaManagement2.tsx) +interface Formula { + id: string; + product: string; // 공통 또는 특정 제품 + category: string; // 카테고리 + name: string; // 수식 이름 + variable: string; // 변수명 + formula: string; // 수식 + type: "calculation" | "range" | "mapping" | "input"; + ranges?: RangeItem[]; // 범위별 규칙 + outputType?: "variable" | "item"; // 결과 출력 타입 + items?: FormulaItem[]; // 품목 목록 +} + +// BOM 계산 행 +interface BOMCalculationRow { + id: string; + itemCode: string; + itemName: string; + baseQuantity: number; + calculatedQuantity: number; + unit: string; + unitPrice: number; + totalPrice: number; + formula?: string; + formulaCategory?: string; +} +``` + +### 5.3 주요 유틸리티 + +```typescript +// 수식 평가 (formulaEvaluator.ts) +validateFormula(formula: string): boolean +evaluateFormula(formula: string, variables: Record): number +extractVariables(formula: string): string[] + +// 샘플 데이터 (sampleQuoteData_Complete.ts) +generateCompleteSampleQuoteData(): QuoteData[] + +// BOM 추가 (addProductBoms.ts) +addProductBoms(products: Product[]): ProductWithBom[] +``` + +--- + +## 6. 데이터 흐름 + +### 6.1 견적 생성 흐름 + +``` +1. 기본 정보 입력 + └─> 발주처, 현장명, 담당자, 연락처, 납기일 + +2. 자동 견적 산출 설정 + └─> 제품 선택, 오픈사이즈 입력, 가이드레일/모터/제어기 선택 + +3. 수식 기반 자동 산출 + └─> FormulaManagement2의 수식 순차 실행 + └─> 제작사이즈(W1, H1), 면적(M), 중량(K) 등 계산 + +4. BOM 계산 + └─> 품목별 수량 계산 (수식 적용) + └─> 단가 조회 및 금액 계산 + +5. 견적서 생성 + └─> 번호기준관리 규칙으로 견적번호 자동 생성 + └─> 상태: 최초작성 + +6. 수정/확정 + └─> 수정 시 리비전 증가 (최초작성 → 1차수정 → 2차수정) + └─> 최종확정 시 수정 불가 + └─> 수주전환 시 수주 데이터 생성 +``` + +### 6.2 수식 실행 순서 + +``` +카테고리 순서대로 실행: +1. 기본정보 (PC, W0, H0, GT, MP, CT, QTY, WS, INSP) +2. 제작사이즈 (W1 = W0 + 140, H1 = H0 + 350) +3. 면적 (M = W1 * H1 / 1000000) +4. 모터용량산출 (용량 = 범위별 계산) +5. 감기사프트 +6. 브라켓&받침용영역 +7. 가이드레일 +8. 가이드레일설치유형 +9. 셔터박스 +10. 하단마감재 +``` + +--- + +## 7. API 연동 가이드 (향후 개발용) + +### 7.1 필요한 API 엔드포인트 + +``` +# 견적 관리 +GET /api/v1/quotes # 견적 목록 +POST /api/v1/quotes # 견적 생성 +GET /api/v1/quotes/{id} # 견적 상세 +PUT /api/v1/quotes/{id} # 견적 수정 +DELETE /api/v1/quotes/{id} # 견적 삭제 +POST /api/v1/quotes/{id}/finalize # 최종 확정 +POST /api/v1/quotes/{id}/convert # 수주 전환 + +# 자동 산출 +POST /api/v1/quotes/calculate # 자동 산출 실행 +GET /api/v1/quotes/{id}/bom # BOM 결과 조회 + +# 수식 관리 +GET /api/v1/formulas # 수식 목록 +POST /api/v1/formulas # 수식 생성 +PUT /api/v1/formulas/{id} # 수식 수정 +DELETE /api/v1/formulas/{id} # 수식 삭제 + +# 번호 기준 관리 +GET /api/v1/lot-rules # 번호규칙 목록 +POST /api/v1/lot-rules # 번호규칙 생성 +POST /api/v1/lot-rules/{id}/generate # 번호 생성 +``` + +### 7.2 데이터베이스 스키마 (예상) + +```sql +-- 견적 테이블 +CREATE TABLE quotes ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + quote_number VARCHAR(50) UNIQUE, + status ENUM('draft', 'sent', 'approved', 'rejected', 'converted', 'finalized'), + client_id BIGINT, + site_id BIGINT, + manager VARCHAR(100), + contact VARCHAR(50), + receipt_date DATE, + completion_date DATE, + total_amount DECIMAL(15,2), + discount_rate DECIMAL(5,2), + final_amount DECIMAL(15,2), + current_revision INT DEFAULT 0, + is_final BOOLEAN DEFAULT FALSE, + remarks TEXT, + created_by BIGINT, + updated_by BIGINT, + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP +); + +-- 견적 품목 테이블 +CREATE TABLE quote_items ( + id BIGINT PRIMARY KEY, + quote_id BIGINT NOT NULL, + item_code VARCHAR(50), + item_name VARCHAR(200), + specification VARCHAR(100), + quantity DECIMAL(10,4), + unit VARCHAR(20), + unit_price DECIMAL(15,2), + total_price DECIMAL(15,2), + formula VARCHAR(500), + formula_category VARCHAR(100), + sort_order INT, + created_at TIMESTAMP, + updated_at TIMESTAMP +); + +-- 견적 자동산출 설정 +CREATE TABLE quote_calculation_settings ( + id BIGINT PRIMARY KEY, + quote_id BIGINT NOT NULL, + product_id BIGINT, + product_category VARCHAR(50), + open_size_width INT, + open_size_height INT, + guide_rail_type VARCHAR(50), + motor_power VARCHAR(50), + controller VARCHAR(50), + quantity INT, + edge_wing_size INT, + inspection_fee DECIMAL(10,2), + created_at TIMESTAMP, + updated_at TIMESTAMP +); + +-- 수식 테이블 +CREATE TABLE formulas ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + product_id BIGINT, -- NULL = 공통 + category VARCHAR(100), + name VARCHAR(200), + variable VARCHAR(50), + formula TEXT, + type ENUM('calculation', 'range', 'mapping', 'input'), + output_type ENUM('variable', 'item'), + description TEXT, + sort_order INT, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP, + updated_at TIMESTAMP, + deleted_at TIMESTAMP +); + +-- 번호 기준 규칙 +CREATE TABLE lot_number_rules ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + rule_name VARCHAR(100), + apply_to JSON, -- ['quote', 'salesOrder', 'production', 'shipping', 'purchase'] + prefix VARCHAR(20), + separator VARCHAR(5), + use_date BOOLEAN DEFAULT TRUE, + date_format VARCHAR(20), + sequence_digits INT, + is_active BOOLEAN DEFAULT TRUE, + description TEXT, + created_at TIMESTAMP, + updated_at TIMESTAMP +); +``` + +--- + +## 8. 참고 자료 + +### 8.1 이미지 분석 폴더 구조 + +``` +docs/data/견적/ +├── 견적산출_Flow.pdf # 전체 플로우 다이어그램 +├── 견적관리 목록/ # 목록 화면 +│ ├── 견적관리_목록.png +│ ├── 견적관리_목록_테이블 수정모드.png +│ ├── 견적관리_목록_상태별 탭 처리.png +│ ├── 일괄삭제.png +│ └── 개별삭제.png +├── 견적관리목록/ # 등록 화면 +│ ├── 견적등록 (3컬럼).png +│ ├── 거래처 선택.png +│ ├── 현장명 선택.png +│ ├── 자동 산출 결과 리스트.png +│ ├── 다중 견적 산출 시.png +│ └── 필수 항목 벨리데이션 체크.png +├── 견적상세/ # 상세 화면 +│ ├── 견적관리_상세 (3컬럼).png +│ ├── 견적서.png +│ └── 견적산출내역서.png +├── 기준정보_견적수식관리/ # 수식 관리 +│ ├── 기준정보_견적수식관리_품목수식관리 섹션.png +│ ├── 수식추가.png +│ ├── 수식 수정.png +│ ├── 카테고리 추가.png +│ ├── 계산식_품목.png +│ ├── 계산식_변수.png +│ └── 입력값.png +├── 단가분류관리/ # 단가 분류 +│ └── 기준정보_견적수식관리_단가계산분류관리섹션.png +├── 단가수식관리/ # 단가 수식 +│ └── AppContent.png +└── 번호기준관리/ # 번호 규칙 + ├── 기준정보_번호기준관리_목록.png + └── 기준정보_번호기준관리_상세.png +``` + +### 8.2 관련 문서 + +- `design/src/QUOTE_AUTO_CALCULATION_GUIDE.md` - 자동 산출 가이드 +- `design/src/FORMULA_MANAGEMENT_GUIDE.md` - 수식 관리 가이드 +- `design/src/ERP_QUOTATION_GUIDE.md` - ERP 견적 가이드 + +--- + +## 9. 개발 체크리스트 + +### 9.1 API 개발 체크리스트 + +- [ ] 견적 CRUD API 구현 +- [ ] 자동 산출 API 구현 +- [ ] BOM 계산 API 구현 +- [ ] 수식 관리 API 구현 +- [ ] 번호 기준 관리 API 구현 +- [ ] 견적서 PDF 생성 API 구현 +- [ ] 수주 전환 API 구현 + +### 9.2 프론트엔드 연동 체크리스트 + +- [ ] API 클라이언트 설정 +- [ ] DataContext API 연동 +- [ ] 견적 목록 API 연동 +- [ ] 견적 등록/수정 API 연동 +- [ ] 자동 산출 API 연동 +- [ ] 수식 관리 API 연동 +- [ ] 번호 기준 API 연동 + +--- + +*문서 작성일: 2025-12-04* +*버전: 1.0* diff --git a/data/견적/기준정보_견적수식관리/MES Solution Website Structure 251129.png b/data/견적/기준정보_견적수식관리/MES Solution Website Structure 251129.png new file mode 100644 index 0000000..c1f287a Binary files /dev/null and b/data/견적/기준정보_견적수식관리/MES Solution Website Structure 251129.png differ diff --git a/data/견적/기준정보_견적수식관리/결과 출력 방식.png b/data/견적/기준정보_견적수식관리/결과 출력 방식.png new file mode 100644 index 0000000..738c8c8 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/결과 출력 방식.png differ diff --git a/data/견적/기준정보_견적수식관리/계산식_변수.png b/data/견적/기준정보_견적수식관리/계산식_변수.png new file mode 100644 index 0000000..13b39b9 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/계산식_변수.png differ diff --git a/data/견적/기준정보_견적수식관리/계산식_품목-1.png b/data/견적/기준정보_견적수식관리/계산식_품목-1.png new file mode 100644 index 0000000..aebd9e2 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/계산식_품목-1.png differ diff --git a/data/견적/기준정보_견적수식관리/계산식_품목-2.png b/data/견적/기준정보_견적수식관리/계산식_품목-2.png new file mode 100644 index 0000000..2836801 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/계산식_품목-2.png differ diff --git a/data/견적/기준정보_견적수식관리/계산식_품목-3.png b/data/견적/기준정보_견적수식관리/계산식_품목-3.png new file mode 100644 index 0000000..d912db2 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/계산식_품목-3.png differ diff --git a/data/견적/기준정보_견적수식관리/계산식_품목-4.png b/data/견적/기준정보_견적수식관리/계산식_품목-4.png new file mode 100644 index 0000000..6b4b394 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/계산식_품목-4.png differ diff --git a/data/견적/기준정보_견적수식관리/계산식_품목.png b/data/견적/기준정보_견적수식관리/계산식_품목.png new file mode 100644 index 0000000..e4464fb Binary files /dev/null and b/data/견적/기준정보_견적수식관리/계산식_품목.png differ diff --git a/data/견적/기준정보_견적수식관리/기준정보_견적수식관리_품목수식관리 섹션.png b/data/견적/기준정보_견적수식관리/기준정보_견적수식관리_품목수식관리 섹션.png new file mode 100644 index 0000000..ff698bf Binary files /dev/null and b/data/견적/기준정보_견적수식관리/기준정보_견적수식관리_품목수식관리 섹션.png differ diff --git a/data/견적/기준정보_견적수식관리/기준정보_견적수식관리_품목수식관리 섹션_카테고리 수정.png b/data/견적/기준정보_견적수식관리/기준정보_견적수식관리_품목수식관리 섹션_카테고리 수정.png new file mode 100644 index 0000000..81c2f7a Binary files /dev/null and b/data/견적/기준정보_견적수식관리/기준정보_견적수식관리_품목수식관리 섹션_카테고리 수정.png differ diff --git a/data/견적/기준정보_견적수식관리/수식 수정-1.png b/data/견적/기준정보_견적수식관리/수식 수정-1.png new file mode 100644 index 0000000..08226ca Binary files /dev/null and b/data/견적/기준정보_견적수식관리/수식 수정-1.png differ diff --git a/data/견적/기준정보_견적수식관리/수식 수정-2.png b/data/견적/기준정보_견적수식관리/수식 수정-2.png new file mode 100644 index 0000000..181e7e0 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/수식 수정-2.png differ diff --git a/data/견적/기준정보_견적수식관리/수식 수정.png b/data/견적/기준정보_견적수식관리/수식 수정.png new file mode 100644 index 0000000..6fe408b Binary files /dev/null and b/data/견적/기준정보_견적수식관리/수식 수정.png differ diff --git a/data/견적/기준정보_견적수식관리/수식 카테고리 목록.png b/data/견적/기준정보_견적수식관리/수식 카테고리 목록.png new file mode 100644 index 0000000..ba18ba8 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/수식 카테고리 목록.png differ diff --git a/data/견적/기준정보_견적수식관리/수식추가.png b/data/견적/기준정보_견적수식관리/수식추가.png new file mode 100644 index 0000000..50f69e8 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/수식추가.png differ diff --git a/data/견적/기준정보_견적수식관리/입력값.png b/data/견적/기준정보_견적수식관리/입력값.png new file mode 100644 index 0000000..546f4d3 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/입력값.png differ diff --git a/data/견적/기준정보_견적수식관리/카테고리 추가.png b/data/견적/기준정보_견적수식관리/카테고리 추가.png new file mode 100644 index 0000000..2e251f6 Binary files /dev/null and b/data/견적/기준정보_견적수식관리/카테고리 추가.png differ diff --git a/data/견적/단가분류관리/MES Solution Website Structure 251131.png b/data/견적/단가분류관리/MES Solution Website Structure 251131.png new file mode 100644 index 0000000..5c04c29 Binary files /dev/null and b/data/견적/단가분류관리/MES Solution Website Structure 251131.png differ diff --git a/data/견적/단가분류관리/MES Solution Website Structure 251132.png b/data/견적/단가분류관리/MES Solution Website Structure 251132.png new file mode 100644 index 0000000..78ca869 Binary files /dev/null and b/data/견적/단가분류관리/MES Solution Website Structure 251132.png differ diff --git a/data/견적/단가분류관리/MES Solution Website Structure 251133.png b/data/견적/단가분류관리/MES Solution Website Structure 251133.png new file mode 100644 index 0000000..e757c2a Binary files /dev/null and b/data/견적/단가분류관리/MES Solution Website Structure 251133.png differ diff --git a/data/견적/단가분류관리/기준정보_견적수식관리_단가계산분류관리섹션.png b/data/견적/단가분류관리/기준정보_견적수식관리_단가계산분류관리섹션.png new file mode 100644 index 0000000..eaee57d Binary files /dev/null and b/data/견적/단가분류관리/기준정보_견적수식관리_단가계산분류관리섹션.png differ diff --git a/data/견적/단가수식관리/AppContent.png b/data/견적/단가수식관리/AppContent.png new file mode 100644 index 0000000..f8d9154 Binary files /dev/null and b/data/견적/단가수식관리/AppContent.png differ diff --git a/data/견적/단가수식관리/MES Solution Website Structure 251137.png b/data/견적/단가수식관리/MES Solution Website Structure 251137.png new file mode 100644 index 0000000..df0f6e7 Binary files /dev/null and b/data/견적/단가수식관리/MES Solution Website Structure 251137.png differ diff --git a/data/견적/단가수식관리/MES Solution Website Structure 251138.png b/data/견적/단가수식관리/MES Solution Website Structure 251138.png new file mode 100644 index 0000000..5a97efb Binary files /dev/null and b/data/견적/단가수식관리/MES Solution Website Structure 251138.png differ diff --git a/data/견적/단가수식관리/MES Solution Website Structure 251139.png b/data/견적/단가수식관리/MES Solution Website Structure 251139.png new file mode 100644 index 0000000..72ee95a Binary files /dev/null and b/data/견적/단가수식관리/MES Solution Website Structure 251139.png differ diff --git a/data/견적/단가수식관리/MES Solution Website Structure 251140.png b/data/견적/단가수식관리/MES Solution Website Structure 251140.png new file mode 100644 index 0000000..7459ef4 Binary files /dev/null and b/data/견적/단가수식관리/MES Solution Website Structure 251140.png differ diff --git a/data/견적/단가수식관리/Primitive.div.png b/data/견적/단가수식관리/Primitive.div.png new file mode 100644 index 0000000..62050ab Binary files /dev/null and b/data/견적/단가수식관리/Primitive.div.png differ diff --git a/data/견적/번호기준관리/MES Solution Website Structure 251128.png b/data/견적/번호기준관리/MES Solution Website Structure 251128.png new file mode 100644 index 0000000..23f90e1 Binary files /dev/null and b/data/견적/번호기준관리/MES Solution Website Structure 251128.png differ diff --git a/data/견적/번호기준관리/기준정보_번호기준관리_목록.png b/data/견적/번호기준관리/기준정보_번호기준관리_목록.png new file mode 100644 index 0000000..0782e9c Binary files /dev/null and b/data/견적/번호기준관리/기준정보_번호기준관리_목록.png differ diff --git a/data/견적/번호기준관리/기준정보_번호기준관리_상세.png b/data/견적/번호기준관리/기준정보_번호기준관리_상세.png new file mode 100644 index 0000000..3372f43 Binary files /dev/null and b/data/견적/번호기준관리/기준정보_번호기준관리_상세.png differ diff --git a/features/boards/README.md b/features/boards/README.md new file mode 100644 index 0000000..13156a2 --- /dev/null +++ b/features/boards/README.md @@ -0,0 +1,37 @@ +# 게시판 시스템 + +> 📌 SAM 프로젝트의 시스템/테넌트 게시판 기능 + +## 문서 목록 + +| 문서 | 설명 | 대상 | +|------|------|------| +| [시스템 스펙](../../specs/board-system-spec.md) | 게시판 전체 설계 스펙 | 설계 참고 | +| [MNG 구현](./mng-implementation.md) | MNG 관리자 패널 구현 상세 | MNG 개발 | + +## 개요 + +- **MNG**: 시스템 게시판 생성/관리 (`is_system=true`, `tenant_id=null`) +- **API**: 테넌트 게시판 생성 + 시스템 게시판 조회 (`is_system=false`, `tenant_id={tenant}`) + +## 빠른 참조 + +### 데이터베이스 +- `boards` - 게시판 정의 +- `board_settings` - 커스텀 필드 정의 +- `posts` - 게시글 +- `comments` - 댓글 + +### 주요 API +- `GET /api/v1/boards` - 게시판 목록 (시스템 + 테넌트) +- `POST /api/v1/boards/{code}/posts` - 게시글 작성 +- `GET /api/v1/boards/{code}/fields` - 커스텀 필드 목록 + +### MNG 라우트 +- `/boards` - 게시판 목록 +- `/boards/create` - 게시판 생성 +- `/boards/{id}/edit` - 게시판 수정 + +--- + +[← 메인 인덱스로](../../INDEX.md) diff --git a/features/boards/mng-implementation.md b/features/boards/mng-implementation.md new file mode 100644 index 0000000..4f8d065 --- /dev/null +++ b/features/boards/mng-implementation.md @@ -0,0 +1,248 @@ +# 게시판 관리 시스템 + +## 개요 + +SAM 프로젝트의 게시판 관리 시스템은 **MNG(상위 관리자)**와 **API(테넌트)**에서 각각 다른 역할로 운영됩니다. + +| 구분 | 역할 | 게시판 유형 | +|------|------|-------------| +| **MNG** | 시스템 게시판 생성/관리 | `is_system=true`, `tenant_id=null` | +| **API** | 테넌트 게시판 생성 + 시스템 게시판 조회 | `is_system=false`, `tenant_id={tenant}` | + +## 아키텍처 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ MNG (상위 관리자) │ +│ - 시스템 게시판 CRUD │ +│ - 커스텀 필드 관리 │ +│ - 모든 테넌트에서 접근 가능한 공용 게시판 │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ boards 테이블 │ +│ - is_system: boolean (시스템/테넌트 구분) │ +│ - tenant_id: nullable (시스템은 null) │ +│ - board_type: varchar(50) - 자유 입력 │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ API (테넌트) │ +│ - 시스템 게시판 조회 (읽기 전용) │ +│ - 테넌트 게시판 CRUD │ +│ - 게시글/댓글 CRUD │ +└─────────────────────────────────────────────────────────────┘ +``` + +## 데이터베이스 스키마 + +### boards 테이블 + +| 컬럼 | 타입 | 설명 | +|------|------|------| +| id | bigint | PK | +| tenant_id | bigint | FK (nullable - 시스템 게시판은 null) | +| is_system | boolean | 시스템 게시판 여부 (default: false) | +| board_type | varchar(50) | 게시판 유형 (notice, qna, faq 등 자유 입력) | +| board_code | varchar(50) | 게시판 코드 (unique per tenant) | +| name | varchar(100) | 게시판명 | +| description | text | 설명 | +| editor_type | enum | wysiwyg, markdown, text | +| allow_files | boolean | 파일 첨부 허용 | +| max_file_count | int | 최대 파일 수 | +| max_file_size | int | 최대 파일 크기 (KB) | +| extra_settings | json | 추가 설정 | +| is_active | boolean | 활성 상태 | +| deleted_at | timestamp | Soft Delete | + +### board_settings 테이블 (커스텀 필드) + +| 컬럼 | 타입 | 설명 | +|------|------|------| +| id | bigint | PK | +| board_id | bigint | FK → boards | +| name | varchar(100) | 필드명 (한글 라벨) | +| field_key | varchar(50) | 필드 키 (영문, 스네이크케이스) | +| field_type | varchar(20) | text, textarea, number, date, select 등 | +| is_required | boolean | 필수 여부 | +| sort_order | int | 정렬 순서 | +| options | json | 선택형 필드의 옵션 값 | + +## MNG 구현 + +### 파일 구조 + +``` +mng/ +├── app/ +│ ├── Http/Controllers/ +│ │ ├── BoardController.php # Blade 컨트롤러 +│ │ └── Api/Admin/BoardController.php # API 컨트롤러 +│ ├── Models/Boards/ +│ │ ├── Board.php +│ │ └── BoardSetting.php +│ └── Services/ +│ └── BoardService.php +├── resources/views/boards/ +│ ├── index.blade.php +│ ├── create.blade.php +│ ├── edit.blade.php +│ └── partials/table.blade.php +└── routes/ + ├── web.php # Blade 라우트 + └── api.php # API 라우트 +``` + +### 라우트 + +#### Web 라우트 (Blade) + +| Method | URI | Name | 설명 | +|--------|-----|------|------| +| GET | /boards | boards.index | 목록 | +| GET | /boards/create | boards.create | 생성 폼 | +| GET | /boards/{id}/edit | boards.edit | 수정 폼 | + +#### API 라우트 (HTMX/Ajax) + +| Method | URI | 설명 | +|--------|-----|------| +| GET | /api/admin/boards | 목록 (페이지네이션) | +| POST | /api/admin/boards | 생성 | +| GET | /api/admin/boards/{id} | 상세 | +| PUT | /api/admin/boards/{id} | 수정 | +| DELETE | /api/admin/boards/{id} | 삭제 | +| 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} | 커스텀 필드 삭제 | + +### 커스텀 필드 모달 + +다중 필드 추가 기능: +- 한 줄에 필드명, 필드키, 타입, 필수 체크박스 배치 +- `+ 필드 추가` 버튼으로 행 추가 +- X 버튼으로 행 삭제 +- 여러 필드 일괄 저장 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 필드 추가 │ +├─────────────────────────────────────────────────────────────┤ +│ 필드명* 필드키* 타입* 필수 삭제 │ +│ [카테고리] [category] [선택 ▼] [✓] [X] │ +│ [작성자] [author] [텍스트 ▼] [ ] [X] │ +├─────────────────────────────────────────────────────────────┤ +│ ┌─────────────────────────┐ │ +│ │ + 필드 추가 │ │ +│ └─────────────────────────┘ │ +│ * 필드 키: 영문 소문자와 언더스코어만 사용 │ +├─────────────────────────────────────────────────────────────┤ +│ [취소] [저장] │ +└─────────────────────────────────────────────────────────────┘ +``` + +## API 구현 (테넌트용) + +### 파일 구조 + +``` +api/ +├── app/ +│ ├── Http/Controllers/Api/V1/ +│ │ ├── BoardController.php +│ │ └── PostController.php +│ ├── Http/Requests/Boards/ +│ │ ├── BoardStoreRequest.php +│ │ ├── BoardUpdateRequest.php +│ │ ├── PostStoreRequest.php +│ │ ├── PostUpdateRequest.php +│ │ └── CommentStoreRequest.php +│ └── Services/Boards/ +│ └── PostService.php +├── app/Swagger/v1/ +│ ├── BoardApi.php +│ └── PostApi.php +└── routes/api.php +``` + +### API 엔드포인트 + +#### 게시판 API + +| Method | URI | 설명 | +|--------|-----|------| +| GET | /api/v1/boards | 접근 가능한 게시판 목록 (시스템 + 테넌트) | +| GET | /api/v1/boards/tenant | 테넌트 게시판만 | +| POST | /api/v1/boards | 테넌트 게시판 생성 | +| GET | /api/v1/boards/{code} | 게시판 상세 (코드 기반) | +| PUT | /api/v1/boards/{id} | 테넌트 게시판 수정 | +| DELETE | /api/v1/boards/{id} | 테넌트 게시판 삭제 | +| GET | /api/v1/boards/{code}/fields | 커스텀 필드 목록 | + +#### 게시글 API + +| Method | URI | 설명 | +|--------|-----|------| +| GET | /api/v1/boards/{code}/posts | 게시글 목록 | +| POST | /api/v1/boards/{code}/posts | 게시글 작성 | +| GET | /api/v1/boards/{code}/posts/{id} | 게시글 상세 | +| PUT | /api/v1/boards/{code}/posts/{id} | 게시글 수정 | +| DELETE | /api/v1/boards/{code}/posts/{id} | 게시글 삭제 | + +#### 댓글 API + +| Method | URI | 설명 | +|--------|-----|------| +| GET | /api/v1/boards/{code}/posts/{postId}/comments | 댓글 목록 | +| POST | /api/v1/boards/{code}/posts/{postId}/comments | 댓글 작성 | +| PUT | /api/v1/boards/{code}/posts/{postId}/comments/{commentId} | 댓글 수정 | +| DELETE | /api/v1/boards/{code}/posts/{postId}/comments/{commentId} | 댓글 삭제 | + +## 접근 권한 로직 + +```php +// 게시판 목록 조회 (테넌트 API) +public function index() +{ + $tenantId = $this->tenantId(); + + // 시스템 게시판 + 해당 테넌트 게시판 + $boards = Board::where(function ($q) use ($tenantId) { + $q->where('is_system', true) + ->orWhere('tenant_id', $tenantId); + }) + ->where('is_active', true) + ->get(); +} + +// 게시판 수정/삭제 (테넌트는 자신의 게시판만) +public function update($id) +{ + $board = Board::where('id', $id) + ->where('tenant_id', $this->tenantId()) + ->where('is_system', false) // 시스템 게시판 수정 불가 + ->firstOrFail(); +} +``` + +## 커스텀 필드 타입 + +| 타입 | 설명 | 옵션 | +|------|------|------| +| text | 한 줄 텍스트 | - | +| textarea | 여러 줄 텍스트 | - | +| number | 숫자 | min, max | +| date | 날짜 | - | +| select | 드롭다운 선택 | options[] | +| checkbox | 체크박스 | - | +| radio | 라디오 버튼 | options[] | +| file | 파일 첨부 | allowed_extensions | + +## 관련 문서 + +- [SAM API Rules](/SAM/API_RULES.md) +- [MNG Critical Rules](/SAM/mng/docs/MNG_CRITICAL_RULES.md) +- [Board System Spec](/SAM/docs/specs/board-system-spec.md) diff --git a/front/[API-2025-12-04] client-api-analysis.md b/front/[API-2025-12-04] client-api-analysis.md new file mode 100644 index 0000000..52358e9 --- /dev/null +++ b/front/[API-2025-12-04] client-api-analysis.md @@ -0,0 +1,294 @@ +# 거래처 관리 API 분석 + +> **작성일**: 2025-12-04 +> **목적**: sam-api 백엔드 Client API와 프론트엔드 거래처 관리 페이지 간 연동 분석 + +--- + +## 1. 현재 상태 요약 + +### 프론트엔드 (sam-react-prod) +- **파일**: `src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx` +- **상태**: ❌ **API 미연동** - 로컬 샘플 데이터(`SAMPLE_CUSTOMERS`)로만 동작 +- **모든 CRUD가 클라이언트 사이드에서만 수행됨** + +### 백엔드 (sam-api) +- **컨트롤러**: `app/Http/Controllers/Api/V1/ClientController.php` +- **서비스**: `app/Services/ClientService.php` +- **모델**: `app/Models/Orders/Client.php` +- **상태**: ✅ **API 구현 완료** - 모든 CRUD 기능 제공 + +--- + +## 2. 백엔드 API 명세 + +### 2.1 Client (거래처) API + +| Method | Endpoint | 설명 | 인증 | +|--------|----------|------|------| +| `GET` | `/api/v1/clients` | 목록 조회 (페이지네이션, 검색) | ✅ Required | +| `GET` | `/api/v1/clients/{id}` | 단건 조회 | ✅ Required | +| `POST` | `/api/v1/clients` | 생성 | ✅ Required | +| `PUT` | `/api/v1/clients/{id}` | 수정 | ✅ Required | +| `DELETE` | `/api/v1/clients/{id}` | 삭제 | ✅ Required | +| `PATCH` | `/api/v1/clients/{id}/toggle` | 활성/비활성 토글 | ✅ Required | + +### 2.2 Client Group (거래처 그룹) API + +| Method | Endpoint | 설명 | 인증 | +|--------|----------|------|------| +| `GET` | `/api/v1/client-groups` | 그룹 목록 | ✅ Required | +| `GET` | `/api/v1/client-groups/{id}` | 그룹 단건 | ✅ Required | +| `POST` | `/api/v1/client-groups` | 그룹 생성 | ✅ Required | +| `PUT` | `/api/v1/client-groups/{id}` | 그룹 수정 | ✅ Required | +| `DELETE` | `/api/v1/client-groups/{id}` | 그룹 삭제 | ✅ Required | +| `PATCH` | `/api/v1/client-groups/{id}/toggle` | 그룹 활성/비활성 | ✅ Required | + +### 2.3 목록 조회 파라미터 (`GET /api/v1/clients`) + +| 파라미터 | 타입 | 설명 | 기본값 | +|---------|------|------|--------| +| `page` | integer | 페이지 번호 | 1 | +| `size` | integer | 페이지당 개수 | 20 | +| `q` | string | 검색어 (이름, 코드, 담당자) | - | +| `only_active` | boolean | 활성 거래처만 조회 | - | + +--- + +## 3. 데이터 모델 비교 + +### 3.1 필드 매핑 분석 + +| 프론트엔드 필드 | 백엔드 필드 | 상태 | 비고 | +|---------------|------------|------|------| +| `id` | `id` | ✅ 동일 | | +| `code` | `client_code` | ✅ 매핑 필요 | 필드명 변경 | +| `name` | `name` | ✅ 동일 | | +| `representative` | `contact_person` | ✅ 매핑 필요 | 필드명 변경 | +| `phone` | `phone` | ✅ 동일 | | +| `email` | `email` | ✅ 동일 | | +| `address` | `address` | ✅ 동일 | | +| `registeredDate` | `created_at` | ✅ 매핑 필요 | 필드명 변경 | +| `status` | `is_active` | ✅ 매핑 필요 | "활성"/"비활성" ↔ "Y"/"N" | +| `businessNo` | - | ❌ **백엔드 없음** | 추가 필요 | +| `businessType` | - | ❌ **백엔드 없음** | 추가 필요 | +| `businessItem` | - | ❌ **백엔드 없음** | 추가 필요 | +| - | `tenant_id` | ✅ 백엔드 전용 | 자동 처리 | +| - | `client_group_id` | ⚠️ 프론트 없음 | 그룹 기능 미구현 | + +### 3.2 백엔드 모델 필드 (Client.php) + +```php +protected $fillable = [ + 'tenant_id', + 'client_group_id', + 'client_code', // 거래처 코드 + 'name', // 거래처명 + 'contact_person', // 담당자 + 'phone', // 전화번호 + 'email', // 이메일 + 'address', // 주소 + 'is_active', // 활성 상태 (Y/N) +]; +``` + +--- + +## 4. 백엔드 수정 요청 사항 + +### 4.1 Client 모델 필드 추가 요청 + +```markdown +## 백엔드 API 수정 요청 + +### 파일 위치 +`app/Models/Orders/Client.php` - Client 모델 + +### 현재 문제 +프론트엔드에서 사용하는 사업자 정보 필드가 백엔드에 없음 + +### 수정 요청 +다음 필드를 Client 모델에 추가: + +| 필드명 | 타입 | 설명 | nullable | +|--------|------|------|----------| +| `business_no` | string(20) | 사업자등록번호 | nullable | +| `business_type` | string(50) | 업태 | nullable | +| `business_item` | string(100) | 업종 | nullable | + +### 마이그레이션 예시 +```sql +ALTER TABLE clients ADD COLUMN business_no VARCHAR(20) NULL; +ALTER TABLE clients ADD COLUMN business_type VARCHAR(50) NULL; +ALTER TABLE clients ADD COLUMN business_item VARCHAR(100) NULL; +``` +``` + +--- + +## 5. 프론트엔드 API 연동 구현 계획 + +### 5.1 필요한 작업 + +| # | 작업 | 우선순위 | 상태 | +|---|------|---------|------| +| 1 | Next.js API Proxy 생성 (`/api/proxy/clients/[...path]`) | 🔴 HIGH | ⬜ 미완료 | +| 2 | 커스텀 훅 생성 (`useClientList`) | 🔴 HIGH | ⬜ 미완료 | +| 3 | 타입 정의 업데이트 (`CustomerAccount` → API 응답 매핑) | 🟡 MEDIUM | ⬜ 미완료 | +| 4 | CRUD 함수를 API 호출로 변경 | 🔴 HIGH | ⬜ 미완료 | +| 5 | 거래처 그룹 기능 추가 (선택) | 🟢 LOW | ⬜ 미완료 | + +### 5.2 API Proxy 구현 패턴 + +```typescript +// /src/app/api/proxy/clients/route.ts +import { NextRequest, NextResponse } from 'next/server'; + +const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL; + +export async function GET(request: NextRequest) { + const token = request.cookies.get('access_token')?.value; + const searchParams = request.nextUrl.searchParams; + + const response = await fetch( + `${BACKEND_URL}/api/v1/clients?${searchParams.toString()}`, + { + headers: { + 'Authorization': `Bearer ${token}`, + 'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY || '', + }, + } + ); + + return NextResponse.json(await response.json()); +} +``` + +### 5.3 useClientList 훅 구현 패턴 + +```typescript +// /src/hooks/useClientList.ts +export function useClientList() { + const [clients, setClients] = useState([]); + const [pagination, setPagination] = useState(null); + const [isLoading, setIsLoading] = useState(false); + + const fetchClients = async (params: FetchParams) => { + setIsLoading(true); + const searchParams = new URLSearchParams({ + page: String(params.page || 1), + size: String(params.size || 20), + ...(params.q && { q: params.q }), + ...(params.onlyActive !== undefined && { only_active: String(params.onlyActive) }), + }); + + const response = await fetch(`/api/proxy/clients?${searchParams}`); + const data = await response.json(); + + setClients(data.data.data); + setPagination({ + currentPage: data.data.current_page, + lastPage: data.data.last_page, + total: data.data.total, + }); + setIsLoading(false); + }; + + return { clients, pagination, isLoading, fetchClients }; +} +``` + +--- + +## 6. 데이터 변환 유틸리티 + +### 6.1 API 응답 → 프론트엔드 타입 변환 + +```typescript +// API 응답 타입 +interface ClientApiResponse { + id: number; + client_code: string; + name: string; + contact_person: string | null; + phone: string | null; + email: string | null; + address: string | null; + is_active: 'Y' | 'N'; + created_at: string; + updated_at: string; +} + +// 프론트엔드 타입으로 변환 +function transformClient(api: ClientApiResponse): CustomerAccount { + return { + id: String(api.id), + code: api.client_code, + name: api.name, + representative: api.contact_person || '', + phone: api.phone || '', + email: api.email || '', + address: api.address || '', + businessNo: '', // TODO: 백엔드 필드 추가 후 매핑 + businessType: '', // TODO: 백엔드 필드 추가 후 매핑 + businessItem: '', // TODO: 백엔드 필드 추가 후 매핑 + registeredDate: api.created_at.split(' ')[0], + status: api.is_active === 'Y' ? '활성' : '비활성', + }; +} +``` + +### 6.2 프론트엔드 → API 요청 변환 + +```typescript +function transformToApiRequest(form: FormData): ClientCreateRequest { + return { + client_code: form.code, + name: form.name, + contact_person: form.representative || null, + phone: form.phone || null, + email: form.email || null, + address: form.address || null, + is_active: 'Y', + }; +} +``` + +--- + +## 7. 결론 및 권장 사항 + +### 7.1 즉시 진행 가능 (백엔드 변경 없이) + +1. ✅ API Proxy 생성 +2. ✅ useClientList 훅 구현 +3. ✅ 기본 CRUD 연동 (현재 백엔드 필드만 사용) + +### 7.2 백엔드 변경 필요 + +1. ⚠️ `business_no`, `business_type`, `business_item` 필드 추가 +2. ⚠️ ClientService, ClientStoreRequest, ClientUpdateRequest 업데이트 +3. ⚠️ Swagger 문서 업데이트 + +### 7.3 선택적 개선 + +1. 거래처 그룹 기능 프론트엔드 구현 +2. 거래처 상세 페이지 구현 +3. 엑셀 내보내기/가져오기 기능 + +--- + +## 참고 파일 + +### 백엔드 (sam-api) +- `app/Http/Controllers/Api/V1/ClientController.php` +- `app/Http/Controllers/Api/V1/ClientGroupController.php` +- `app/Services/ClientService.php` +- `app/Services/ClientGroupService.php` +- `app/Models/Orders/Client.php` +- `app/Models/Orders/ClientGroup.php` +- `app/Swagger/v1/ClientApi.php` +- `routes/api.php` (Line 316-333) + +### 프론트엔드 (sam-react-prod) +- `src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx` \ No newline at end of file diff --git a/front/[API-2025-12-04] quote-api-request.md b/front/[API-2025-12-04] quote-api-request.md new file mode 100644 index 0000000..d3154f1 --- /dev/null +++ b/front/[API-2025-12-04] quote-api-request.md @@ -0,0 +1,605 @@ +# 견적관리 API 요청서 + +> **작성일**: 2025-12-04 +> **목적**: 견적관리 기능을 위한 백엔드 API 요청 +> **참조**: sam-design/QuoteManagement3Write.tsx, QuoteManagement3Detail.tsx + +--- + +## 1. 개요 + +### 1.1 기능 요약 +견적관리 시스템은 다음 기능을 지원해야 합니다: +- 견적 CRUD (등록, 조회, 수정, 삭제) +- 견적 상태 관리 (임시저장 → 확정 → 수주전환) +- 견적 수정 이력 관리 (버전 관리) +- 견적 품목(BOM) 관리 +- 자동 견적 산출 (수식 기반 계산) ← **백엔드 구현** + +### 1.2 특이사항 +- **자동 견적 산출 로직**은 백엔드에서 구현 예정 (수식 계산 엔진) +- 프론트엔드는 입력값을 전달하고 계산 결과를 받아서 표시 + +--- + +## 2. 데이터 모델 + +### 2.1 Quote (견적) - 메인 엔티티 + +```typescript +interface Quote { + // === 기본 정보 === + id: number; + tenant_id: number; + quote_number: string; // 견적번호 (예: KD-SC-251204-01) + registration_date: string; // 등록일 (YYYY-MM-DD) + receipt_date: string; // 접수일 + author: string; // 작성자 + + // === 발주처 정보 === + client_id: number | null; // 거래처 ID (FK) + client_name: string; // 거래처명 (직접입력 대응) + manager: string | null; // 담당자 + contact: string | null; // 연락처 + + // === 현장 정보 === + site_id: number | null; // 현장 ID (FK, 별도 테이블 필요시) + site_name: string | null; // 현장명 + site_code: string | null; // 현장코드 + + // === 제품 정보 === + product_category: 'SCREEN' | 'STEEL'; // 제품 카테고리 + product_id: number | null; // 선택된 제품 ID (품목마스터 FK) + product_code: string | null; // 제품코드 + product_name: string | null; // 제품명 + + // === 규격 정보 === + open_size_width: number | null; // 오픈사이즈 폭 (mm) + open_size_height: number | null; // 오픈사이즈 높이 (mm) + quantity: number; // 수량 (기본값: 1) + unit_symbol: string | null; // 부호 + floors: string | null; // 층수 + + // === 금액 정보 === + material_cost: number; // 재료비 합계 + labor_cost: number; // 노무비 + install_cost: number; // 설치비 + subtotal: number; // 소계 + discount_rate: number; // 할인율 (%) + discount_amount: number; // 할인금액 + total_amount: number; // 최종 금액 + + // === 상태 관리 === + status: 'draft' | 'sent' | 'approved' | 'rejected' | 'finalized' | 'converted'; + current_revision: number; // 현재 수정 차수 (0부터 시작) + is_final: boolean; // 최종확정 여부 + finalized_at: string | null; // 확정일시 + finalized_by: number | null; // 확정자 ID + + // === 기타 정보 === + completion_date: string | null; // 납기일 + remarks: string | null; // 비고 + memo: string | null; // 메모 + notes: string | null; // 특이사항 + + // === 시스템 필드 === + created_at: string; + updated_at: string; + created_by: number | null; + updated_by: number | null; + deleted_at: string | null; // Soft Delete +} +``` + +### 2.2 QuoteItem (견적 품목) - BOM 계산 결과 + +```typescript +interface QuoteItem { + id: number; + quote_id: number; // 견적 ID (FK) + tenant_id: number; + + // === 품목 정보 === + item_id: number | null; // 품목마스터 ID (FK) + item_code: string; // 품목코드 + item_name: string; // 품명 + specification: string | null; // 규격 + unit: string; // 단위 + + // === 수량/금액 === + base_quantity: number; // 기본수량 + calculated_quantity: number; // 계산된 수량 + unit_price: number; // 단가 + total_price: number; // 금액 (수량 × 단가) + + // === 수식 정보 === + formula: string | null; // 수식 (예: "W/1000 + 0.1") + formula_source: string | null; // 수식 출처 (BOM템플릿, 제품BOM 등) + formula_category: string | null; // 수식 카테고리 + data_source: string | null; // 데이터 출처 + + // === 기타 === + delivery_date: string | null; // 품목별 납기일 + note: string | null; // 비고 + sort_order: number; // 정렬순서 + + created_at: string; + updated_at: string; +} +``` + +### 2.3 QuoteRevision (견적 수정 이력) + +```typescript +interface QuoteRevision { + id: number; + quote_id: number; // 견적 ID (FK) + tenant_id: number; + + revision_number: number; // 수정 차수 (1, 2, 3...) + revision_date: string; // 수정일 + revision_by: number; // 수정자 ID + revision_by_name: string; // 수정자 이름 + revision_reason: string | null; // 수정 사유 + + // 이전 버전 데이터 (JSON) + previous_data: object; // 수정 전 견적 전체 데이터 (스냅샷) + + created_at: string; +} +``` + +--- + +## 3. API 엔드포인트 + +### 3.1 견적 CRUD + +| Method | Endpoint | 설명 | 비고 | +|--------|----------|------|------| +| `GET` | `/api/v1/quotes` | 목록 조회 | 페이지네이션, 필터, 검색 | +| `GET` | `/api/v1/quotes/{id}` | 단건 조회 | 품목(items), 이력(revisions) 포함 | +| `POST` | `/api/v1/quotes` | 생성 | 품목 배열 포함 | +| `PUT` | `/api/v1/quotes/{id}` | 수정 | 수정이력 자동 생성 | +| `DELETE` | `/api/v1/quotes/{id}` | 삭제 | Soft Delete | +| `DELETE` | `/api/v1/quotes` | 일괄 삭제 | `ids[]` 파라미터 | + +### 3.2 견적 상태 관리 + +| Method | Endpoint | 설명 | 비고 | +|--------|----------|------|------| +| `PATCH` | `/api/v1/quotes/{id}/finalize` | 최종확정 | status → 'finalized', is_final → true | +| `PATCH` | `/api/v1/quotes/{id}/convert-to-order` | 수주전환 | status → 'converted', 수주 데이터 생성 | +| `PATCH` | `/api/v1/quotes/{id}/cancel-finalize` | 확정취소 | is_final → false (조건부) | + +### 3.3 자동 견적 산출 (핵심 기능) + +| Method | Endpoint | 설명 | 비고 | +|--------|----------|------|------| +| `POST` | `/api/v1/quotes/calculate` | 자동 산출 | **수식 계산 엔진** | +| `POST` | `/api/v1/quotes/{id}/recalculate` | 재계산 | 기존 견적 재산출 | + +### 3.4 견적 문서 출력 + +| Method | Endpoint | 설명 | 비고 | +|--------|----------|------|------| +| `GET` | `/api/v1/quotes/{id}/document/quote` | 견적서 PDF | | +| `GET` | `/api/v1/quotes/{id}/document/calculation` | 산출내역서 PDF | | +| `GET` | `/api/v1/quotes/{id}/document/purchase-order` | 발주서 PDF | | + +### 3.5 견적번호 생성 + +| Method | Endpoint | 설명 | 비고 | +|--------|----------|------|------| +| `GET` | `/api/v1/quotes/generate-number` | 견적번호 생성 | `?category=SCREEN` | + +--- + +## 4. 상세 API 명세 + +### 4.1 목록 조회 `GET /api/v1/quotes` + +**Query Parameters:** +``` +page: number (default: 1) +size: number (default: 20) +q: string (검색어 - 견적번호, 발주처, 담당자, 현장명) +status: string (상태 필터) +product_category: string (제품 카테고리) +client_id: number (발주처 ID) +date_from: string (등록일 시작) +date_to: string (등록일 종료) +sort_by: string (정렬 컬럼) +sort_order: 'asc' | 'desc' +``` + +**Response:** +```json +{ + "success": true, + "data": { + "current_page": 1, + "data": [ + { + "id": 1, + "quote_number": "KD-SC-251204-01", + "registration_date": "2025-12-04", + "client_name": "ABC건설", + "site_name": "강남 오피스텔 현장", + "product_category": "SCREEN", + "product_name": "전동스크린 A형", + "quantity": 10, + "total_amount": 15000000, + "status": "draft", + "current_revision": 0, + "is_final": false, + "created_at": "2025-12-04T10:00:00Z" + } + ], + "last_page": 5, + "per_page": 20, + "total": 100 + } +} +``` + +### 4.2 단건 조회 `GET /api/v1/quotes/{id}` + +**Response:** +```json +{ + "success": true, + "data": { + "id": 1, + "quote_number": "KD-SC-251204-01", + "registration_date": "2025-12-04", + "receipt_date": "2025-12-04", + "author": "김철수", + + "client_id": 10, + "client_name": "ABC건설", + "manager": "이영희", + "contact": "010-1234-5678", + + "site_id": 5, + "site_name": "강남 오피스텔 현장", + "site_code": "PJ-20251204-01", + + "product_category": "SCREEN", + "product_id": 100, + "product_code": "SCR-001", + "product_name": "전동스크린 A형", + + "open_size_width": 2000, + "open_size_height": 3000, + "quantity": 10, + "unit_symbol": "A", + "floors": "3층", + + "material_cost": 12000000, + "labor_cost": 1500000, + "install_cost": 1500000, + "subtotal": 15000000, + "discount_rate": 0, + "discount_amount": 0, + "total_amount": 15000000, + + "status": "draft", + "current_revision": 2, + "is_final": false, + + "completion_date": "2025-12-31", + "remarks": "급하게 진행 필요", + "memo": "", + "notes": "", + + "items": [ + { + "id": 1, + "item_code": "SCR-MOTOR-001", + "item_name": "스크린 모터", + "specification": "220V, 1/4HP", + "unit": "EA", + "base_quantity": 1, + "calculated_quantity": 10, + "unit_price": 150000, + "total_price": 1500000, + "formula": "Q", + "formula_source": "제품BOM", + "sort_order": 1 + } + ], + + "revisions": [ + { + "revision_number": 2, + "revision_date": "2025-12-04", + "revision_by_name": "김철수", + "revision_reason": "고객 요청으로 수량 변경" + }, + { + "revision_number": 1, + "revision_date": "2025-12-03", + "revision_by_name": "김철수", + "revision_reason": "단가 조정" + } + ], + + "created_at": "2025-12-04T10:00:00Z", + "updated_at": "2025-12-04T15:30:00Z" + } +} +``` + +### 4.3 생성 `POST /api/v1/quotes` + +**Request Body:** +```json +{ + "registration_date": "2025-12-04", + "receipt_date": "2025-12-04", + + "client_id": 10, + "client_name": "ABC건설", + "manager": "이영희", + "contact": "010-1234-5678", + + "site_id": 5, + "site_name": "강남 오피스텔 현장", + "site_code": "PJ-20251204-01", + + "product_category": "SCREEN", + "product_id": 100, + + "open_size_width": 2000, + "open_size_height": 3000, + "quantity": 10, + "unit_symbol": "A", + "floors": "3층", + + "completion_date": "2025-12-31", + "remarks": "급하게 진행 필요", + + "items": [ + { + "item_id": 50, + "item_code": "SCR-MOTOR-001", + "item_name": "스크린 모터", + "unit": "EA", + "base_quantity": 1, + "calculated_quantity": 10, + "unit_price": 150000, + "total_price": 1500000, + "formula": "Q", + "sort_order": 1 + } + ] +} +``` + +### 4.4 자동 산출 `POST /api/v1/quotes/calculate` ⭐ 핵심 + +**Request Body:** +```json +{ + "product_id": 100, + "product_category": "SCREEN", + "open_size_width": 2000, + "open_size_height": 3000, + "quantity": 10, + "floors": "3층", + "unit_symbol": "A", + + "options": { + "guide_rail_install_type": "벽부형", + "motor_power": "1/4HP", + "controller": "표준형", + "edge_wing_size": 50, + "inspection_fee": 0 + } +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "product_id": 100, + "product_name": "전동스크린 A형", + "product_category": "SCREEN", + + "open_size": { + "width": 2000, + "height": 3000 + }, + "quantity": 10, + + "items": [ + { + "item_id": 50, + "item_code": "SCR-MOTOR-001", + "item_name": "스크린 모터", + "specification": "220V, 1/4HP", + "unit": "EA", + "base_quantity": 1, + "calculated_quantity": 10, + "unit_price": 150000, + "total_price": 1500000, + "formula": "Q", + "formula_result": "10 × 1 = 10", + "formula_source": "제품BOM: 전동스크린 A형", + "data_source": "품목마스터 [SCR-MOTOR-001]" + }, + { + "item_id": 51, + "item_code": "SCR-RAIL-001", + "item_name": "가이드레일", + "specification": "알루미늄", + "unit": "M", + "base_quantity": 1, + "calculated_quantity": 60, + "unit_price": 15000, + "total_price": 900000, + "formula": "H/1000 × 2 × Q", + "formula_result": "(3000/1000) × 2 × 10 = 60", + "formula_source": "BOM템플릿: 스크린_표준", + "data_source": "품목마스터 [SCR-RAIL-001]" + } + ], + + "summary": { + "material_cost": 12000000, + "labor_cost": 1500000, + "install_cost": 1500000, + "subtotal": 15000000, + "total_amount": 15000000 + }, + + "calculation_info": { + "bom_template_used": "스크린_표준", + "formula_variables": { + "W": 2000, + "H": 3000, + "Q": 10 + }, + "calculated_at": "2025-12-04T10:00:00Z" + } + } +} +``` + +--- + +## 5. 수식 계산 엔진 (백엔드 구현 요청) + +### 5.1 수식 변수 + +| 변수 | 설명 | 예시 | +|------|------|------| +| `W` | 오픈사이즈 폭 (mm) | 2000 | +| `H` | 오픈사이즈 높이 (mm) | 3000 | +| `Q` | 수량 | 10 | + +### 5.2 수식 예시 + +``` +수량 그대로: Q +높이 기반: H/1000 +폭+높이: (W + H) / 1000 +가이드레일: H/1000 × 2 × Q +스크린원단: (W/1000 + 0.1) × (H/1000 + 0.3) × Q +``` + +### 5.3 반올림 규칙 + +| 규칙 | 설명 | +|------|------| +| `ceil` | 올림 | +| `floor` | 내림 | +| `round` | 반올림 | + +### 5.4 BOM 템플릿 연동 + +- 제품별 BOM 템플릿에서 수식 조회 +- 템플릿이 없으면 품목마스터 BOM 사용 +- 수식 + 단가로 자동 금액 계산 + +--- + +## 6. 상태 흐름도 + +``` +[신규등록] + ↓ +[draft] 임시저장 + ↓ (최종확정) +[finalized] 확정 + ↓ (수주전환) +[converted] 수주전환 +``` + +### 6.1 상태별 제약 + +| 상태 | 수정 가능 | 삭제 가능 | 비고 | +|------|----------|----------|------| +| `draft` | O | O | 자유롭게 수정 | +| `sent` | O | O | 발송 후 수정 가능 (이력 기록) | +| `finalized` | X | X | 확정 후 수정 불가 | +| `converted` | X | X | 수주전환 후 불변 | + +--- + +## 7. 프론트엔드 연동 계획 + +### 7.1 useQuoteList 훅 (목록) +```typescript +const { + quotes, + pagination, + isLoading, + fetchQuotes, + deleteQuote, + bulkDelete +} = useQuoteList(); +``` + +### 7.2 useQuote 훅 (단건 CRUD) +```typescript +const { + quote, + isLoading, + fetchQuote, + createQuote, + updateQuote, + finalizeQuote, + convertToOrder +} = useQuote(); +``` + +### 7.3 useQuoteCalculation 훅 (자동 산출) +```typescript +const { + calculationResult, + isCalculating, + calculate, + recalculate +} = useQuoteCalculation(); +``` + +--- + +## 8. 관련 참조 + +### 8.1 거래처 API 연동 +- 발주처 선택 시 `/api/v1/clients` 연동 +- 직접입력 시 자동 등록 가능 + +### 8.2 현장 API (추후) +- 현장 선택 시 `/api/v1/sites` 연동 (별도 API 필요시) + +### 8.3 품목마스터 연동 +- 제품 선택 시 `/api/v1/item-masters` 연동 +- BOM 조회 시 품목마스터 BOM 활용 + +--- + +## 9. 요청 우선순위 + +| 순위 | API | 설명 | +|------|-----|------| +| P1 | 견적 CRUD | 기본 목록/등록/수정/삭제 | +| P1 | 자동 산출 | 수식 계산 엔진 (핵심) | +| P1 | 견적번호 생성 | 자동 채번 | +| P2 | 상태 관리 | 확정/수주전환 | +| P2 | 수정 이력 | 버전 관리 | +| P3 | 문서 출력 | PDF 생성 | + +--- + +## 10. 질문사항 + +1. **현장(Site) 테이블**: 별도 테이블로 관리할지? (거래처 하위 개념) +2. **수식 계산**: BOM 템플릿 테이블 구조는? +3. **문서 출력**: PDF 라이브러리 선정 (TCPDF, Dompdf 등) +4. **알림**: 견적 발송 시 이메일/카카오톡 연동 계획? diff --git a/front/[API-REQUEST-2025-11-28] dynamic-page-rendering-api.md b/front/[API-REQUEST-2025-11-28] dynamic-page-rendering-api.md new file mode 100644 index 0000000..768ba64 --- /dev/null +++ b/front/[API-REQUEST-2025-11-28] dynamic-page-rendering-api.md @@ -0,0 +1,1112 @@ +# 품목관리 페이지 전체 API 요청서 + +## 작업 일자: 2025-11-28 + +## 문서 버전 +| 버전 | 날짜 | 작성자 | 내용 | +|------|------|--------|------| +| 1.0 | 2025-11-28 | Claude | 초안 작성 (동적 렌더링만) | +| 2.0 | 2025-11-28 | Claude | 전체 CRUD + 리스트 + 페이징 추가 | +| 3.0 | 2025-11-28 | Claude | **백엔드 스키마/기존 API 기반 재검토** | + +--- + +## 🔴 백엔드 검토 결과 요약 + +### 기존 API와의 정합성 분석 + +| 항목 | 기존 백엔드 | 요청서 v2.0 | 조정 필요 | +|------|------------|-------------|----------| +| 품목 수정/삭제 | `/{code}` (코드 기반) | `/{id}` (ID 기반) | ✅ **코드 기반으로 통일** | +| 품목 조회 | `item_type` 파라미터 필수 | 자동 감지 | ✅ 파라미터 추가 | +| 페이징 파라미터 | `size` | `per_page` | ✅ `size`로 변경 | +| item-master init | 이미 구현됨 | 별도 요청 | ✅ 기존 활용 | +| BOM API | `/items/{code}/bom` | `/items/{id}/bom` | ✅ **코드 기반으로 통일** | +| 파일 API | `/items/{code}/files` | `/files/upload` | ✅ 기존 구조 활용 | +| 테넌트 격리 | `tenant_id` 자동 | 미언급 | ✅ 서버 자동 처리 | + +### 주요 백엔드 아키텍처 특성 (반영 필요) + +```yaml +multi_tenancy: + - 모든 테이블에 tenant_id 필수 + - BelongsToTenant 글로벌 스코프 적용 + - API 레벨에서 자동 격리 (클라이언트 처리 불필요) + +soft_delete: + - deleted_at, deleted_by 컬럼 사용 + - 삭제 시 실제 삭제가 아닌 soft delete + +audit_columns: + - created_by, updated_by, deleted_by + - 사용자 추적 자동 처리 + +api_response_format: + success: true/false + data: {} | [] + message: string (i18n key) +``` + +--- + +## 작업 체크리스트 + +### Phase 1: 분석 단계 +- [x] 품목기준관리 API 저장/수정/삭제 검토 +- [x] 현재 품목관리 페이지 구조 분석 +- [x] 품목기준관리 저장 데이터 구조 확인 +- [x] 품목관리 리스트/상세/등록/수정 페이지 분석 + +### Phase 2: 설계 단계 +- [x] 품목 리스트 API (페이징, 필터, 검색) +- [x] 품목 CRUD API (생성, 조회, 수정, 삭제) +- [x] 동적 페이지 렌더링 API +- [x] BOM 관리 API +- [x] 파일 업로드 API +- [x] 통계/대시보드 API + +### Phase 3: 검토 단계 ✅ 완료 +- [x] 백엔드 DB 스키마 검토 (`database-schema.md`) +- [x] 기존 item-master-spec 검토 (`item-master-spec.md`) +- [x] sam-api 기존 API 구조 확인 (`api.php`, Controllers) +- [x] API 스펙 정합성 조정 + +### Phase 4: 확정 단계 +- [ ] 백엔드 팀 최종 리뷰 +- [ ] API 스펙 확정 +- [ ] 프론트엔드 연동 테스트 + +--- + +## 1. 개요 + +### 1.1 목적 +품목관리 페이지(`/items/*`)에서 필요한 **모든 API**를 정의합니다: +- 품목 목록 조회 (페이징, 필터, 검색) +- 품목 CRUD (생성, 조회, 수정, 삭제) +- 동적 폼 렌더링 (품목기준관리 연동) +- BOM 관리 +- 파일 업로드/다운로드 +- 통계 정보 + +### 1.2 관련 페이지 +| 경로 | 페이지 | 필요 API | +|------|--------|----------| +| `/items` | 품목 목록 | 리스트, 검색, 필터, 페이징, 통계, 삭제 | +| `/items/create` | 품목 등록 | 동적 폼 구조, 생성, BOM 검색, 파일 업로드 | +| `/items/[id]` | 품목 상세 | 단건 조회, BOM 조회 | +| `/items/[id]/edit` | 품목 수정 | 단건 조회, 수정, BOM 관리, 파일 업로드 | + +--- + +## 2. 품목 목록 API (List) + +### API 2.1: 품목 목록 조회 (페이징) + +> ⚠️ **기존 API 존재**: `ItemsController@index` - 파라미터명 조정 필요 + +``` +GET /api/v1/items +``` + +**Query Parameters** (기존 백엔드 기준): +| 파라미터 | 타입 | 필수 | 기본값 | 설명 | +|----------|------|------|--------|------| +| page | number | N | 1 | 페이지 번호 | +| size | number | N | 20 | 페이지당 항목 수 (기존: `size`, 변경 금지) | +| type | string | N | - | 품목유형 필터 (FG, PT, SM, RM, CS) | +| search | string | N | - | 검색어 (품목코드, 품목명) | +| q | string | N | - | 검색어 (search와 동일, 호환용) | +| category_id | number | N | - | 카테고리 ID 필터 | +| is_active | boolean | N | - | 활성 상태 필터 **(신규 요청)** | +| sort_by | string | N | created_at | 정렬 기준 **(신규 요청)** | +| sort_order | string | N | desc | 정렬 순서 **(신규 요청)** | + +**Request Example**: +``` +GET /api/v1/items?page=1&size=20&type=FG&search=스크린 +``` + +**Response**: +```json +{ + "success": true, + "data": { + "items": [ + { + "id": 1, + "item_code": "KD-FG-001", + "item_name": "스크린 제품 A", + "item_type": "FG", + "unit": "EA", + "specification": "2000x2000", + "is_active": true, + "category1": "본체부품", + "category2": "가이드시스템", + "sales_price": 150000, + "purchase_price": 100000, + "product_category": "SCREEN", + "current_revision": 0, + "is_final": false, + "created_at": "2025-01-10T00:00:00Z", + "updated_at": "2025-01-10T00:00:00Z" + } + ], + "pagination": { + "current_page": 1, + "per_page": 20, + "total_items": 150, + "total_pages": 8, + "has_next": true, + "has_prev": false + } + } +} +``` + +--- + +### API 2.2: 품목 통계 조회 + +> 🆕 **신규 API 요청** + +``` +GET /api/v1/items/stats +``` + +**Response**: +```json +{ + "success": true, + "data": { + "total_count": 500, + "by_item_type": { + "FG": 50, + "PT": 200, + "SM": 100, + "RM": 100, + "CS": 50 + }, + "active_count": 450, + "inactive_count": 50 + }, + "message": "message.fetched" +} +``` + +--- + +### API 2.3: 품목 검색 (BOM용 자동완성) +``` +GET /api/v1/items/search +``` + +**Query Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| q | string | Y | 검색어 (최소 2자) | +| item_type | string | N | 품목유형 필터 (복수 가능: PT,SM) | +| limit | number | N | 결과 개수 제한 (기본 10, 최대 50) | + +**Request Example**: +``` +GET /api/v1/items/search?q=가이드&item_type=PT&limit=10 +``` + +**Response**: +```json +{ + "success": true, + "data": [ + { + "id": 2, + "item_code": "KD-PT-001", + "item_name": "가이드레일(벽면형)", + "item_type": "PT", + "unit": "EA", + "specification": "2438mm", + "sales_price": 50000 + } + ] +} +``` + +--- + +## 3. 품목 CRUD API + +### API 3.1: 품목 단건 조회 (ID 기반) + +> ⚠️ **기존 API 존재**: `ItemsController@show` - `item_type` 파라미터 필수 + +``` +GET /api/v1/items/{id} +``` + +**Path Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| id | number | Y | 품목 ID | + +**Query Parameters** (기존 백엔드 기준): +| 파라미터 | 타입 | 필수 | 기본값 | 설명 | +|----------|------|------|--------|------| +| item_type | string | Y | PRODUCT | 품목 유형 (PRODUCT, MATERIAL) | +| include_price | boolean | N | false | 가격 정보 포함 여부 | +| client_id | number | N | - | 고객별 가격 조회 시 | +| price_date | string | N | - | 가격 기준일 (YYYY-MM-DD) | + +### API 3.1.1: 품목 단건 조회 (Code 기반) + +> ✅ **기존 API 존재**: `ItemsController@showByCode` + +``` +GET /api/v1/items/code/{code} +``` + +**Path Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| code | string | Y | 품목 코드 (예: KD-FG-001) | + +**Query Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| include_bom | boolean | N | BOM 정보 포함 여부 | + +**Response**: +```json +{ + "success": true, + "data": { + "id": 1, + "item_code": "KD-FG-001", + "item_name": "스크린 제품 A", + "item_type": "FG", + "unit": "EA", + "specification": "2000x2000", + "is_active": true, + "product_category": "SCREEN", + "lot_abbreviation": "KD", + + "category1": "본체부품", + "category2": "가이드시스템", + "category3": null, + + "purchase_price": 100000, + "sales_price": 150000, + "margin_rate": 50, + "processing_cost": 10000, + "labor_cost": 5000, + "install_cost": 3000, + + "certification_number": "인정번호-001", + "certification_start_date": "2025-01-01", + "certification_end_date": "2028-01-01", + "specification_file": "/files/spec-001.pdf", + "specification_file_name": "시방서.pdf", + "certification_file": "/files/cert-001.pdf", + "certification_file_name": "인정서.pdf", + "note": "비고 내용", + + "current_revision": 0, + "is_final": false, + "finalized_date": null, + "finalized_by": null, + + "bom": [ + { + "id": 1, + "child_item_code": "KD-PT-001", + "child_item_name": "가이드레일(벽면형)", + "quantity": 2, + "unit": "EA", + "unit_price": 50000, + "quantity_formula": "H / 1000", + "note": "높이에 따라 수량 변동" + } + ], + + "revisions": [], + "created_at": "2025-01-10T00:00:00Z", + "updated_at": "2025-01-10T00:00:00Z", + "created_by": 1, + "updated_by": 1 + } +} +``` + +--- + +### API 3.2: 품목 생성 +``` +POST /api/v1/items +``` + +**Request Body**: +```json +{ + "item_type": "FG", + "item_name": "스크린 제품 신규", + "unit": "EA", + "specification": "2500x2500", + "is_active": true, + "product_category": "SCREEN", + "lot_abbreviation": "KD", + + "category1": "본체부품", + "category2": "가이드시스템", + + "purchase_price": 120000, + "sales_price": 180000, + + "certification_number": "인정번호-002", + "certification_start_date": "2025-01-01", + "certification_end_date": "2028-01-01", + "note": "신규 제품", + + "bom": [ + { + "child_item_id": 2, + "quantity": 2, + "unit": "EA", + "quantity_formula": "H / 1000", + "note": "높이에 따라 수량 변동" + } + ] +} +``` + +**Response**: +```json +{ + "success": true, + "data": { + "id": 10, + "item_code": "KD-FG-010", + "item_name": "스크린 제품 신규", + "message": "품목이 성공적으로 생성되었습니다." + } +} +``` + +--- + +### API 3.3: 품목 수정 + +> ⚠️ **기존 API 존재**: `ItemsController@update` - **코드 기반 경로** + +``` +PUT /api/v1/items/{code} +``` + +**Path Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| code | string | Y | 품목 코드 (예: KD-FG-001) | + +**Request Body**: (생성과 동일, 변경할 필드만 전송) +```json +{ + "item_name": "스크린 제품 A (수정)", + "sales_price": 160000, + "note": "가격 조정됨", + "bom": [ + { + "id": 1, + "quantity": 3 + }, + { + "child_item_id": 5, + "quantity": 10, + "unit": "EA" + } + ] +} +``` + +**Response**: +```json +{ + "success": true, + "data": { + "id": 1, + "item_code": "KD-FG-001", + "message": "품목이 성공적으로 수정되었습니다." + } +} +``` + +--- + +### API 3.4: 품목 삭제 + +> ⚠️ **기존 API 존재**: `ItemsController@destroy` - **코드 기반 경로** + +``` +DELETE /api/v1/items/{code} +``` + +**Path Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| code | string | Y | 품목 코드 (예: KD-FG-001) | + +**Response**: +```json +{ + "success": true, + "data": { + "message": "품목이 성공적으로 삭제되었습니다." + } +} +``` + +**Error Response** (사용 중인 품목): +```json +{ + "success": false, + "error": { + "code": "ITEM_IN_USE", + "message": "해당 품목은 다른 BOM에서 사용 중이므로 삭제할 수 없습니다.", + "details": { + "used_in": [ + {"item_code": "KD-FG-001", "item_name": "스크린 제품 A"} + ] + } + } +} +``` + +--- + +### API 3.5: 품목 일괄 삭제 + +> 🆕 **신규 API 요청** - 코드 기반 일괄 삭제 + +``` +DELETE /api/v1/items/batch +``` + +**Request Body**: +```json +{ + "codes": ["KD-FG-001", "KD-PT-002", "KD-SM-003"] +} +``` + +**Response**: +```json +{ + "success": true, + "data": { + "deleted_count": 2, + "failed_count": 1, + "failed_items": [ + { + "id": 3, + "item_code": "KD-PT-003", + "reason": "BOM에서 사용 중" + } + ], + "message": "2개 품목이 삭제되었습니다. 1개 품목은 삭제할 수 없습니다." + } +} +``` + +--- + +## 4. 동적 폼 렌더링 API + +### API 4.1: 품목 유형별 폼 구조 조회 +``` +GET /api/v1/item-master/form-structure/{item_type} +``` + +**Path Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| item_type | string | Y | 품목 유형 (FG, PT, SM, RM, CS) | + +**Query Parameters**: +| 파라미터 | 타입 | 필수 | 기본값 | 설명 | +|----------|------|------|--------|------| +| include_conditions | boolean | N | true | 조건부 필드 포함 여부 | + +**Response**: +```json +{ + "success": true, + "data": { + "page": { + "id": 1, + "page_name": "제품 등록", + "item_type": "FG", + "description": "제품(완제품) 등록 페이지" + }, + "sections": [ + { + "id": 101, + "title": "기본 정보", + "section_type": "BASIC", + "order_no": 1, + "is_collapsible": false, + "is_default_open": true, + "fields": [ + { + "id": 1001, + "field_name": "품목명", + "field_key": "item_name", + "field_type": "textbox", + "order_no": 1, + "is_required": true, + "placeholder": "품목명을 입력하세요", + "validation_rules": { + "maxLength": 100 + }, + "grid_row": 1, + "grid_col": 1, + "grid_span": 2 + }, + { + "id": 1002, + "field_name": "품목 상태", + "field_key": "status", + "field_type": "dropdown", + "order_no": 2, + "is_required": true, + "default_value": "DEV", + "options": [ + {"label": "개발", "value": "DEV"}, + {"label": "양산", "value": "PROD"}, + {"label": "단종", "value": "EOL"} + ], + "grid_row": 2, + "grid_col": 1, + "grid_span": 1 + } + ] + }, + { + "id": 102, + "title": "인정 정보", + "section_type": "BASIC", + "order_no": 2, + "is_collapsible": true, + "is_default_open": false, + "fields": [ + { + "id": 1010, + "field_name": "인정번호", + "field_key": "certification_number", + "field_type": "textbox", + "order_no": 1, + "is_required": false + }, + { + "id": 1011, + "field_name": "시방서", + "field_key": "specification_file", + "field_type": "file", + "order_no": 2, + "is_required": false, + "component_type": "file-upload", + "properties": { + "accept": ".pdf,.doc,.docx", + "max_size_mb": 10 + } + } + ] + }, + { + "id": 103, + "title": "부품 구성 (BOM)", + "section_type": "BOM", + "order_no": 3, + "is_collapsible": true, + "is_default_open": false, + "bom_config": { + "columns": [ + {"key": "child_item_code", "label": "품목코드", "width": 120, "editable": false}, + {"key": "child_item_name", "label": "품목명", "width": 200, "editable": false}, + {"key": "quantity", "label": "수량", "width": 80, "type": "number", "editable": true}, + {"key": "unit", "label": "단위", "width": 60, "editable": false}, + {"key": "quantity_formula", "label": "수량식", "width": 120, "editable": true}, + {"key": "note", "label": "비고", "width": 150, "editable": true} + ], + "allow_search": true, + "search_endpoint": "/api/v1/items/search", + "searchable_item_types": ["PT", "SM", "RM"] + } + } + ], + "conditional_sections": [ + { + "condition": { + "field_key": "needs_bom", + "operator": "equals", + "value": true + }, + "show_sections": [103] + } + ] + } +} +``` + +--- + +### API 4.2: 부품(PT) 조건부 필드 조회 +``` +GET /api/v1/item-master/form-structure/PT/conditional +``` + +**Query Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| part_type | string | Y | 부품유형 (ASSEMBLY, BENDING, PURCHASED) | +| category1 | string | N | 대분류 값 | + +**Request Example**: +``` +GET /api/v1/item-master/form-structure/PT/conditional?part_type=BENDING&category1=가이드레일 +``` + +**Response**: +```json +{ + "success": true, + "data": { + "part_type": "BENDING", + "category1": "가이드레일", + "additional_sections": [ + { + "id": 201, + "title": "절곡품 정보", + "section_type": "CUSTOM", + "order_no": 2, + "fields": [ + { + "id": 2001, + "field_name": "재질", + "field_key": "material", + "field_type": "dropdown", + "is_required": true, + "options": [ + {"label": "EGI 1.55T", "value": "EGI_155"}, + {"label": "SUS 1.2T", "value": "SUS_12"}, + {"label": "SPCC 1.6T", "value": "SPCC_16"} + ] + }, + { + "id": 2002, + "field_name": "길이", + "field_key": "length", + "field_type": "dropdown", + "is_required": true, + "options": [ + {"label": "2438mm", "value": "2438"}, + {"label": "3000mm", "value": "3000"}, + {"label": "4000mm", "value": "4000"} + ] + } + ] + }, + { + "id": 202, + "title": "전개도", + "section_type": "CUSTOM", + "order_no": 3, + "fields": [ + { + "id": 2010, + "field_name": "전개도 이미지", + "field_key": "bending_diagram", + "field_type": "custom", + "component_type": "drawing-canvas", + "is_required": false, + "properties": { + "width": 800, + "height": 400, + "tools": ["pen", "line", "eraser", "text"] + } + }, + { + "id": 2011, + "field_name": "전개도 상세", + "field_key": "bending_details", + "field_type": "custom", + "component_type": "bending-detail-table", + "is_required": false + } + ] + } + ] + } +} +``` + +--- + +## 5. BOM 관리 API + +### API 5.1: 품목 BOM 조회 +``` +GET /api/v1/items/{id}/bom +``` + +**Response**: +```json +{ + "success": true, + "data": { + "item_id": 1, + "item_code": "KD-FG-001", + "item_name": "스크린 제품 A", + "bom_lines": [ + { + "id": 1, + "child_item_id": 2, + "child_item_code": "KD-PT-001", + "child_item_name": "가이드레일(벽면형)", + "quantity": 2, + "unit": "EA", + "unit_price": 50000, + "total_price": 100000, + "quantity_formula": "H / 1000", + "note": "높이에 따라 수량 변동", + "order_no": 1 + } + ], + "total_cost": 250000 + } +} +``` + +--- + +### API 5.2: BOM 항목 추가 +``` +POST /api/v1/items/{id}/bom +``` + +**Request Body**: +```json +{ + "child_item_id": 5, + "quantity": 10, + "unit": "EA", + "quantity_formula": null, + "note": "추가 부품" +} +``` + +--- + +### API 5.3: BOM 항목 수정 +``` +PUT /api/v1/items/{item_id}/bom/{bom_id} +``` + +**Request Body**: +```json +{ + "quantity": 15, + "note": "수량 증가" +} +``` + +--- + +### API 5.4: BOM 항목 삭제 +``` +DELETE /api/v1/items/{item_id}/bom/{bom_id} +``` + +--- + +## 6. 파일 관리 API + +### API 6.1: 파일 업로드 +``` +POST /api/v1/files/upload +``` + +**Content-Type**: `multipart/form-data` + +**Form Data**: +| 필드 | 타입 | 필수 | 설명 | +|------|------|------|------| +| file | File | Y | 업로드할 파일 | +| type | string | Y | 파일 유형 (specification, certification, bending_diagram) | +| item_id | number | N | 연결할 품목 ID (수정 시) | + +**Response**: +```json +{ + "success": true, + "data": { + "file_id": "uuid-1234-5678", + "file_name": "시방서.pdf", + "file_url": "/files/uuid-1234-5678/시방서.pdf", + "file_size": 1024000, + "mime_type": "application/pdf" + } +} +``` + +--- + +### API 6.2: 파일 다운로드 +``` +GET /api/v1/files/{file_id}/download +``` + +--- + +### API 6.3: 파일 삭제 +``` +DELETE /api/v1/files/{file_id} +``` + +--- + +## 7. 마스터 데이터 조회 API + +### API 7.1: 단위 목록 조회 +``` +GET /api/v1/master/units +``` + +**Response**: +```json +{ + "success": true, + "data": [ + {"value": "EA", "label": "EA (개)"}, + {"value": "SET", "label": "SET (세트)"}, + {"value": "M", "label": "M (미터)"}, + {"value": "KG", "label": "KG (킬로그램)"}, + {"value": "L", "label": "L (리터)"} + ] +} +``` + +--- + +### API 7.2: 카테고리 목록 조회 +``` +GET /api/v1/master/categories +``` + +**Query Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| item_type | string | N | 품목유형별 필터 | +| parent_id | number | N | 상위 카테고리 ID | + +--- + +### API 7.3: 재질 목록 조회 +``` +GET /api/v1/master/materials +``` + +**Response**: +```json +{ + "success": true, + "data": [ + {"value": "EGI_155", "label": "EGI 1.55T", "thickness": "1.55"}, + {"value": "SUS_12", "label": "SUS 1.2T", "thickness": "1.2"}, + {"value": "SPCC_16", "label": "SPCC 1.6T", "thickness": "1.6"} + ] +} +``` + +--- + +### API 7.4: 규격 목록 조회 (원자재/부자재) +``` +GET /api/v1/master/specifications +``` + +**Query Parameters**: +| 파라미터 | 타입 | 필수 | 설명 | +|----------|------|------|------| +| item_type | string | Y | RM 또는 SM | +| item_name | string | N | 품목명 필터 (예: SPHC-SD) | + +--- + +## 8. API 요약 테이블 + +### 8.1 필수 API (MVP) +| 우선순위 | 메서드 | 엔드포인트 | 설명 | 상태 | +|----------|--------|------------|------|------| +| 🔴 P0 | GET | `/api/v1/items` | 품목 목록 조회 (페이징) | ⚠️ 기존 | +| 🔴 P0 | GET | `/api/v1/items/{id}` | 품목 단건 조회 (ID) | ⚠️ 기존 | +| 🔴 P0 | GET | `/api/v1/items/code/{code}` | 품목 단건 조회 (코드) | ⚠️ 기존 | +| 🔴 P0 | POST | `/api/v1/items` | 품목 생성 | ⚠️ 기존 | +| 🔴 P0 | PUT | `/api/v1/items/{code}` | 품목 수정 (코드 기반) | ⚠️ 기존 | +| 🔴 P0 | DELETE | `/api/v1/items/{code}` | 품목 삭제 (코드 기반) | ⚠️ 기존 | +| 🔴 P0 | GET | `/api/v1/items/search` | 품목 검색 (BOM용) | 🆕 신규 | + +### 8.2 중요 API +| 우선순위 | 메서드 | 엔드포인트 | 설명 | +|----------|--------|------------|------| +| 🟡 P1 | GET | `/api/v1/item-master/form-structure/{type}` | 동적 폼 구조 조회 | +| 🟡 P1 | GET | `/api/v1/items/stats` | 품목 통계 | +| 🟡 P1 | DELETE | `/api/v1/items/batch` | 품목 일괄 삭제 | +| 🟡 P1 | POST | `/api/v1/files/upload` | 파일 업로드 | + +### 8.3 추가 API +| 우선순위 | 메서드 | 엔드포인트 | 설명 | +|----------|--------|------------|------| +| 🟢 P2 | GET | `/api/v1/item-master/form-structure/PT/conditional` | PT 조건부 필드 | +| 🟢 P2 | GET | `/api/v1/items/{id}/bom` | BOM 조회 | +| 🟢 P2 | POST | `/api/v1/items/{id}/bom` | BOM 항목 추가 | +| 🟢 P2 | PUT | `/api/v1/items/{id}/bom/{bom_id}` | BOM 항목 수정 | +| 🟢 P2 | DELETE | `/api/v1/items/{id}/bom/{bom_id}` | BOM 항목 삭제 | +| 🟢 P2 | GET | `/api/v1/master/units` | 단위 목록 | +| 🟢 P2 | GET | `/api/v1/master/categories` | 카테고리 목록 | +| 🟢 P2 | GET | `/api/v1/master/materials` | 재질 목록 | +| 🟢 P2 | GET | `/api/v1/master/specifications` | 규격 목록 | +| 🟢 P2 | GET | `/api/v1/files/{id}/download` | 파일 다운로드 | +| 🟢 P2 | DELETE | `/api/v1/files/{id}` | 파일 삭제 | + +--- + +## 9. 에러 응답 형식 + +### 공통 에러 응답 +```json +{ + "success": false, + "error": { + "code": "ERROR_CODE", + "message": "사용자 친화적 에러 메시지", + "details": {} + } +} +``` + +### 에러 코드 목록 +| 코드 | HTTP Status | 설명 | +|------|-------------|------| +| VALIDATION_ERROR | 400 | 입력값 검증 실패 | +| ITEM_NOT_FOUND | 404 | 품목을 찾을 수 없음 | +| ITEM_IN_USE | 409 | 품목이 다른 곳에서 사용 중 | +| DUPLICATE_ITEM_CODE | 409 | 중복된 품목코드 | +| FILE_TOO_LARGE | 413 | 파일 크기 초과 | +| UNAUTHORIZED | 401 | 인증 필요 | +| FORBIDDEN | 403 | 권한 없음 | +| INTERNAL_ERROR | 500 | 서버 내부 오류 | + +--- + +## 10. 데이터 모델 참조 + +### 10.1 품목(Item) 테이블 필드 +```sql +CREATE TABLE items ( + id SERIAL PRIMARY KEY, + tenant_id INTEGER NOT NULL, + item_code VARCHAR(50) UNIQUE NOT NULL, + item_name VARCHAR(200) NOT NULL, + item_type VARCHAR(10) NOT NULL, -- FG, PT, SM, RM, CS + unit VARCHAR(20) NOT NULL, + specification VARCHAR(200), + is_active BOOLEAN DEFAULT true, + + -- 제품(FG) 전용 + product_category VARCHAR(20), -- SCREEN, STEEL + lot_abbreviation VARCHAR(10), + certification_number VARCHAR(100), + certification_start_date DATE, + certification_end_date DATE, + specification_file VARCHAR(500), + specification_file_name VARCHAR(200), + certification_file VARCHAR(500), + certification_file_name VARCHAR(200), + + -- 부품(PT) 전용 + part_type VARCHAR(20), -- ASSEMBLY, BENDING, PURCHASED + part_usage VARCHAR(50), + installation_type VARCHAR(50), + assembly_type VARCHAR(10), + assembly_length VARCHAR(20), + side_spec_width VARCHAR(20), + side_spec_height VARCHAR(20), + material VARCHAR(50), + length VARCHAR(20), + bending_diagram TEXT, -- Base64 이미지 + bending_details JSONB, -- 전개도 상세 데이터 + + -- 분류 + category1 VARCHAR(100), + category2 VARCHAR(100), + category3 VARCHAR(100), + + -- 가격 + purchase_price DECIMAL(15,2), + sales_price DECIMAL(15,2), + margin_rate DECIMAL(5,2), + processing_cost DECIMAL(15,2), + labor_cost DECIMAL(15,2), + install_cost DECIMAL(15,2), + + -- 재고 + safety_stock INTEGER, + lead_time INTEGER, + + -- 버전 관리 + current_revision INTEGER DEFAULT 0, + is_final BOOLEAN DEFAULT false, + finalized_date TIMESTAMP, + finalized_by INTEGER, + + note TEXT, + created_by INTEGER, + updated_by INTEGER, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); +``` + +### 10.2 BOM 테이블 +```sql +CREATE TABLE item_bom ( + id SERIAL PRIMARY KEY, + tenant_id INTEGER NOT NULL, + parent_item_id INTEGER REFERENCES items(id), + child_item_id INTEGER REFERENCES items(id), + quantity DECIMAL(10,3) NOT NULL, + unit VARCHAR(20), + unit_price DECIMAL(15,2), + quantity_formula VARCHAR(100), -- 예: "H / 1000" + note TEXT, + order_no INTEGER DEFAULT 0, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW() +); +``` + +--- + +## 11. 참고 문서 + +- `src/components/items/ItemListClient.tsx` - 품목 목록 UI +- `src/components/items/ItemForm/index.tsx` - 품목 등록/수정 폼 +- `src/contexts/ItemMasterContext.tsx` - 품목기준관리 데이터 구조 +- `[API-2025-11-25] item-master-data-management-api-request.md` - 품목기준관리 API + +--- + +## 변경 이력 + +| 날짜 | 버전 | 변경 내용 | +|------|------|----------| +| 2025-11-28 | 1.0 | 초안 작성 (동적 렌더링만) | +| 2025-11-28 | 2.0 | **전체 CRUD + 리스트 + 페이징 + BOM + 파일 + 마스터 데이터 추가** | +| 2025-11-28 | 3.0 | **백엔드 스키마/기존 API 기반 재검토**: `/{id}` → `/{code}` 경로 변경, `per_page` → `size` 파라미터 변경, 기존 API 주석 추가, 일괄삭제 코드 기반 변경 | \ No newline at end of file diff --git a/front/[API-RESPONSE-2025-11-28] items-api-spec-changes.md b/front/[API-RESPONSE-2025-11-28] items-api-spec-changes.md new file mode 100644 index 0000000..b05b462 --- /dev/null +++ b/front/[API-RESPONSE-2025-11-28] items-api-spec-changes.md @@ -0,0 +1,24 @@ +# API 스펙 회신 (2025-11-28) + +요청서 검토 완료. 아래 2가지만 변경됩니다. + +--- + +## 변경 1: 식별자 코드 → ID + +``` +PUT /items/{code} → PUT /items/{id} +DELETE /items/{code} → DELETE /items/{id} +/items/{code}/bom/* → /items/{id}/bom/* +/items/{code}/files/* → /items/{id}/files/* +``` + +## 변경 2: 일괄 삭제 파라미터 + +``` +{ "codes": [...] } → { "ids": [...] } +``` + +--- + +나머지는 요청서대로 진행합니다. \ No newline at end of file diff --git a/front/item-master-guide.md b/front/item-master-guide.md new file mode 100644 index 0000000..a09effa --- /dev/null +++ b/front/item-master-guide.md @@ -0,0 +1,378 @@ +# 품목기준관리(ItemMaster) 프론트엔드 가이드 + +> 📌 **품목설정 시스템의 구조, API, 잠금 기능에 대한 프론트엔드 개발 가이드** + +--- + +## 1. 개요 + +품목기준관리(ItemMaster)는 제품의 입력 화면을 구성하는 **페이지-섹션-필드** 구조를 관리하는 시스템입니다. + +### 1.1 핵심 개념 + +| 엔티티 | 설명 | 예시 | +|--------|------|------| +| **Page** | 품목 유형별 화면 (FG, PT, SM, RM, CS) | "완제품 기본정보", "부품 상세" | +| **Section** | 페이지 내 논리적 영역 | "제품 상세", "BOM 정보" | +| **Field** | 섹션 내 입력 항목 | "제품명", "규격", "단가" | +| **BomItem** | BOM 섹션 내 부품 항목 | "부품A x 2개" | + +### 1.2 아키텍처 특징 + +- **독립 엔티티 구조**: 섹션, 필드, BOM은 독립적으로 존재하며 재사용 가능 +- **링크 테이블**: `entity_relationships`로 관계 관리 +- **연결 잠금**: 중요한 구조는 잠금으로 보호 가능 + +--- + +## 2. 데이터 구조 + +### 2.1 엔티티 관계도 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ ItemPage │ +│ (id, page_name, item_type, is_active) │ +└─────────────┬──────────────────────────────────────────────────┘ + │ entity_relationships (is_locked) + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ ItemSection │ +│ (id, title, type, is_template, is_default) │ +└─────────────┬───────────────────────────────────┬──────────────┘ + │ entity_relationships │ entity_relationships + │ (is_locked) │ (is_locked) + ▼ ▼ +┌─────────────────────────────┐ ┌─────────────────────────────┐ +│ ItemField │ │ ItemBomItem │ +│ (id, field_name, │ │ (id, item_code, │ +│ field_type, is_required) │ │ item_name, quantity) │ +└─────────────────────────────┘ └─────────────────────────────┘ +``` + +### 2.2 entity_relationships 테이블 + +모든 엔티티 간 관계는 `entity_relationships` 테이블로 관리됩니다. + +```typescript +interface EntityRelationship { + id: number; + tenant_id: number; + group_id: number; // 1: ItemMaster + parent_type: 'page' | 'section'; + parent_id: number; + child_type: 'section' | 'field' | 'bom'; + child_id: number; + order_no: number; + is_locked: boolean; // ⭐ 잠금 여부 + locked_by?: number; + locked_at?: string; + metadata?: object; +} +``` + +--- + +## 3. 잠금(Lock) 기능 + +### 3.1 잠금의 의미 + +**연결이 잠기면:** +- 해당 연결(관계)를 해제할 수 없음 +- 연결된 자식 엔티티를 삭제할 수 없음 +- 이름 변경, 속성 추가 등 **비구조적 수정은 허용** + +``` +예시: page→section 연결이 잠김 +├─ ❌ 섹션을 페이지에서 분리할 수 없음 +├─ ❌ 해당 섹션을 삭제할 수 없음 +├─ ✅ 섹션 제목 변경 가능 +└─ ✅ 섹션에 새 필드 추가 가능 +``` + +### 3.2 잠금 상태 확인 + +init API 응답에 `is_locked` 필드가 포함됩니다. + +```typescript +// GET /api/v1/item-master/init 응답 +{ + "pages": [ + { + "id": 1, + "page_name": "완제품 기본정보", + "sections": [ + { + "id": 10, + "title": "제품 상세", + "is_locked": true, // ⭐ 이 연결이 잠김 + "fields": [ + { + "id": 100, + "field_name": "제품명", + "is_locked": false // ⭐ 이 연결은 잠기지 않음 + } + ] + } + ] + } + ] +} +``` + +### 3.3 프론트엔드 처리 가이드 + +```typescript +// 잠금 상태에 따른 UI 처리 예시 +interface SectionProps { + section: ItemSection; + isLocked: boolean; // 부모로부터 전달받은 잠금 상태 +} + +function SectionItem({ section, isLocked }: SectionProps) { + return ( +
+

+ {section.title} + {isLocked && } {/* 잠금 아이콘 표시 */} +

+ + {/* 잠금 시 삭제/분리 버튼 비활성화 */} + + + + + {/* 수정은 항상 가능 */} + +
+ ); +} +``` + +### 3.4 잠금 관련 에러 처리 + +잠금된 항목에 대해 삭제/해제 시도 시 에러가 반환됩니다. + +```typescript +// 에러 응답 예시 +{ + "success": false, + "message": "잠금된 연결은 해제할 수 없습니다.", + "error": "relationship_locked" +} + +// 프론트엔드 에러 처리 +try { + await deleteSection(sectionId); +} catch (error) { + if (error.response?.data?.error === 'entity_protected_by_locked_relationship') { + toast.error('잠금된 연결로 보호된 항목은 삭제할 수 없습니다.'); + } +} +``` + +--- + +## 4. API 엔드포인트 + +### 4.1 초기화 API + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/init` | 전체 데이터 로드 (페이지, 섹션, 커스텀탭, 단위옵션) | + +**응답 구조:** +```typescript +interface InitResponse { + pages: ItemPage[]; // 페이지 + 연결된 섹션/필드 + sections: ItemSection[]; // 모든 독립 섹션 (재사용 풀) + customTabs: CustomTab[]; + unitOptions: UnitOption[]; +} +``` + +### 4.2 페이지 API + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/pages` | 페이지 목록 | +| POST | `/api/v1/item-master/pages` | 페이지 생성 | +| PUT | `/api/v1/item-master/pages/{id}` | 페이지 수정 | +| DELETE | `/api/v1/item-master/pages/{id}` | 페이지 삭제 | + +### 4.3 섹션 API + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/sections` | 독립 섹션 목록 | +| POST | `/api/v1/item-master/sections` | 독립 섹션 생성 | +| POST | `/api/v1/item-master/pages/{pageId}/sections` | 섹션 생성 + 페이지 연결 | +| PUT | `/api/v1/item-master/sections/{id}` | 섹션 수정 | +| DELETE | `/api/v1/item-master/sections/{id}` | 섹션 삭제 | +| POST | `/api/v1/item-master/sections/{id}/clone` | 섹션 복제 | +| GET | `/api/v1/item-master/sections/{id}/usage` | 사용처 조회 | + +### 4.4 필드 API + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/fields` | 독립 필드 목록 | +| POST | `/api/v1/item-master/fields` | 독립 필드 생성 | +| POST | `/api/v1/item-master/sections/{sectionId}/fields` | 필드 생성 + 섹션 연결 | +| PUT | `/api/v1/item-master/fields/{id}` | 필드 수정 | +| DELETE | `/api/v1/item-master/fields/{id}` | 필드 삭제 | +| POST | `/api/v1/item-master/fields/{id}/clone` | 필드 복제 | +| GET | `/api/v1/item-master/fields/{id}/usage` | 사용처 조회 | + +### 4.5 BOM API + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/item-master/bom-items` | 독립 BOM 목록 | +| POST | `/api/v1/item-master/bom-items` | 독립 BOM 생성 | +| POST | `/api/v1/item-master/sections/{sectionId}/bom-items` | BOM 생성 + 섹션 연결 | +| PUT | `/api/v1/item-master/bom-items/{id}` | BOM 수정 | +| DELETE | `/api/v1/item-master/bom-items/{id}` | BOM 삭제 | + +### 4.6 순서 변경 API + +| Method | Endpoint | 설명 | +|--------|----------|------| +| PUT | `/api/v1/item-master/pages/{pageId}/sections/reorder` | 섹션 순서 변경 | +| PUT | `/api/v1/item-master/sections/{sectionId}/fields/reorder` | 필드 순서 변경 | + +--- + +## 5. 필드 타입 + +### 5.1 지원 필드 타입 + +| field_type | 설명 | 렌더링 컴포넌트 | +|------------|------|----------------| +| `textbox` | 텍스트 입력 | `` | +| `number` | 숫자 입력 | `` | +| `dropdown` | 드롭다운 선택 | `