Files
factoryOps-v2/planning/integrated-analysis.md
Johngreen ab2a3e35b2 feat: Phase 0-2 complete — auth, machines, equipment parts with full CRUD
Multi-tenant factory inspection system (SpiFox, Enkid, Alpet):
- FastAPI backend with JWT auth, PostgreSQL (asyncpg)
- Next.js 16 frontend with App Router, SWR data fetching
- Machines CRUD with equipment parts management
- Part lifecycle tracking (hours/count/date) with counters
- Partial unique index for soft-delete support
- 24 pytest tests passing, E2E verified

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
2026-02-10 12:05:22 +09:00

479 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 원시 데이터 수신 시에는 평가 안 함)