# 설비관리 (Equipment Management) > **작성일**: 2026-02-27 > **상태**: MNG R&D 완료 / API Phase 1 완료 / React 미구현 > **최종 갱신**: 2026-03-12 (설비 등록 시 사진 업로드 기능 반영) --- ## 1. 개요 ### 1.1 목적 생산 설비의 등록, 점검, 수리이력을 체계적으로 관리한다. MNG 관리자 패널에서 Blade/HTMX 기반으로 R&D가 완료되었으며, API 백엔드 구현이 완료되어 React 프론트엔드 연동을 진행할 수 있다. ### 1.2 핵심 기능 | 기능 | 설명 | MNG | API | |------|------|:---:|:---:| | 설비 대시보드 | 현황 카드(총/가동/유휴/폐기), 유형별 통계 | ✅ | ✅ | | 설비 대장 (CRUD) | 등록/수정/삭제/복원, SoftDeletes | ✅ | ✅ | | 설비 점검 | 6주기(일일~반년), 그리드 셀 토글, 종합판정 | ✅ | ✅ | | 점검 템플릿 | 설비별 점검항목 정의, 주기간 복사 | ✅ | ✅ | | 수리이력 | 사내/외주, 비용, 시간, 업체 관리 | ✅ | ✅ | | 설비 사진 | 파일 업로드/삭제 | ✅ | ✅ | | 엑셀 Import | 미리보기 + 일괄등록, 이미지 포함 | ✅ | — | | 모바일 점검 | QR 스캔 → 모바일 점검 화면 | ✅ | — | | 설비-공정 매핑 | N:N 관계, 주 설비 여부 | ✅ | ✅ | --- ## 2. DB 테이블 > 마이그레이션: `api/database/migrations/` (MNG에서 생성 금지) ### 2.1 테이블 목록 | 테이블 | 설명 | 마이그레이션 | |--------|------|-------------| | `equipments` | 설비 마스터 | `2026_02_25_100000` | | `equipment_inspection_templates` | 점검항목 템플릿 | `2026_02_25_100100` | | `equipment_inspections` | 점검 헤더 (설비+주기+기간) | `2026_02_25_100200` | | `equipment_inspection_details` | 점검 상세 (셀 단위 결과) | `2026_02_25_100300` | | `equipment_repairs` | 수리이력 | `2026_02_25_100400` | | `equipment_process` | 설비-공정 매핑 (N:N pivot) | `2026_02_25_100500` | 추가 마이그레이션: | 마이그레이션 | 설명 | |-------------|------| | `2026_02_28_100000` | `sub_manager_id` 컬럼 추가 | | `2026_02_28_100100` | templates에 `inspection_cycle` 추가 + 유니크 변경 | | `2026_02_28_100200` | inspections에 `inspection_cycle` 추가 + 유니크 변경 | | `2026_03_12_100000` | `equipments`, `equipment_repairs`에 `options` JSON 추가 | | `2026_03_12_100001` | 기본 DB에 테이블 존재 보장 (`hasTable` 체크) | > **DB 연결 참고**: 기존 MNG 마이그레이션이 `codebridge` DB에 테이블을 생성했으나, API에서는 기본 DB(`sam`/`sam_prod`)에 테이블이 필요하다. `2026_03_12_100001` 마이그레이션이 기본 DB에 테이블이 없으면 최신 스키마로 생성한다. ### 2.2 ERD 개요 ``` equipments (설비 마스터) ├── 1:N → equipment_inspection_templates (점검항목 정의) ├── 1:N → equipment_inspections (점검 헤더) │ └── 1:N → equipment_inspection_details (점검 상세) ├── 1:N → equipment_repairs (수리이력) ├── N:N → processes (via equipment_process) └── 1:N → files (사진, document_type='equipment') ``` ### 2.3 주요 컬럼 #### `equipments` | 컬럼 | 타입 | 설명 | |------|------|------| | `tenant_id` | bigint | 테넌트 ID | | `equipment_code` | varchar(20) | 설비코드 (UNIQUE per tenant) | | `name` | varchar(100) | 설비명 | | `equipment_type` | varchar(50) | 유형: 포밍기/미싱기/샤링기/V컷팅기/절곡기/프레스/드릴/기타 | | `production_line` | varchar(50) | 라인: 스라트/스크린/절곡/기타 | | `status` | varchar(20) | active/idle/disposed | | `manager_id` | FK → users | 정 담당자 | | `sub_manager_id` | FK → users | 부 담당자 | | `purchase_date` | date | 구입일 | | `install_date` | date | 설치일 | | `purchase_price` | decimal(15,2) | 구입가격 | | `useful_life` | int | 내용연수 | | `options` | json | 확장 속성 JSON | | `sort_order` | int | 정렬순서 | #### `equipment_inspection_templates` | 컬럼 | 타입 | 설명 | |------|------|------| | `equipment_id` | FK → equipments | 설비 | | `inspection_cycle` | varchar | 점검주기 (daily/weekly/monthly/bimonthly/quarterly/semiannual) | | `item_no` | int | 항목번호 | | `check_point` | varchar(50) | 점검개소 | | `check_item` | varchar(100) | 점검항목 | | `check_timing` | varchar(20) | 시기: operating/stopped | | `check_method` | text | 점검방법 및 기준 | #### `equipment_inspections` | 컬럼 | 타입 | 설명 | |------|------|------| | `equipment_id` | FK → equipments | 설비 | | `inspection_cycle` | varchar | 점검주기 | | `year_month` | varchar(7) | 기간 (daily: `2026-03`, 그 외: `2026`) | | `overall_judgment` | varchar(10) | 종합판정: OK/NG | | `inspector_id` | FK → users | 점검자 | | `repair_note` | text | 수리내역 | | `issue_note` | text | 이상내용 | #### `equipment_inspection_details` | 컬럼 | 타입 | 설명 | |------|------|------| | `inspection_id` | FK → inspections | 점검 헤더 | | `template_item_id` | FK → templates | 점검항목 | | `check_date` | date | 점검일 | | `result` | varchar(10) | good(○)/bad(X)/repaired(△) | #### `equipment_repairs` | 컬럼 | 타입 | 설명 | |------|------|------| | `equipment_id` | FK → equipments | 설비 | | `repair_date` | date | 수리일 | | `repair_type` | varchar(20) | internal(사내)/external(외주) | | `repair_hours` | decimal(5,1) | 수리시간 | | `cost` | decimal(15,2) | 수리비용 | | `vendor` | varchar(100) | 외주업체 | | `repaired_by` | FK → users | 수리자 | | `options` | json | 확장 속성 JSON | --- ## 3. API 구현 현황 (Phase 1 완료) ### 3.1 모델 (`api/app/Models/Equipment/`) | 모델 | Traits | 특이사항 | |------|--------|---------| | `Equipment` | Auditable, BelongsToTenant, ModelTrait, SoftDeletes | `options` cast, `getOption()`/`setOption()` | | `EquipmentInspection` | Auditable, BelongsToTenant, ModelTrait | — | | `EquipmentInspectionDetail` | ModelTrait | `getNextResult()`, `getResultSymbol()` static | | `EquipmentInspectionTemplate` | Auditable, BelongsToTenant, ModelTrait | — | | `EquipmentRepair` | Auditable, BelongsToTenant, ModelTrait, SoftDeletes | `options` cast, `getOption()`/`setOption()` | | `EquipmentProcess` | — | pivot 모델 | ### 3.2 Enum (`api/app/Enums/InspectionCycle.php`) 6개 점검주기를 관리하는 헬퍼 클래스: | 주기 | 코드 | period 형식 | 그리드 열 | |------|------|------------|----------| | 일일 | `daily` | `2026-03` (년-월) | 1~31일 | | 주간 | `weekly` | `2026` (년) | 1~52주 | | 월간 | `monthly` | `2026` (년) | 1~12월 | | 2개월 | `bimonthly` | `2026` (년) | 1~6 | | 분기 | `quarterly` | `2026` (년) | 1~4분기 | | 반년 | `semiannual` | `2026` (년) | 상/하반기 | 주요 메서드: `columnLabels()`, `resolveCheckDate()`, `resolvePeriod()`, `isNonWorkingDay()`, `getHolidayDates(int $tenantId)` > **MNG→API 변환**: `getHolidayDates()`가 `session('selected_tenant_id')` 대신 명시적 `$tenantId` 매개변수를 받는다. ### 3.3 서비스 (`api/app/Services/Equipment/`) 모든 서비스는 `extends Service` (base class)를 사용하며, 쓰기 작업은 `DB::transaction()`으로 감싼다. | 서비스 | 핵심 메서드 | |--------|-----------| | `EquipmentService` | `index()`, `show()`, `store()`, `update()`, `destroy()`, `restore()`, `toggleActive()`, `stats()`, `options()` | | `EquipmentInspectionService` | `getInspections()`, `toggleDetail()`, `setResult()`, `updateNotes()`, `resetInspection()`, `saveTemplate()`, `updateTemplate()`, `deleteTemplate()`, `copyTemplates()`, `getActiveCycles()` | | `EquipmentRepairService` | `index()`, `store()`, `update()`, `destroy()` | | `EquipmentPhotoService` | `index()`, `store()`, `destroy()` | ### 3.4 컨트롤러 (`api/app/Http/Controllers/V1/Equipment/`) | 컨트롤러 | DI | 메서드 | |---------|-----|-------| | `EquipmentController` | `EquipmentService` | index, show, store, update, destroy, restore, toggleActive, stats, options | | `EquipmentInspectionController` | `EquipmentInspectionService` | index, toggleDetail, setResult, updateNotes, resetInspection, templates, storeTemplate, updateTemplate, deleteTemplate, copyTemplates | | `EquipmentRepairController` | `EquipmentRepairService` | index, store, update, destroy | | `EquipmentPhotoController` | `EquipmentPhotoService` | index, store, destroy | ### 3.5 FormRequest (`api/app/Http/Requests/V1/Equipment/`) | 클래스 | 용도 | |--------|------| | `StoreEquipmentRequest` | 설비 등록 (코드 unique per tenant) | | `UpdateEquipmentRequest` | 설비 수정 (`sometimes` 규칙) | | `StoreEquipmentRepairRequest` | 수리이력 등록/수정 | | `StoreInspectionTemplateRequest` | 점검항목 등록 (cycle enum 검증) | | `ToggleInspectionDetailRequest` | 점검 셀 토글 | | `UpdateInspectionNotesRequest` | 점검 메모/판정 수정 | ### 3.6 API 라우트 (`api/routes/api/v1/equipment.php`) 26개 엔드포인트, prefix: `/v1/equipment` ``` 설비 CRUD (9): GET /v1/equipment → index (목록+검색+필터) GET /v1/equipment/options → options (드롭다운 데이터) GET /v1/equipment/stats → stats (대시보드 통계) POST /v1/equipment → store GET /v1/equipment/{id} → show PUT /v1/equipment/{id} → update DELETE /v1/equipment/{id} → destroy (soft delete) POST /v1/equipment/{id}/restore → restore PATCH /v1/equipment/{id}/toggle → toggleActive 점검 템플릿 (5): GET /v1/equipment/{id}/templates → templates (활성 주기 목록) POST /v1/equipment/{id}/templates → storeTemplate PUT /v1/equipment/templates/{templateId} → updateTemplate DELETE /v1/equipment/templates/{templateId} → deleteTemplate POST /v1/equipment/{id}/templates/copy → copyTemplates 점검 (5): GET /v1/equipment/inspections → index (그리드 데이터) PATCH /v1/equipment/inspections/toggle → toggleDetail (셀 토글) PATCH /v1/equipment/inspections/set-result → setResult (결과 직접 설정) PATCH /v1/equipment/inspections/notes → updateNotes (메모/판정) DELETE /v1/equipment/inspections/reset → resetInspection (초기화) 수리이력 (4): GET /v1/equipment/repairs → index POST /v1/equipment/repairs → store PUT /v1/equipment/repairs/{id} → update DELETE /v1/equipment/repairs/{id} → destroy 사진 (3): GET /v1/equipment/{id}/photos → index POST /v1/equipment/{id}/photos → store DELETE /v1/equipment/{id}/photos/{fileId} → destroy ``` ### 3.7 i18n 메시지 **성공 메시지** (`lang/ko/message.php` → `equipment.*`): | 키 | 메시지 | |----|--------| | `created` | 설비가 등록되었습니다. | | `updated` | 설비 정보가 수정되었습니다. | | `deleted` | 설비가 삭제되었습니다. | | `restored` | 설비가 복원되었습니다. | | `inspection_saved` | 점검 정보가 저장되었습니다. | | `inspection_reset` | 점검 데이터가 초기화되었습니다. | | `template_created` | 점검항목이 추가되었습니다. | | `template_copied` | 점검항목이 복사되었습니다. | | `repair_created` | 수리이력이 등록되었습니다. | | `photo_uploaded` | 사진이 업로드되었습니다. | **에러 메시지** (`lang/ko/error.php` → `equipment.*`): | 키 | 메시지 | |----|--------| | `not_found` | 설비 정보를 찾을 수 없습니다. | | `template_not_found` | 점검항목을 찾을 수 없습니다. | | `inspection_not_found` | 점검 데이터를 찾을 수 없습니다. | | `repair_not_found` | 수리이력을 찾을 수 없습니다. | | `photo_not_found` | 사진을 찾을 수 없습니다. | | `invalid_cycle` | 유효하지 않은 점검주기입니다. | | `no_source_templates` | 복사할 점검항목이 없습니다. | ### 3.8 MNG→API 변환 규칙 적용 | MNG 패턴 | API 변환 | |----------|---------| | `$connection = 'codebridge'` | 제거 (기본 connection 사용) | | `session('selected_tenant_id')` | `$this->tenantId()` | | `auth()->id()` | `$this->apiUserId()` | | `DB::connection('codebridge')` | `DB::` (기본 connection) | | MNG 직접 validate | FormRequest 분리 | | 직접 문자열 에러 메시지 | `__('error.equipment.*')` i18n | | — | `Auditable` trait 추가 | | — | `DB::transaction()` 쓰기 래핑 | --- ## 4. MNG 구현 현황 ### 4.1 서비스 (`mng/app/Services/`) | 서비스 | 핵심 메서드 | |--------|-----------| | `EquipmentService` | `getEquipments()`, `createEquipment()`, `updateEquipment()`, `deleteEquipment()`, `restoreEquipment()`, `getDashboardStats()`, `getTypeStats()` | | `EquipmentInspectionService` | `getInspections()`, `toggleDetail()`, `setResult()`, `updateInspectionNotes()`, `resetEquipmentInspection()`, `resetAllInspections()`, `saveTemplate()`, `copyTemplatesToCycles()` | | `EquipmentRepairService` | `getRepairs()`, `createRepair()`, `updateRepair()`, `deleteRepair()`, `getRecentRepairs()` | | `EquipmentPhotoService` | `uploadPhotos()`, `uploadPhotoFromPath()`, `deletePhoto()`, `getPhotoUrls()`, `compressImage()` | | `EquipmentImportService` | `preview()`, `import()` — 엑셀 헤더 매핑, 이미지 추출, 중복 처리 | ### 4.2 뷰 파일 (`mng/resources/views/equipment/`) ``` equipment/ ├── dashboard.blade.php # 설비 현황 대시보드 ├── index.blade.php # 설비 대장 목록 ├── create.blade.php # 설비 등록 ├── show.blade.php # 설비 상세 ├── edit.blade.php # 설비 수정 ├── import.blade.php # 엑셀 Import ├── guide.blade.php # 설비관리 가이드 ├── inspections/ │ └── index.blade.php # 점검 그리드 (6주기) ├── repairs/ │ ├── index.blade.php # 수리이력 목록 │ └── create.blade.php # 수리이력 등록 └── partials/ ├── table.blade.php # 설비 목록 테이블 (HTMX) ├── repair-table.blade.php # 수리이력 테이블 (HTMX) ├── inspection-grid.blade.php # 점검 그리드 (HTMX) ├── qr-code.blade.php # QR 코드 └── tabs/ ├── basic-info.blade.php # 설비 기본정보 탭 ├── inspection-items.blade.php # 점검항목 탭 └── repair-history.blade.php # 수리이력 탭 ``` --- ## 5. 비즈니스 규칙 ### 5.1 설비 상태 | 상태 | 코드 | 설명 | |------|------|------| | 가동 | `active` | 정상 운영 중 | | 유휴 | `idle` | 일시 정지 | | 폐기 | `disposed` | 사용 중단 | ### 5.2 점검 권한 - 관리자(`isAdmin`): 모든 설비 점검 가능 - 일반 사용자: `manager_id` 또는 `sub_manager_id`와 일치하는 설비만 점검 가능 - 권한 없는 사용자가 점검 시도 시 403 응답 ### 5.3 점검 결과 순환 셀 클릭 시 결과가 순환한다: ``` (빈칸) → good(○) → bad(X) → repaired(△) → (빈칸) ``` ### 5.4 휴일/주말 점검 제한 - 일일 점검(`daily`)에서 주말(토/일) 및 `holidays` 테이블 등록 휴일에는 점검 기록 불가 - 다른 주기(weekly/monthly 등)에는 제한 없음 ### 5.5 설비 사진 - 최대 10장 (설비당) - Cloudflare R2에 저장 (`Storage::disk('r2')`) - 저장 경로: `{tenantId}/equipment/{year}/{month}/{storedName}` - 다중 업로드 지원 (`files[]` multipart/form-data) - 허용 확장자: jpg, jpeg, png, gif, bmp, webp (최대 10MB/파일) - 삭제 시 soft delete (`softDeleteFile()`) 적용 - MNG는 GCS + 자동 압축, API는 R2 직접 저장 - **등록 시 사진 업로드**: 등록 폼에서 사진을 미리 선택하면 대기열에 추가되고 미리보기가 표시된다. 설비 저장 완료 후 대기 중인 사진이 자동으로 업로드된다. - **수정 시 사진 관리**: 기존 사진 조회/삭제 + 새 사진 추가 가능 ### 5.6 엑셀 Import (MNG 전용) - 한글/영문 헤더 자동 매핑 - 중복 처리: skip 또는 overwrite 선택 - 엑셀 내 이미지(Drawing) 자동 추출 후 저장 (MNG: GCS, API: R2 예정) - API에서는 미구현 (Phase 2+ 검토) --- ## 6. 향후 계획 | 단계 | 내용 | 상태 | |------|------|------| | Phase 1 | API 백엔드 (모델, 서비스, 컨트롤러, 라우트) | ✅ 완료 | | Phase 2 | React 프론트엔드 | 미착수 | | Phase 3 | 테스트 + Swagger 문서 | 미착수 | | 추가 | 엑셀 Import API | 검토 중 | | 추가 | 모바일 점검 (React) | 검토 중 | --- ## 관련 문서 - [서비스 구축 계획](../../dev/dev_plans/equipment-service-build-plan.md) - [MNG 구조](../../system/mng-structure.md) - [DB 스키마 — 공통](../../system/database/commons.md) - [options 컬럼 정책](../../dev/standards/options-column-policy.md) --- **최종 업데이트**: 2026-03-12