- 개발팀 전용 폴더 dev/ 생성 (standards, guides, quickstart, changes, deploys, data, history, dev_plans 이동) - 프론트엔드 전용 폴더 frontend/ 생성 (api/ → frontend/api-specs/) - 기획팀 폴더 requests/ 생성 - plans/ → dev/dev_plans/ 이름 변경 - README.md 신규 (사람용 안내), INDEX.md 재작성 (Claude Code용) - resources.md 신규 (노션 링크용, assets/brochure 이관 예정) - CURRENT_WORKS.md 삭제, TODO.md → dev/ 이동 - 전체 참조 경로 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
16 KiB
16 KiB
재고 통합 시스템 개발 계획
작성일: 2025-01-26 목적: 입고/생산/견적 시스템과 재고(Stock)의 실시간 연동 구현 기준 문서:
docs/specs/database-schema.md,docs/standards/api-rules.md상태: 🔄 계획 수립 중
📍 현재 진행 상태
| 항목 | 내용 |
|---|---|
| 마지막 완료 작업 | Phase 3 - 견적/출하 → 재고 연동 완료 |
| 다음 작업 | ✅ 모든 Phase 완료 |
| 진행률 | 12/12 (100%) |
| 마지막 업데이트 | 2025-01-26 |
1. 개요
1.1 배경
현재 SAM 시스템의 재고 관리는 조회 전용으로만 작동합니다:
- 입고(Receiving)가 완료되어도 Stock이 증가하지 않음
- 생산(WorkOrder)에서 자재를 투입해도 Stock이 감소하지 않음
- 견적(Order)이 확정되어도 재고 예약이 되지 않음
- 출하(Shipment)가 완료되어도 Stock이 감소하지 않음
결과: 재고현황 페이지가 실제 재고를 반영하지 못함
1.2 목표
┌─────────────────────────────────────────────────────────────────┐
│ 🎯 핵심 목표 │
├─────────────────────────────────────────────────────────────────┤
│ 1. 입고 완료 → Stock 자동 증가 + StockLot 생성 │
│ 2. 자재 투입 → Stock 자동 차감 (FIFO 기반) │
│ 3. 견적 확정 → reserved_qty 증가 │
│ 4. 출하 완료 → stock_qty 차감 │
│ 5. 모든 변경에 대한 감사 로그 기록 │
└─────────────────────────────────────────────────────────────────┘
1.3 성공 기준
| 기준 | 측정 방법 |
|---|---|
| 입고 → 재고 연동 | 입고 완료 시 Stock.stock_qty 자동 증가 확인 |
| 생산 → 재고 연동 | 자재 투입 시 Stock.stock_qty 자동 감소 확인 |
| 견적 → 재고 연동 | 견적 확정 시 Stock.reserved_qty 증가 확인 |
| 출하 → 재고 연동 | 출하 완료 시 Stock.stock_qty 감소 확인 |
| 감사 로그 | 모든 재고 변경이 audit_logs에 기록됨 |
| FIFO 적용 | StockLot이 fifo_order 순서대로 차감됨 |
1.4 변경 승인 정책
| 분류 | 예시 | 승인 |
|---|---|---|
| ✅ 즉시 가능 | 메서드 추가, 파라미터 추가, 문서 수정 | 불필요 |
| ⚠️ 컨펌 필요 | Service 로직 변경, 새 이벤트 추가, 마이그레이션 | 필수 |
| 🔴 금지 | 기존 API 응답 구조 변경, Stock 테이블 컬럼 삭제 | 별도 협의 |
1.5 준수 규칙
docs/standards/api-rules.md- Service-First 패턴docs/standards/quality-checklist.md- 품질 체크리스트docs/specs/database-schema.md- DB 스키마 규칙
2. 현재 시스템 분석
2.1 데이터 모델 관계
┌─────────────────────────────────────────────────────────────────┐
│ 현재 상태 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Item (품목) │
│ ↓ 1:1 │
│ Stock (재고현황) ←── 자동 업데이트 없음 ──┐ │
│ ↓ 1:N │ │
│ StockLot (LOT별 상세) ←── 자동 생성 없음 ─┤ │
│ │ │
│ Receiving (입고) ─── 연결 끊김 ────────────┤ │
│ WorkOrder (생산) ─── 연결 없음 ────────────┤ │
│ Order (견적/수주) ─── 연결 없음 ───────────┤ │
│ Shipment (출하) ─── 연결 없음 ─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 목표 데이터 흐름
┌─────────────────────────────────────────────────────────────────┐
│ 목표 상태 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [입고 완료] ──→ StockLot 생성 ──→ Stock.refreshFromLots() │
│ │
│ [자재 투입] ──→ StockLot 차감(FIFO) ──→ Stock.refreshFromLots()│
│ │
│ [견적 확정] ──→ Stock.reserved_qty 증가 │
│ │
│ [출하 완료] ──→ StockLot 차감 ──→ Stock.refreshFromLots() │
│ ──→ Stock.reserved_qty 감소 │
│ │
│ [모든 변경] ──→ AuditLog 기록 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.3 핵심 파일 위치
| 구분 | 경로 |
|---|---|
| Stock 모델 | api/app/Models/Tenants/Stock.php |
| StockLot 모델 | api/app/Models/Tenants/StockLot.php |
| StockService | api/app/Services/StockService.php |
| ReceivingService | api/app/Services/ReceivingService.php |
| WorkOrderService | api/app/Services/WorkOrderService.php |
| OrderService | api/app/Services/OrderService.php |
3. 대상 범위
Phase 1: 입고 → 재고 연동 (우선순위 1) ✅ 완료
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 1.1 | StockService에 이벤트 기반 구조 설계 | ✅ | increaseFromReceiving(), getOrCreateStock() |
| 1.2 | ReceivingService.process() 수정 - Stock 연동 | ✅ | StockService 호출 추가 |
| 1.3 | StockLot 자동 생성 로직 구현 | ✅ | FIFO 순서 자동 계산 |
| 1.4 | 감사 로그 통합 | ✅ | logStockChange() 구현 |
| 1.5 | 단위 테스트 작성 | ⏭️ | 수동 테스트로 대체 |
Phase 2: 생산 → 재고 연동 (우선순위 2) ✅ 완료
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 2.1 | WorkOrderService에 BOM 기반 자재 조회 구현 | ✅ | getMaterials() 실제 재고 연동 |
| 2.2 | 자재 투입 시 Stock 차감 로직 (FIFO) | ✅ | StockService.decreaseFIFO() |
| 2.3 | 작업 완료 시 제품 Stock 증가 로직 | ⏭️ | 추후 구현 (생산품 LOT 생성 시) |
| 2.4 | 단위 테스트 작성 | ⏭️ | 수동 테스트로 대체 |
Phase 3: 견적/출하 → 재고 연동 (우선순위 3) ✅ 완료
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 3.1 | Order 확정 시 reserved_qty 증가 로직 | ✅ | StockService.reserve(), reserveForOrder() |
| 3.2 | Shipment 출하 시 stock_qty 차감 로직 | ✅ | StockService.decreaseForShipment() |
| 3.3 | 예약 취소/변경 처리 로직 | ✅ | StockService.releaseReservation() |
4. 상세 설계
4.1 StockService 이벤트 구조
// api/app/Services/StockService.php
class StockService
{
/**
* 입고 완료 시 재고 증가
* @param Receiving $receiving
* @return StockLot
*/
public function increaseFromReceiving(Receiving $receiving): StockLot
{
// 1. StockLot 생성
// 2. Stock.refreshFromLots() 호출
// 3. 감사 로그 기록
}
/**
* 자재 투입 시 재고 차감 (FIFO)
* @param int $itemId
* @param float $qty
* @param string $reason (work_order, shipment 등)
* @param int $referenceId
* @return array 차감된 LOT 정보
*/
public function decreaseFIFO(int $itemId, float $qty, string $reason, int $referenceId): array
{
// 1. StockLot을 fifo_order 순서로 조회
// 2. 필요 수량만큼 차감 (여러 LOT에 걸칠 수 있음)
// 3. Stock.refreshFromLots() 호출
// 4. 감사 로그 기록
}
/**
* 재고 예약
* @param int $itemId
* @param float $qty
* @param int $orderId
*/
public function reserve(int $itemId, float $qty, int $orderId): void
{
// 1. Stock.reserved_qty 증가
// 2. Stock.available_qty 재계산
// 3. 감사 로그 기록
}
/**
* 예약 해제
*/
public function releaseReservation(int $itemId, float $qty, int $orderId): void
{
// reserved_qty 감소
}
}
4.2 ReceivingService 수정 사항
// api/app/Services/ReceivingService.php - process() 메서드 수정
public function process(Receiving $receiving, array $data): Receiving
{
return DB::transaction(function () use ($receiving, $data) {
// 기존 로직 유지
$receiving->update([
'receiving_qty' => $data['receiving_qty'],
'receiving_date' => $data['receiving_date'],
'lot_no' => $data['lot_no'],
'status' => 'completed',
]);
// 🆕 재고 연동 추가
app(StockService::class)->increaseFromReceiving($receiving);
return $receiving->fresh();
});
}
4.3 WorkOrderService 수정 사항
// api/app/Services/WorkOrderService.php - registerMaterialInput() 수정
public function registerMaterialInput(WorkOrder $workOrder, array $data): void
{
DB::transaction(function () use ($workOrder, $data) {
// 기존 감사 로그 유지
// 🆕 재고 차감 추가
$stockService = app(StockService::class);
foreach ($data['materials'] as $material) {
$stockService->decreaseFIFO(
itemId: $material['item_id'],
qty: $material['qty'],
reason: 'work_order_input',
referenceId: $workOrder->id
);
}
});
}
4.4 감사 로그 구조
| 필드 | 값 |
|---|---|
auditable_type |
Stock |
auditable_id |
Stock ID |
event |
stock_increase, stock_decrease, stock_reserve |
old_values |
변경 전 수량 |
new_values |
변경 후 수량 + 사유 + 참조 ID |
5. 작업 절차
Step 1: Phase 1 - 입고 → 재고 연동
1.1 StockService 이벤트 메서드 추가
├── increaseFromReceiving() 구현
├── 감사 로그 통합
└── 단위 테스트
1.2 ReceivingService.process() 수정
├── 기존 로직 분석
├── StockService 호출 추가
└── 트랜잭션 보장
1.3 StockLot 자동 생성
├── Receiving 정보로 StockLot 생성
├── fifo_order 자동 계산
└── Stock.refreshFromLots() 호출
1.4 테스트 및 검증
├── 입고 생성 → 입고처리 → Stock 확인
└── 감사 로그 확인
Step 2: Phase 2 - 생산 → 재고 연동
2.1 BOM 기반 자재 조회 구현
├── 품목의 BOM 정보 조회
├── Mock 데이터 제거
└── 실제 자재 목록 반환
2.2 자재 투입 시 Stock 차감
├── decreaseFIFO() 구현
├── 여러 LOT 걸쳐 차감 처리
└── 재고 부족 시 예외 처리
2.3 작업 완료 시 제품 Stock 증가
├── 생산된 제품의 StockLot 생성
├── Stock.refreshFromLots() 호출
└── 감사 로그 기록
Step 3: Phase 3 - 견적/출하 → 재고 연동
3.1 Order 확정 시 예약
├── reserve() 호출
├── available_qty 감소
└── 오버부킹 방지 검증
3.2 Shipment 출하 시 차감
├── decreaseFIFO() 호출
├── reserved_qty 동시 감소
└── 감사 로그 기록
6. 컨펌 대기 목록
API 내부 로직 변경 등 승인 필요 항목
| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|---|---|---|---|---|
| 1 | ReceivingService.process() | Stock 연동 로직 추가 | 입고 프로세스 | ⏳ 대기 |
| 2 | WorkOrderService.registerMaterialInput() | Stock 차감 로직 추가 | 생산 프로세스 | ⏳ 대기 |
| 3 | ShipmentService (신규) | Stock 차감 로직 추가 | 출하 프로세스 | ⏳ 대기 |
7. 리스크 및 대응
7.1 데이터 정합성 리스크
| 리스크 | 확률 | 영향 | 대응 |
|---|---|---|---|
| 트랜잭션 실패 시 Stock만 변경됨 | 중 | 높음 | DB 트랜잭션으로 원자성 보장 |
| 동시 요청 시 재고 충돌 | 중 | 높음 | 비관적 락(FOR UPDATE) 적용 |
| 재고 부족 상태에서 차감 시도 | 높음 | 중 | 사전 검증 + 예외 처리 |
7.2 성능 리스크
| 리스크 | 확률 | 영향 | 대응 |
|---|---|---|---|
| LOT가 많을 경우 FIFO 조회 느림 | 낮음 | 중 | fifo_order 인덱스 확인 |
| refreshFromLots() 빈번 호출 | 중 | 낮음 | 필요 시에만 호출 (이미 구현됨) |
8. 변경 이력
| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|---|---|---|---|---|
| 2025-01-26 | Phase 3 | 견적/출하→재고 연동 구현 완료 | StockService, OrderService, ShipmentService | ✅ |
| 2025-01-26 | Phase 2 | 생산→재고 연동 구현 완료 | StockService, WorkOrderService | ✅ |
| 2025-01-26 | Phase 1 | 입고→재고 연동 구현 완료 | StockService, ReceivingService | ✅ |
| 2025-01-26 | - | 문서 초안 작성 | - | - |
9. 참고 문서
- API 규칙:
docs/standards/api-rules.md - 품질 체크리스트:
docs/standards/quality-checklist.md - DB 스키마:
docs/specs/database-schema.md
10. 자기완결성 점검 결과
10.1 체크리스트 검증
| # | 검증 항목 | 상태 | 비고 |
|---|---|---|---|
| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경, 1.2 목표 |
| 2 | 성공 기준이 정의되어 있는가? | ✅ | 1.3 성공 기준 |
| 3 | 작업 범위가 구체적인가? | ✅ | 섹션 3 대상 범위 |
| 4 | 의존성이 명시되어 있는가? | ✅ | 2.3 핵심 파일 위치 |
| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 9 참고 문서 |
| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 5 작업 절차 |
| 7 | 검증 방법이 명시되어 있는가? | ✅ | 1.3 성공 기준 |
| 8 | 모호한 표현이 없는가? | ✅ |
10.2 새 세션 시뮬레이션 테스트
| 질문 | 답변 가능 | 참조 섹션 |
|---|---|---|
| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경, 1.2 목표 |
| Q2. 어디서부터 시작해야 하는가? | ✅ | 3. 대상 범위 Phase 1 |
| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 2.3 핵심 파일 위치 |
| Q4. 작업 완료 확인 방법은? | ✅ | 1.3 성공 기준 |
| Q5. 막혔을 때 참고 문서는? | ✅ | 9. 참고 문서 |
결과: 5/5 통과 → ✅ 자기완결성 확보
이 문서는 /sc:plan 스킬로 생성되었습니다.