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>
479 lines
25 KiB
Markdown
479 lines
25 KiB
Markdown
# 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 원시 데이터 수신 시에는 평가 안 함)
|