# 3개 고객사 통합 비교분석서 > 작성일: 2026-02-10 > 대상: 스피폭스(SpiFox), 엔키드(Enkid), 알펫(Alpet) > 목적: FactoryOps v2 설비검사/품질검사 시스템의 공통 아키텍처 도출 및 업체별 차이점 해결 전략 수립 > ⚠️ **새 프로젝트 (PostgreSQL 전용)** — 기존 factoryOps 코드베이스는 참고만. asyncpg + SQLAlchemy async 사용. --- ## 1. 고객사 개요 비교 | 항목 | 스피폭스 (SpiFox) | 엔키드 (Enkid) | 알펫 (Alpet) | |------|-------------------|----------------|--------------| | **업종** | 알루미늄 전해 콘덴서 케이스 | 자동차 부품 (다이캐스팅) | PET필름 라미네이팅 알루미늄판 | | **공정 유형** | 이산 공정 (프레스) | 이산 공정 (다이캐스팅) | **연속 공정** (코일→코일) | | **설비 수** | 304대 (대규모) | 7대 (소규모) | ~15대 (중규모, 연속라인) | | **주요 설비** | CASE프레스 186, CUP프레스 32, 머신비전 30→80 | Toyo/Toshiba 다이캐스팅기 200T~650T | 언코일러, 전처리, 라미네이팅, 코팅, 리코일러 | | **PLC 파라미터** | 60+ (온도11, 압력5, 시간20+, 속도10) | 26+ (온도12, 압력6, 속도4, 전류4) | 41차원 (온도31, 농도6, 전류2, 온습도6) | | **핵심 관리 대상** | 금형 타발수, 비전검사 | 금형 마모, X-ray/CT 검사 | 온도 프로파일, 밀착력 | | **예산** | 12억/24개월 | 3.87억/11개월 | 4억/11개월 | | **품질 기준** | 불량률 1.51%→1.00% | IATF 16949 (자동차) | 밀착력 ≥ 5N, 두께 균일도 | --- ## 2. 설비검사 비교 ### 2.1 검사 대상 및 주기 | 항목 | 스피폭스 | 엔키드 | 알펫 | |------|---------|--------|------| | **일일검사** | 프레스 186대 순회 (작업자 10+대/교대) | 7대 전수 (작업자 1~2인) | 연속라인 시작 전 점검 | | **주간검사** | 금형 상태, 윤활, 건조/세척 설비 | 금형 마모 측정, 유압 점검 | 화학 용액 농도, 필터 상태 | | **월간검사** | 열처리기, 자동창고 | 3차원측정기 교정, 냉각수 | 히터 소자, 퀜칭 탱크 | | **수시검사** | 금형 교체 후, 비전 장비 캘리브레이션 | 불량 발생 시, 금형 교체 후 | 제품 전환 시, 밀착력 이상 시 | ### 2.2 부품 수명 관리 방식 | 항목 | 스피폭스 | 엔키드 | 알펫 | |------|---------|--------|------| | **주요 방식** | 타발수 (count) | 타발수 (count) + 시간 (hours) | 시간 (hours) + 날짜 (date) | | **관리 부품 예시** | 상부금형 10,000타, 하부금형 8,000타, 플런저팁 5,000타 | 금형 15,000타, 플런저팁 3,000타, 슬리브 2,000시간 | 히터 소자 5,000시간, 화학약품 30일, 라미네이팅 롤 3,000시간 | | **카운터 소스** | PLC shotno (자동) | PLC shots (자동) + 가동시간 (자동) | 가동시간 (자동) + 달력 (date 기반) | | **교체 트리거** | 9,000타 알람 → 10,000타 교체 | 알람 + 측정 확인 | 알람 + 밀착력 테스트 확인 | | **교체 후 리셋** | 카운터 0 리셋 | 카운터 0 리셋 | 카운터 0 리셋 or 날짜 갱신 | ### 2.3 검사 항목 유형 | data_type | 스피폭스 예시 | 엔키드 예시 | 알펫 예시 | |-----------|-------------|------------|----------| | **numeric** | 유압 압력 (140~160 bar), 금형 온도 (180~220℃) | 사출 압력 (80~120 MPa), 금형 온도 (200~280℃) | 라미네이팅 온도 (240~260℃), 밀착력 (≥5.0 N) | | **boolean** | 윤활 상태 OK/NG, 비전 캘리브레이션 OK/NG | 냉각수 순환 OK/NG, 유압 누유 OK/NG | 온도 프로파일 정상/이상, 필터 상태 OK/NG | | **text** | 외관 메모, 이상 발견 내용 | 불량 상세 기술, X-ray 판독 소견 | 코팅 상태 관찰 내용 | | **select** | 금형 상태 [양호/주의/교체필요] | 표면 품질 등급 [A/B/C/D] | 밀착 등급 [우수/양호/불량] | --- ## 3. 품질검사 비교 ### 3.1 검사 방식 | 항목 | 스피폭스 | 엔키드 | 알펫 | |------|---------|--------|------| | **주요 검사** | 머신비전 자동검사 (CNN) | X-ray, 3D CT, 치수 측정, 중량 | 밀착력, 두께, 표면 외관 | | **검사 단위** | 개별 제품 (전수검사) | 개별 제품 (샘플 + 전수) | **연속 코일** (구간별 샘플링) | | **판정 방식** | OK/NG (이진) | OK/NG + 불량 코드 6종 + 신뢰도 | 수치 기반 (밀착력 N 값) | | **불량 유형** | 버, 찌그러짐, 스크래치 | 기포, 미성형, 플래시, 수축, 표면, 치수/중량 | 밀착 불량, 두께 편차, 코팅 불균일 | | **자동화 수준** | 높음 (비전 80대 확장 예정) | 중간 (X-ray AI 도입 예정) | 낮음 (수동 샘플링 + 센서 모니터링) | ### 3.2 품질 데이터 흐름 **스피폭스**: ``` 프레스 생산 → 머신비전 자동검사 → OK/NG 즉시 판정 → 불량 통계 집계 → NG 이미지 저장 ``` **엔키드**: ``` 다이캐스팅 생산 → 외관검사 (Visual) → X-ray/CT 검사 → 치수측정 → 중량측정 → 불량코드 + 신뢰도 → 종합 판정 → 이미지/X-ray 첨부 ``` **알펫**: ``` 연속생산 라인 → 실시간 센서 모니터링 (온도, 두께) → 정기 샘플 채취 → 밀착력 테스트 (파괴 시험) → 구간별 합격/불합격 판정 ``` --- ## 4. 핵심 차이점 요약 ### 4.1 공통점 (80% — 단일 엔진으로 처리 가능) 1. **기준정보 구조 동일**: 설비 → 부품 → 검사템플릿 → 검사항목 (선배 개발자 원칙 그대로) 2. **검사항목 유형 동일**: numeric, boolean, text, select 4가지 data_type 3. **부품 수명 관리 원리 동일**: lifecycle_type + lifecycle_limit + 알람 임계값 4. **검사 워크플로우 동일**: 템플릿 선택 → 세션 시작 → 항목 입력 (자동저장) → 완료 5. **알람 유형 동일**: 부품 수명 초과, 검사 미실시, 스펙 이탈 6. **멀티테넌트 격리**: tenant_id 기반 데이터 격리 ### 4.2 차이점 (20% — 설정/어댑터로 흡수) | 차이 영역 | 설명 | 해결 방식 | |-----------|------|----------| | **① 카운터 소스** | PLC shotno vs 가동시간 vs 달력 | `lifecycle_type` 필드 (`count`/`hours`/`date`)로 이미 설계됨 | | **② 카운터 갱신 방식** | PLC 자동 vs 수동 입력 | `counter_source` 설정: `auto_plc`/`auto_production`/`manual` | | **③ 품질 판정 복잡도** | 이진(OK/NG) vs 다중 불량코드+신뢰도 vs 수치기반 | 검사 결과는 모두 `InspectionSession.results` JSON에 저장. 판정 로직은 템플릿의 `spec_min`/`spec_max`로 통일 | | **④ 검사 빈도/규모** | 304대 순회 vs 7대 정밀 vs 연속라인 모니터링 | UX 차이일 뿐, 데이터 모델은 동일. 대시보드 뷰만 다르게 구성 | | **⑤ 첨부파일** | 비전 이미지 vs X-ray/CT vs 없음 | `InspectionSession.results` 내 `attachments` JSON 필드 (optional) | | **⑥ 연속공정 특수성** | 알펫만 코일 단위 (개별 제품이 아님) | `subject_type='product'` 시 `product_code`에 코일 번호 사용 | --- ## 5. 업체별 설비검사/품질검사 로직 차이점 해결 전략 > **핵심 원칙**: 코드 분기(if spifox / elif enkid / elif alpet) 최소화. > **설정(Configuration)과 템플릿(Template)으로 차이를 흡수한다.** ### 5.1 전략 개요: 3-Layer 분리 ``` ┌─────────────────────────────────────────────────────┐ │ Layer 1: 공통 엔진 (Common Engine) │ │ ─ 모든 테넌트가 공유하는 코드 │ │ ─ InspectionTemplate, InspectionSession, PartCounter │ │ ─ 알람 서비스, 자동저장, 검사 완료 로직 │ │ ─ 변경: 거의 없음 │ ├─────────────────────────────────────────────────────┤ │ Layer 2: 테넌트 설정 (Tenant Configuration) │ │ ─ JSON/DB 설정으로 테넌트별 동작을 제어 │ │ ─ Tenant.workflow_config에 저장 │ │ ─ 변경: 설정값만 변경, 코드 변경 없음 │ ├─────────────────────────────────────────────────────┤ │ Layer 3: 데이터 어댑터 (Data Adapters) │ │ ─ 외부 데이터 소스별 변환 로직 │ │ ─ speedfox_adapter, enkied_adapter, alpet_adapter │ │ ─ 변경: 새 어댑터 추가 시에만 │ └─────────────────────────────────────────────────────┘ ``` ### 5.2 차이점별 구체적 해결 방안 #### ① 카운터 갱신 방식 — `Tenant.workflow_config.counter_policy` 테넌트마다 카운터가 갱신되는 방식이 다르다. 이를 코드 분기가 아닌 **테넌트 설정**으로 해결한다. ```json // 스피폭스: PLC에서 shotno가 직접 오므로 자동 갱신 { "counter_policy": { "default_source": "auto_plc", "plc_field_mapping": { "count": "shotno", "hours": null } } } // 엔키드: PLC shots + 가동시간 둘 다 자동 갱신 { "counter_policy": { "default_source": "auto_plc", "plc_field_mapping": { "count": "shot_count", "hours": "operating_hours" } } } // 알펫: 가동시간은 자동, 화학약품 수명은 날짜 기반 (자동 계산) { "counter_policy": { "default_source": "auto_time", "plc_field_mapping": { "count": null, "hours": "line_running_hours" } } } ``` **카운터 서비스 로직** (코드 변경 없이 설정으로 동작): ```python def update_counter(part: EquipmentPart, counter: PartCounter, source_data: dict, policy: dict): if part.lifecycle_type == "count": # PLC에서 카운트 필드 읽기 (필드명은 설정에서) field = policy["plc_field_mapping"]["count"] if field and field in source_data: counter.current_value = source_data[field] elif part.lifecycle_type == "hours": field = policy["plc_field_mapping"]["hours"] if field and field in source_data: counter.current_value = source_data[field] else: # auto_time: 장착일로부터 경과 시간 자동 계산 counter.current_value = hours_since(part.installed_at) elif part.lifecycle_type == "date": # 장착일로부터 경과 일수 자동 계산 counter.current_value = days_since(part.installed_at) counter.lifecycle_pct = (counter.current_value / part.lifecycle_limit) * 100 ``` #### ② 품질 판정 로직 — 템플릿 spec_min/spec_max로 통일 품질 판정의 복잡도가 업체마다 다르지만, **모두 `spec_min`/`spec_max` 범위 체크로 환원**된다. | 업체 | 판정 방식 | spec_min/spec_max 표현 | |------|----------|----------------------| | 스피폭스 | OK/NG (이진) | boolean 항목으로 표현. spec 불필요 | | 엔키드 | 6종 불량코드 + 신뢰도 | 각 측정항목마다 spec_min/max 설정. 불량코드는 select 항목으로 | | 알펫 | 밀착력 N 값 | spec_min=5.0 (하한만). 두께: spec_min=0.95, spec_max=1.05 | **불량코드/신뢰도** 같은 엔키드 특유의 데이터는 어디에? → `InspectionTemplateItem`의 `select_options`로 불량코드를 선택지로 제공. → 신뢰도(confidence)는 numeric 항목으로 별도 추가. → **새로운 모델이 필요 없다.** #### ③ 알람 임계값 — 기존 3가지 + `trend_warning` 1가지 추가 (Oracle 권고) | 알람 유형 | 스피폭스 | 엔키드 | 알펫 | |----------|---------|--------|------| | `part_lifecycle` | 금형 9,000타 도달 | 금형 12,000타 도달, 슬리브 1,800시간 | 히터 4,500시간, 약품 27일 | | `inspection_overdue` | 일일 프레스 검사 미실시 | 주간 금형 마모 측정 미실시 | 일일 농도 체크 미실시 | | `spec_violation` | 비전 NG 발생 | X-ray 기포 검출, 치수 초과 | 밀착력 < 5.0N, 온도 범위 이탈 | | `trend_warning` (**신규**) | — | 사출압력 연속 5회 경고구간 진입 | 라미네이팅 온도 연속 10회 편향 | → **4가지 알람 유형으로 3개 업체 모두 커버 가능.** → `trend_warning`은 엔키드/알펫의 "경향 관리" 수요를 흡수. SPC 전체 구현 없이 실무적 알람 제공. → `InspectionTemplateItem`에 `warning_min`/`warning_max`/`trend_window` 3개 필드 추가로 구현. **trend_warning 동작 원리**: - `spec_min`/`spec_max` = 경(hard) 이탈 → `spec_violation` (critical) - `warning_min`/`warning_max` = 연(soft) 경고구간 - `trend_window` = N → 최근 N회 연속 경고구간 진입 시 → `trend_warning` (warning) - SPC(Cp, Cpk, 관리도)는 **대시보드 리포팅** 기능으로 별도 구현 (알람 트리거가 아님) #### ④ 검사 UX — 동일 컴포넌트, 다른 사용 패턴 | UX 관점 | 스피폭스 | 엔키드 | 알펫 | |---------|---------|--------|------| | **작업자 동선** | 10+대 순회 → 빠른 체크 | 1~2대 집중 → 정밀 측정 | 라인 모니터링 → 샘플 채취 | | **검사 시간** | 짧음 (2~5분/대) | 김 (15~30분/대) | 중간 (모니터링 연속) | | **동시 진행 세션** | 많음 (5~10개) | 적음 (1~2개) | 중간 (2~3개) | | **모바일 필요** | 높음 (현장 순회) | 보통 (검사실) | 낮음 (제어실 데스크톱) | → **`InspectionTemplate.inspection_mode` 필드 추가 (Oracle 권고)**: 3가지 프론트엔드 레이아웃으로 분리. → **`inspection_mode`는 테넌트가 아닌 템플릿에 설정** — 같은 테넌트도 검사 종류마다 다른 모드 사용 가능. | `inspection_mode` | 최적 대상 | UX 특징 | |-------------------|----------|---------| | `checklist` | 스피폭스 프레스 일일검사, 엔키드 시작 전 점검 | 큰 OK/NG 버튼, 스와이프 진행, 모바일 최적화 | | `measurement` | 엔키드 품질검사, 스피폭스 비전 캘리브레이션 | 상세 폼, 이미지 업로드, 부품 추적성 | | `monitoring` | 알펫 라인 모니터링 | 수치 테이블, 인라인 트렌드 스파크라인, 데스크톱 최적화 | **프론트엔드 구현**: ``` dashboard/app/[tenant]/inspections/[id]/ _layouts/ ChecklistLayout.tsx # 빠른 체크리스트 (스와이프형) MeasurementLayout.tsx # 정밀 측정 폼 (첨부파일 지원) MonitoringLayout.tsx # 모니터링 판넬 (트렌드 차트) ``` → `next/dynamic`으로 3개 레이아웃 동적 로드. 같은 API, 같은 데이터 모델, 다른 렌더링. #### ⑤ 데이터 어댑터 — 업체별 독립 어댑터 | 어댑터 | 입력 | 출력 | 상태 | |--------|------|------|------| | `SpeedfoxAdapter` | PLC 27개 태그 (프레스) | TelemetryEvent | ✅ 구현됨 | | `EnkiedAdapter` | 품질분석 결과 JSON (6종 불량코드) | InspectionEvent | ✅ 구현됨 | | `AlpetAdapter` | PLC 41차원 센서 (연속공정) | TelemetryEvent | ❌ 신규 필요 | **AlpetAdapter 설계 방향**: ```python class AlpetAdapter(BaseAdapter): """연속공정(라미네이팅) PLC 데이터 → TelemetryEvent""" def __init__(self): super().__init__(source_system="alpet") self.tag_mapping = { # 온도 (31개) "PreHeat_Zone1": "preheat_zone1_temp", "Lami_Top_Temp": "laminating_top_temp", "Quench_Tank_Temp": "quench_tank_temp", # 농도 (6개) "NaOH_Conc": "naoh_concentration", "CrO3_Conc": "cro3_concentration", # ... (41차원 전체 매핑) } def convert_telemetry(self, raw_data): """PLC 연속공정 데이터 → TelemetryEvent""" # SpeedfoxAdapter와 동일한 패턴 ... def convert_inspection(self, raw_data): raise NotImplementedError("Alpet uses manual inspection, not automated") ``` → **기존 BaseAdapter 인터페이스 그대로 사용**. 새 어댑터 추가만 하면 됨. → 파이프라인 라우팅에 `elif source.lower() == "alpet":` 한 줄 추가. --- ## 6. Tenant.workflow_config 전체 스키마 각 테넌트의 동작 차이를 흡수하는 **설정 JSON** 전체 구조: ```json { // --- 검사 모듈 설정 --- "inspection": { "flow": "template_based", // "template_based" (v2 기본) "auto_save_interval_ms": 2000, // 자동저장 간격 (모든 테넌트 동일 권장) "allow_concurrent_sessions": true, // 동시 진행 세션 허용 여부 "max_concurrent_sessions": 10 // 최대 동시 세션 수 }, // --- 카운터 정책 --- "counter_policy": { "default_source": "auto_plc", // "auto_plc" | "auto_time" | "manual" "plc_field_mapping": { "count": "shotno", // PLC 필드명 (null이면 해당 유형 미지원) "hours": "operating_hours" // PLC 필드명 }, "auto_time_enabled": false // date/hours 유형의 자동 시간 계산 활성화 }, // --- 알람 정책 --- "alarm_policy": { "overdue_check_method": "on_access", // "on_access" | "scheduler" "default_alarm_threshold_pct": 90.0 // 부품 수명 알람 기본 임계값 (%) }, // --- 품질검사 설정 --- "quality": { "subject_type_enabled": ["equipment"], // ["equipment"] | ["equipment", "product"] "defect_codes": [], // 업체별 불량 코드 목록 (빈 배열이면 범용) "attachment_types": ["image"] // ["image"] | ["image", "xray"] | [] } } ``` **업체별 설정 예시**: ```json // --- 스피폭스 --- { "inspection": {"flow": "template_based", "max_concurrent_sessions": 20}, "counter_policy": {"default_source": "auto_plc", "plc_field_mapping": {"count": "shotno", "hours": null}}, "quality": {"subject_type_enabled": ["equipment"], "attachment_types": ["image"]} } // --- 엔키드 --- { "inspection": {"flow": "template_based", "max_concurrent_sessions": 5}, "counter_policy": {"default_source": "auto_plc", "plc_field_mapping": {"count": "shot_count", "hours": "operating_hours"}}, "quality": {"subject_type_enabled": ["equipment", "product"], "defect_codes": ["GAS_POROSITY","SHORT_SHOT","BURR_FLASH","SHRINKAGE","SURFACE_DEFECT","DIMENSION_WEIGHT"], "attachment_types": ["image", "xray"]} } // --- 알펫 --- { "inspection": {"flow": "template_based", "max_concurrent_sessions": 5}, "counter_policy": {"default_source": "auto_time", "plc_field_mapping": {"count": null, "hours": "line_running_hours"}, "auto_time_enabled": true}, "quality": {"subject_type_enabled": ["equipment"], "attachment_types": []} } ``` --- ## 7. 데이터 모델 영향도 분석 ### 7.1 기존 설계 변경 불필요 (그대로 사용) | 모델 | 이유 | |------|------| | `Machine` | 3개 업체 모두 설비 단위 관리 | | `EquipmentPart` | `lifecycle_type` = count/hours/date로 3개 업체 모두 커버 | | `InspectionTemplate` | `subject_type` = equipment/product로 설비검사/품질검사 구분 | | `InspectionTemplateItem` | `data_type` 4종으로 모든 검사항목 표현 가능 | | `InspectionSession` | `template_snapshot` + `partial_results` JSON으로 유연하게 대응 | | `PartCounter` | `current_value` + `lifecycle_pct`로 타발수/시간/날짜 모두 추적 | | `PartReplacementLog` | 교체 이력 구조 동일 | | `InspectionAlarm` | 3가지 알람 유형으로 3개 업체 모두 커버 | ### 7.2 소규모 확장 필요 (Oracle 컨설팅 반영) | 변경 | 내용 | 영향도 | |------|------|--------| | `Tenant.workflow_config` | 위 섹션 6의 JSON 스키마 적용 | 기존 필드 활용 (스키마만 확장) | | `EquipmentPart.counter_source` | 카운터 갱신 방식 명시 (`auto_plc`/`auto_time`/`manual`) | 컬럼 1개 추가 | | `InspectionTemplate.inspection_mode` | 검사 UX 모드 (`checklist`/`measurement`/`monitoring`) | 컬럼 1개 추가 | | `InspectionTemplateItem.warning_min/max` | 트렌드 경고 소프트 한계값 | 컬럼 2개 추가 | | `InspectionTemplateItem.trend_window` | 연속 N회 경고구간 진입 시 trend_warning 알람 | 컬럼 1개 추가 | | `InspectionSession.lot_number` | 엔키드 IATF 추적성용 로트/시리얼 번호 (optional) | 컬럼 1개 추가 | | `InspectionAlarm.alarm_type` | `trend_warning` 추가 (기존 3종 → 4종) | enum 값 1개 추가 | | `AlpetAdapter` | 신규 어댑터 클래스 | 파일 1개 추가 | | 파이프라인 라우팅 | `elif source == "alpet":` | 라인 2~3개 추가 | ### 7.3 변경 불필요 확인 — 신규 테이블 없음 "업체마다 다른 검사 로직" 때문에 **새로운 테이블이 필요한가?** → **아니오.** - 검사항목 차이 → `InspectionTemplateItem`의 설정값 차이로 해결 - 불량코드 차이 → `select_options` JSON으로 해결 - 카운터 소스 차이 → `workflow_config` 설정으로 해결 - 알람 임계값 차이 → `EquipmentPart.alarm_threshold` 개별 설정으로 해결 --- ## 8. 구현 우선순위 (3개 업체 동시 지원 관점) ### Phase 1 — 공통 엔진 우선 (변경 없음) 기존 development-plan.md의 Phase 0~7 그대로 진행. **스피폭스를 1차 테스트 테넌트로 사용** (설비 수 가장 많고, 요구사항 가장 구체적). ### Phase 1+ — 엔키드/알펫 테넌트 설정 추가 1. `Tenant.workflow_config` 스키마에 `counter_policy`, `quality` 설정 추가 2. `EquipmentPart`에 `counter_source` 컬럼 추가 3. 엔키드/알펫 테넌트 생성 + 설정값 적용 4. 엔키드/알펫 설비 + 부품 + 템플릿 시드 데이터 준비 ### Phase 2+ — 알펫 어댑터 개발 1. `AlpetAdapter` 구현 (BaseAdapter 상속) 2. 파이프라인 라우팅 확장 3. 연속공정 특화 템플릿 설계 (온도 프로파일 구간별 체크) ### Phase 3+ — 업체별 UX 최적화 (필요시) - 스피폭스: 대량 설비 빠른 순회 뷰 (카드 그리드) - 엔키드: 정밀 검사 상세 뷰 (X-ray 이미지 뷰어) - 알펫: 연속 모니터링 대시보드 뷰 (라인 상태 타임라인) --- ## 9. 리스크 및 미결 사항 ### 9.1 리스크 | 리스크 | 영향 | 완화 방안 | |--------|------|----------| | 알펫의 연속공정 데이터가 이산공정 모델에 안 맞을 수 있음 | 중 | 코일 번호를 product_code로 사용, 구간을 세션으로 매핑 | | 3개 업체 설비 수 차이 (304 vs 7 vs 15) → 성능 | 중 | 인덱스 최적화, 페이지네이션 (이미 설계됨) | | 업체별 현장 자료 미확보 | 고 | 설비 목록, PLC 태그, 검사지 등 사전 수집 필수 | | 엔키드 IATF 16949 규격 요구 | 중 | 검사 이력 추적성 확보 (template_snapshot으로 이미 대응) | ### 9.2 미결 사항 1. **알펫 PLC 태그 리스트** 미확보 — AlpetAdapter 구현 시 필요 2. **엔키드 X-ray 이미지 저장소** — 첨부파일 스토리지 설계 필요 (S3? 로컬?) 3. **연속공정 "검사 세션" 단위** — 코일 1롤 = 1세션? 시간 구간 = 1세션? 4. **SPC 통계적 공정관리** — 3개 업체 모두 향후 필요하지만 v2 범위 외 5. **AI 연동 포인트** — v2에서는 수동 검사만. AI 자동 판정은 다음 버전 --- ## 10. 결론 > **핵심 원칙 (Oracle 확인): "TYPE 필드로 분기하고, 테넌트 ID로는 절대 분기하지 않는다."** > 모든 차이는 `lifecycle_type`, `data_type`, `inspection_mode`, `alarm_type` 등 **엔티티의 TYPE 필드**에서 결정됨. > 코어 앱에 `if tenant == "spifox"` 같은 분기는 **0개**. - **데이터 모델**: 기존 10개 테이블 설계 유지 + 소규모 컬럼 추가 (6개 컬럼) - **알람 유형 확장**: 기존 3종 → 4종 (`trend_warning` 추가) - **검사 UX 모드**: `InspectionTemplate.inspection_mode` = `checklist`/`measurement`/`monitoring` - **추적성**: `InspectionSession.lot_number` (엔키드 IATF용, optional) - **신규 코드**: `AlpetAdapter` 1개 파일 + 프론트엔드 레이아웃 3개 - **테넌트 설정**: `workflow_config` JSON으로 카운터 정책, 품질 설정, 알람 정책 제어 - **검사 항목/스펙**: `InspectionTemplate` + `InspectionTemplateItem`으로 업체별 자유 설정 ### 주의사항 (Oracle 경고) 1. **알펫 설비 계층**: 알펫의 `equipment_id`는 개별 기계가 아닌 **라인 구간** (전처리존, 라미네이팅 스테이션 등). Machine 모델이 "라인 > 구간" 계층을 지원하는지 확인 필요 2. **엔키드 로트 추적**: IATF 16949은 검사 결과 → 특정 로트/시리얼 연결 필수. `InspectionSession.lot_number` 필드로 대응 3. **스피폭스 대규모 알람**: 304대 × 60개 PLC 파라미터 매 수신 시 알람 평가 → 과부하 위험. **알람은 검사 제출/카운터 갱신 시점에만 평가** (PLC 원시 데이터 수신 시에는 평가 안 함)