ERP-node/docs/screen-implementation-guide/03_production/production-plan-implementat...

34 KiB

생산계획관리 화면 구현 설계서

Screen Code: TOPSEAL_PP_MAIN (screen_id: 3985) 메뉴 경로: 생산관리 > 생산계획관리 HTML 예시: 00_화면개발_html/Cursor 폴더/화면개발/PC브라우저/생산/생산계획관리.html 작성일: 2026-03-13


1. 화면 전체 구조

+---------------------------------------------------------------------+
|                        검색 섹션 (상단)                                |
|  [품목코드] [품명] [계획기간(daterange)] [상태]                         |
|                       [사용자옵션] [엑셀업로드] [엑셀다운로드]           |
+----------------------------------+--+-------------------------------+
|     좌측 패널 (50%, 리사이즈)     |  |      우측 패널 (50%)           |
| +------------------------------+ |리| +---------------------------+ |
| | [수주데이터] [안전재고 부족분] | |사| | [완제품] [반제품]          | |
| +------------------------------+ |이| +---------------------------+ |
| | 수주 목록 헤더                 | |즈| | 완제품 생산 타임라인 헤더   | |
| |  [계획에없는품목만] [불러오기]  | |핸| |  [새로고침] [자동스케줄]    | |
| | +---------------------------+| |들| |  [병합] [반제품계획] [저장] | |
| | | 품목 그룹 테이블            || |  | | +------------------------+| |
| | | - 품목별 그룹 행 (13컬럼)  || |  | | | 옵션 패널               || |
| | |   -> 수주 상세 행 (7컬럼)  || |  | | | [리드타임] [기간] [재계산]|| |
| | | - 접기/펼치기 토글          || |  | | +------------------------+| |
| | | - 체크박스 (그룹/개별)      || |  | | | 범례                    || |
| | +---------------------------+| |  | | +------------------------+| |
| +------------------------------+ |  | | | 타임라인 스케줄러        || |
|                                  |  | | | (간트차트 형태)          || |
| -- 안전재고 부족분 탭 --          |  | | +------------------------+| |
| | 부족 품목 테이블 (8컬럼)       | |  | +---------------------------+ |
| | - 체크박스, 품목코드, 품명     | |  |                               |
| | - 현재고, 안전재고, 부족수량   | |  | -- 반제품 탭 --                |
| | - 권장생산량, 최종입고일       | |  | | 옵션 + 안내 패널            | |
| +------------------------------+ |  | | 반제품 타임라인 스케줄러     | |
+----------------------------------+--+-------------------------------+

2. 사용 테이블 및 컬럼 매핑

2.1 메인 테이블

테이블명 용도 PK
production_plan_mng 생산계획 마스터 id (serial)
sales_order_mng 수주 데이터 (좌측 패널 조회용) id (serial)
item_info 품목 마스터 (참조) id (uuid text)
inventory_stock 재고 현황 (안전재고 부족분 탭) id (uuid text)
equipment_info 설비 정보 (타임라인 리소스) id (serial)
bom / bom_detail BOM 정보 (반제품 계획 생성) id (uuid text)
work_instruction 작업지시 (타임라인 연동) 별도 확인 필요

2.2 핵심 컬럼 매핑 - production_plan_mng

컬럼명 타입 용도 HTML 매핑
id serial PK 고유 ID schedule.id
company_code varchar 멀티테넌시 -
plan_no varchar NOT NULL 계획번호 SCH-{timestamp}
plan_date date 계획 등록일 자동
item_code varchar NOT NULL 품목코드 schedule.itemCode
item_name varchar 품목명 schedule.itemName
product_type varchar 완제품/반제품 '완제품' or '반제품'
plan_qty numeric NOT NULL 계획 수량 schedule.quantity
completed_qty numeric 완료 수량 schedule.completedQty
progress_rate numeric 진행률(%) schedule.progressRate
start_date date NOT NULL 시작일 schedule.startDate
end_date date NOT NULL 종료일 schedule.endDate
due_date date 납기일 schedule.dueDate
equipment_id integer 설비 ID schedule.equipmentId
equipment_code varchar 설비 코드 -
equipment_name varchar 설비명 schedule.productionLine
status varchar 상태 planned/in_progress/completed/work-order
priority varchar 우선순위 normal/high/urgent
hourly_capacity numeric 시간당 생산능력 schedule.hourlyCapacity
daily_capacity numeric 일일 생산능력 schedule.dailyCapacity
lead_time integer 리드타임(일) schedule.leadTime
work_shift varchar 작업조 DAY/NIGHT/BOTH
work_order_no varchar 작업지시번호 schedule.workOrderNo
manager_name varchar 담당자 schedule.manager
order_no varchar 연관 수주번호 schedule.orderInfo[].orderNo
parent_plan_id integer 모 계획 ID (반제품용) schedule.parentPlanId
remarks text 비고 schedule.remarks

2.3 수주 데이터 조회용 - sales_order_mng

컬럼명 용도 좌측 테이블 컬럼 매핑
order_no 수주번호 수주 상세 행 - 수주번호
part_code 품목코드 그룹 행 - 품목코드 (그룹 기준)
part_name 품명 그룹 행 - 품목명
order_qty 수주량 총수주량 (SUM)
ship_qty 출고량 출고량 (SUM)
balance_qty 잔량 잔량 (SUM)
due_date 납기일 수주 상세 행 - 납기일
partner_id 거래처 수주 상세 행 - 거래처
status 상태 상태 배지 (일반/긴급)

2.4 안전재고 부족분 조회용 - inventory_stock + item_info

컬럼명 출처 좌측 테이블 컬럼 매핑
item_code inventory_stock 품목코드
item_name item_info (JOIN) 품목명
current_qty inventory_stock 현재고
safety_qty inventory_stock 안전재고
부족수량 계산값 (safety_qty - current_qty) 부족수량 (음수면 부족)
권장생산량 계산값 (safety_qty * 2 - current_qty) 권장생산량
last_in_date inventory_stock 최종입고일

3. V2 컴포넌트 구현 가능/불가능 분석

3.1 구현 가능 (기존 V2 컴포넌트)

기능 V2 컴포넌트 현재 상태
좌우 분할 레이아웃 v2-split-panel-layout (displayMode: "custom") layout_data에 이미 존재
검색 필터 v2-table-search-widget layout_data에 이미 존재
좌측/우측 탭 전환 v2-tabs-widget layout_data에 이미 존재
체크박스 선택 v2-table-grouped (showCheckbox: true) layout_data에 이미 존재
단순 그룹핑 테이블 v2-table-grouped (groupByColumn) layout_data에 이미 존재
타임라인 스케줄러 v2-timeline-scheduler layout_data에 이미 존재
버튼 액션 v2-button-primary layout_data에 이미 존재
안전재고 부족분 테이블 v2-table-list 또는 v2-table-grouped 미구성 (탭2에 컴포넌트 없음)

3.2 부분 구현 가능 (개선/확장 필요)

기능 문제점 필요 작업
수주 그룹 테이블 (2레벨) v2-table-grouped동일 컬럼 기준 그룹핑만 지원. HTML은 그룹 행(13컬럼)과 상세 행(7컬럼)이 완전히 다른 구조 컴포넌트 확장 or 백엔드에서 집계 데이터를 별도 API로 제공
스케줄러 옵션 패널 HTML의 안전리드타임/표시기간/재계산 옵션을 위한 전용 UI 없음 v2-input + v2-select 조합으로 구성 가능
범례 UI v2-timeline-scheduler에 statusColors 설정은 있지만 범례 UI 자체는 없음 v2-text-display 또는 커스텀 구성
부족수량 빨간색 강조 조건부 서식(conditional formatting) 미지원 컴포넌트 확장 필요
"계획에 없는 품목만" 필터 단순 테이블 필터가 아닌 교차 테이블 비교 필터 백엔드 API 필요

3.3 신규 개발 필요 (현재 V2 컴포넌트로 불가능)

기능 설명 구현 방안
자동 스케줄 생성 API 선택 품목의 필요생산계획량, 납기일, 설비 생산능력 기반으로 타임라인 자동 배치 백엔드 전용 API
선택 계획 병합 API 동일 품목 복수 스케줄을 하나로 합산 백엔드 전용 API
반제품 계획 자동 생성 API BOM 기반으로 완제품 계획에서 필요 반제품 소요량 계산 백엔드 전용 API (BOM + 재고 연계)
수주 잔량/현재고 연산 조회 API 여러 테이블 JOIN + 집계 연산으로 좌측 패널 데이터 제공 백엔드 전용 API
스케줄 상세 모달 기본정보, 근거정보, 생산정보, 계획기간, 계획분할, 설비할당 모달 화면 (TOPSEAL_PP_MODAL screen_id: 3986) 보강
설비 선택 모달 설비별 수량 할당 및 일정 등록 신규 모달 화면 필요
변경사항 확인 모달 자동 스케줄 생성 전후 비교 (신규/유지/삭제 건수 요약) 신규 모달 또는 확인 다이얼로그

4. 백엔드 API 설계

4.1 수주 데이터 조회 API (좌측 패널 - 수주데이터 탭)

GET /api/production/order-summary

목적: 수주 데이터를 품목별로 그룹핑하여 반환. 그룹 헤더에 집계값(총수주량, 출고량, 잔량, 현재고, 안전재고, 기생산계획량 등) 포함.

응답 구조:

{
  "success": true,
  "data": [
    {
      "item_code": "ITEM-001",
      "item_name": "탑씰 Type A",
      "hourly_capacity": 100,
      "daily_capacity": 800,
      "lead_time": 1,
      "total_order_qty": 1000,
      "total_ship_qty": 300,
      "total_balance_qty": 700,
      "current_stock": 100,
      "safety_stock": 150,
      "plan_ship_qty": 0,
      "existing_plan_qty": 0,
      "in_progress_qty": 0,
      "required_plan_qty": 750,
      "orders": [
        {
          "order_no": "SO-2025-101",
          "partner_name": "ABC 상사",
          "order_qty": 500,
          "ship_qty": 200,
          "balance_qty": 300,
          "due_date": "2025-11-05",
          "is_urgent": false
        },
        {
          "order_no": "SO-2025-102",
          "partner_name": "XYZ 무역",
          "order_qty": 500,
          "ship_qty": 100,
          "balance_qty": 400,
          "due_date": "2025-11-10",
          "is_urgent": false
        }
      ]
    }
  ]
}

SQL 로직 (핵심):

WITH order_summary AS (
  SELECT
    so.part_code AS item_code,
    so.part_name AS item_name,
    SUM(COALESCE(so.order_qty, 0)) AS total_order_qty,
    SUM(COALESCE(so.ship_qty, 0)) AS total_ship_qty,
    SUM(COALESCE(so.balance_qty, 0)) AS total_balance_qty
  FROM sales_order_mng so
  WHERE so.company_code = $1
    AND so.status NOT IN ('cancelled', 'completed')
    AND so.balance_qty > 0
  GROUP BY so.part_code, so.part_name
),
stock_info AS (
  SELECT
    item_code,
    SUM(COALESCE(current_qty::numeric, 0)) AS current_stock,
    MAX(COALESCE(safety_qty::numeric, 0)) AS safety_stock
  FROM inventory_stock
  WHERE company_code = $1
  GROUP BY item_code
),
plan_info AS (
  SELECT
    item_code,
    SUM(CASE WHEN status = 'planned' THEN plan_qty ELSE 0 END) AS existing_plan_qty,
    SUM(CASE WHEN status = 'in_progress' THEN plan_qty ELSE 0 END) AS in_progress_qty
  FROM production_plan_mng
  WHERE company_code = $1
    AND product_type = '완제품'
    AND status NOT IN ('completed', 'cancelled')
  GROUP BY item_code
)
SELECT
  os.*,
  COALESCE(si.current_stock, 0) AS current_stock,
  COALESCE(si.safety_stock, 0) AS safety_stock,
  COALESCE(pi.existing_plan_qty, 0) AS existing_plan_qty,
  COALESCE(pi.in_progress_qty, 0) AS in_progress_qty,
  GREATEST(
    os.total_balance_qty + COALESCE(si.safety_stock, 0) - COALESCE(si.current_stock, 0)
    - COALESCE(pi.existing_plan_qty, 0) - COALESCE(pi.in_progress_qty, 0),
    0
  ) AS required_plan_qty
FROM order_summary os
LEFT JOIN stock_info si ON os.item_code = si.item_code
LEFT JOIN plan_info pi ON os.item_code = pi.item_code
ORDER BY os.item_code;

파라미터:

  • company_code: req.user.companyCode (자동)
  • exclude_planned (optional): true이면 기존 계획이 있는 품목 제외

4.2 안전재고 부족분 조회 API (좌측 패널 - 안전재고 탭)

GET /api/production/stock-shortage

응답 구조:

{
  "success": true,
  "data": [
    {
      "item_code": "ITEM-001",
      "item_name": "탑씰 Type A",
      "current_qty": 50,
      "safety_qty": 200,
      "shortage_qty": -150,
      "recommended_qty": 300,
      "last_in_date": "2025-10-15"
    }
  ]
}

SQL 로직:

SELECT
  ist.item_code,
  ii.item_name,
  COALESCE(ist.current_qty::numeric, 0) AS current_qty,
  COALESCE(ist.safety_qty::numeric, 0) AS safety_qty,
  (COALESCE(ist.current_qty::numeric, 0) - COALESCE(ist.safety_qty::numeric, 0)) AS shortage_qty,
  GREATEST(COALESCE(ist.safety_qty::numeric, 0) * 2 - COALESCE(ist.current_qty::numeric, 0), 0) AS recommended_qty,
  ist.last_in_date
FROM inventory_stock ist
JOIN item_info ii ON ist.item_code = ii.id AND ist.company_code = ii.company_code
WHERE ist.company_code = $1
  AND COALESCE(ist.current_qty::numeric, 0) < COALESCE(ist.safety_qty::numeric, 0)
ORDER BY shortage_qty ASC;

4.3 자동 스케줄 생성 API

POST /api/production/generate-schedule

요청 body:

{
  "items": [
    {
      "item_code": "ITEM-001",
      "item_name": "탑씰 Type A",
      "required_qty": 750,
      "earliest_due_date": "2025-11-05",
      "hourly_capacity": 100,
      "daily_capacity": 800,
      "lead_time": 1,
      "orders": [
        { "order_no": "SO-2025-101", "balance_qty": 300, "due_date": "2025-11-05" },
        { "order_no": "SO-2025-102", "balance_qty": 400, "due_date": "2025-11-10" }
      ]
    }
  ],
  "options": {
    "safety_lead_time": 1,
    "recalculate_unstarted": true,
    "product_type": "완제품"
  }
}

비즈니스 로직:

  1. 각 품목의 필요생산계획량, 납기일, 일일생산능력을 기반으로 생산일수 계산
  2. 생산일수 = ceil(필요생산계획량 / 일일생산능력)
  3. 시작일 = 납기일 - 생산일수 - 안전리드타임
  4. 시작일이 오늘 이전이면 오늘로 조정
  5. recalculate_unstarted = true면 기존 진행중/작업지시/완료 스케줄은 유지, 미진행(planned)만 제거 후 재계산
  6. 결과를 production_plan_mng에 INSERT
  7. 변경사항 요약(신규/유지/삭제 건수) 반환

응답 구조:

{
  "success": true,
  "data": {
    "summary": {
      "total": 3,
      "new_count": 2,
      "kept_count": 1,
      "deleted_count": 1
    },
    "schedules": [
      {
        "id": 101,
        "plan_no": "PP-2025-0001",
        "item_code": "ITEM-001",
        "item_name": "탑씰 Type A",
        "plan_qty": 750,
        "start_date": "2025-10-30",
        "end_date": "2025-11-03",
        "due_date": "2025-11-05",
        "status": "planned"
      }
    ]
  }
}

4.4 스케줄 병합 API

POST /api/production/merge-schedules

요청 body:

{
  "schedule_ids": [101, 102, 103],
  "product_type": "완제품"
}

비즈니스 로직:

  1. 선택된 스케줄이 모두 동일 품목인지 검증
  2. 완제품/반제품이 섞여있지 않은지 검증
  3. 수량 합산, 가장 빠른 시작일/납기일, 가장 늦은 종료일 적용
  4. 원본 스케줄 DELETE, 병합된 스케줄 INSERT
  5. 수주 정보(order_no)는 병합 (중복 제거)

4.5 반제품 계획 자동 생성 API

POST /api/production/generate-semi-schedule

요청 body:

{
  "plan_ids": [101, 102],
  "options": {
    "consider_stock": true,
    "keep_in_progress": false,
    "exclude_used": true
  }
}

비즈니스 로직:

  1. 선택된 완제품 계획의 품목코드로 BOM 조회
  2. bom 테이블에서 해당 품목의 item_idbom_detail에서 하위 반제품(child_item_id) 조회
  3. 각 반제품의 필요 수량 = 완제품 계획수량 x BOM 소요량(quantity)
  4. consider_stock = true면 현재고/안전재고 감안하여 순 필요량 계산
  5. exclude_used = true면 이미 투입된 반제품 수량 차감
  6. 모품목 생산 시작일 고려하여 반제품 납기일 설정 (시작일 - 반제품 리드타임)
  7. production_plan_mngproduct_type = '반제품', parent_plan_id 설정하여 INSERT

4.6 스케줄 상세 저장/수정 API

PUT /api/production/plan/:id

요청 body:

{
  "plan_qty": 750,
  "start_date": "2025-10-30",
  "end_date": "2025-11-03",
  "equipment_id": 1,
  "equipment_code": "LINE-01",
  "equipment_name": "1호기",
  "manager_name": "홍길동",
  "work_shift": "DAY",
  "priority": "high",
  "remarks": "긴급 생산"
}

4.7 스케줄 분할 API

POST /api/production/split-schedule

요청 body:

{
  "plan_id": 101,
  "splits": [
    { "qty": 500, "start_date": "2025-10-30", "end_date": "2025-11-01" },
    { "qty": 250, "start_date": "2025-11-02", "end_date": "2025-11-03" }
  ]
}

비즈니스 로직:

  1. 분할 수량 합산이 원본 수량과 일치하는지 검증
  2. 원본 스케줄 DELETE
  3. 분할된 각 조각을 신규 INSERT (동일 order_no, item_code 유지)

5. 모달 화면 설계

5.1 스케줄 상세 모달 (screen_id: 3986 보강)

섹션 구성:

섹션 필드 타입 비고
기본 정보 품목코드, 품목명 text (readonly) 자동 채움
근거 정보 수주번호/거래처/납기일 목록 text (readonly) 연관 수주 정보 표시
생산 정보 총 생산수량 number 수정 가능
납기일 (수주 기준) date (readonly) 가장 빠른 납기일
계획 기간 계획 시작일, 종료일 date 수정 가능
생산 기간 text (readonly) 자동 계산 표시
계획 분할 분할 개수, 분할 수량 입력 select, number 분할하기 기능
설비 할당 설비 선택 버튼 button → 모달 설비 선택 모달 오픈
생산 상태 상태 select (disabled) planned/work-order/in_progress/completed
추가 정보 담당자, 작업지시번호, 비고 text 수정 가능
하단 버튼 삭제, 취소, 저장 buttons -

5.2 수주 불러오기 모달

구성:

  • 선택된 품목 목록 표시
  • 주의사항 안내
  • 라디오 버튼: "기존 계획에 추가" / "별도 계획으로 생성"
  • 취소/불러오기 버튼

5.3 안전재고 불러오기 모달

구성: 수주 불러오기 모달과 동일한 패턴

5.4 설비 선택 모달

구성:

  • 총 수량 / 할당 수량 / 미할당 수량 요약
  • 설비 카드 그리드 (설비명, 생산능력, 할당 수량 입력, 시작일/종료일)
  • 취소/저장 버튼

5.5 변경사항 확인 모달

구성:

  • 경고 메시지
  • 변경사항 요약 카드 (총 계획, 신규 생성, 유지됨, 삭제됨)
  • 변경사항 상세 목록 (품목별 변경 전/후 비교)
  • 취소/확인 및 적용 버튼

6. 현재 layout_data 수정 필요 사항

6.1 현재 layout_data 구조 (screen_id: 3985, layout_id: 9192)

comp_search (v2-table-search-widget) - 검색 필터
comp_split_panel (v2-split-panel-layout)
  ├── leftPanel (custom mode)
  │   ├── left_tabs (v2-tabs-widget) - [수주데이터, 안전재고 부족분]
  │   ├── order_table (v2-table-grouped) - 수주 테이블
  │   └── btn_import (v2-button-primary) - 선택 품목 불러오기
  ├── rightPanel (custom mode)
  │   ├── right_tabs (v2-tabs-widget) - [완제품, 반제품]
  │   │   └── finished_tab.components
  │   │       ├── v2-timeline-scheduler - 타임라인
  │   │       └── v2-button-primary - 스케줄 생성
  │   ├── btn_save (v2-button-primary) - 자동 스케줄 생성
  │   └── btn_clear (v2-button-primary) - 초기화
comp_q0iqzkpx (v2-button-primary) - 하단 저장 버튼 (무의미)

6.2 수정 필요 사항

항목 현재 상태 필요 상태
좌측 - 안전재고 탭 컴포넌트 없음 ("컴포넌트가 없습니다" 표시) v2-table-list 또는 별도 조회 API 연결된 테이블 추가
좌측 - order_table selectedTable: "sales_order_mng" (범용 API) 전용 API (/api/production/order-summary)로 변경 필요
좌측 - 체크박스 필터 없음 "계획에 없는 품목만" 체크박스 UI 추가
우측 - 반제품 탭 컴포넌트 없음 반제품 타임라인 + 옵션 패널 추가
우측 - 타임라인 selectedTable: "work_instruction" selectedTable: "production_plan_mng" + 필터 product_type='완제품'
우측 - 옵션 패널 없음 안전리드타임, 표시기간, 재계산 체크박스 → v2-input 조합
우측 - 범례 없음 v2-text-display 또는 커스텀 범례 컴포넌트
우측 - 버튼들 일부만 존재 병합, 반제품계획, 저장, 초기화 추가
하단 저장 버튼 존재 (무의미) 제거
우측 패널 렌더링 버그 타임라인 미렌더링 SplitPanelLayout custom 모드 디버깅 필요

7. 구현 단계별 계획

Phase 1: 기존 버그 수정 + 기본 구조 안정화

목표: 현재 layout_data로 화면이 최소한 정상 렌더링되게 만들기

작업 상세 예상 난이도
1-1. 좌측 z-index 겹침 수정 SplitPanelLayout의 custom 모드에서 내부 컴포넌트가 비대화형 div에 가려지는 이슈
1-2. 우측 타임라인 렌더링 수정 tabs-widget 내부 timeline-scheduler가 렌더링되지 않는 이슈
1-3. 하단 저장 버튼 제거 layout_data에서 comp_q0iqzkpx 제거
1-4. 타임라인 데이터 소스 수정 work_instructionproduction_plan_mng으로 변경

Phase 2: 백엔드 API 개발

목표: 화면에 필요한 데이터를 제공하는 전용 API 구축

작업 상세 예상 난이도
2-1. 수주 데이터 조회 API GET /api/production/order-summary (4.1 참조)
2-2. 안전재고 부족분 API GET /api/production/stock-shortage (4.2 참조)
2-3. 자동 스케줄 생성 API POST /api/production/generate-schedule (4.3 참조)
2-4. 스케줄 CRUD API PUT/DELETE /api/production/plan/:id (4.6 참조)
2-5. 스케줄 병합 API POST /api/production/merge-schedules (4.4 참조)
2-6. 반제품 계획 자동 생성 API POST /api/production/generate-semi-schedule (4.5 참조)
2-7. 스케줄 분할 API POST /api/production/split-schedule (4.7 참조)

Phase 3: layout_data 보강 + 모달 화면

목표: 안전재고 탭, 반제품 탭, 모달들 구성

작업 상세 예상 난이도
3-1. 안전재고 부족분 탭 구성 stock_tab에 테이블 컴포넌트 + "선택 품목 불러오기" 버튼 추가
3-2. 반제품 탭 구성 semi_tab에 타임라인 + 옵션 + 버튼 추가
3-3. 옵션 패널 구성 v2-input 조합으로 안전리드타임, 표시기간, 체크박스
3-4. 버튼 액션 연결 자동 스케줄, 병합, 반제품계획, 저장, 초기화 → API 연결
3-5. 스케줄 상세 모달 보강 screen_id: 3986 layout_data 수정
3-6. 수주/안전재고 불러오기 모달 신규 모달 screen 생성
3-7. 설비 선택 모달 신규 모달 screen 생성

Phase 4: v2-table-grouped 확장 (2레벨 트리 지원)

목표: HTML 예시의 "품목 그룹 → 수주 상세" 2레벨 트리 테이블 구현

작업 상세 예상 난이도
4-1. 컴포넌트 확장 설계 그룹 행과 상세 행이 다른 컬럼 구조를 가질 수 있도록 설계
4-2. expandedRowRenderer 구현 그룹 행 펼침 시 별도 컬럼/데이터로 하위 행 렌더링
4-3. 그룹 행 집계 컬럼 설정 그룹 헤더에 SUM, 계산 필드 표시 (현재고, 안전재고, 필요생산계획 등)
4-4. 조건부 서식 지원 부족수량 빨간색, 양수 초록색 등

대안: Phase 4가 너무 복잡하면, 좌측 수주데이터를 2개 연동 테이블로 분리 (상단: 품목별 집계 테이블, 하단: 선택 품목의 수주 상세 테이블) 하는 방식도 검토 가능


8. 파일 생성/수정 목록

8.1 백엔드

파일 작업 비고
backend-node/src/routes/productionRoutes.ts 라우터 등록 신규 or 기존 확장
backend-node/src/controllers/productionController.ts API 핸들러 신규 or 기존 확장
backend-node/src/services/productionPlanService.ts 비즈니스 로직 서비스 신규

8.2 DB (layout_data 수정)

대상 작업
screen_layouts_v2 (screen_id: 3985) layout_data JSON 수정
screen_layouts_v2 (screen_id: 3986) 모달 layout_data 보강
screen_definitions + screen_layouts_v2 설비 선택 모달 신규 등록
screen_definitions + screen_layouts_v2 불러오기 모달 신규 등록

8.3 프론트엔드 (API 클라이언트)

파일 작업
frontend/lib/api/production.ts 생산계획 전용 API 클라이언트 함수 추가

8.4 프론트엔드 (V2 컴포넌트 확장, Phase 4)

파일 작업
frontend/lib/registry/components/v2-table-grouped/ 2레벨 트리 지원 확장
frontend/lib/registry/components/v2-timeline-scheduler/ 옵션 패널/범례 확장 (필요시)

9. 이벤트 흐름 (주요 시나리오)

9.1 자동 스케줄 생성 흐름

1. 사용자가 좌측 수주데이터에서 품목 체크박스 선택
2. 우측 "자동 스케줄 생성" 버튼 클릭
3. (옵션 확인) 안전리드타임, 재계산 모드 체크
4. POST /api/production/generate-schedule 호출
5. (응답) 변경사항 확인 모달 표시 (신규/유지/삭제 건수)
6. 사용자 "확인 및 적용" 클릭
7. 타임라인 스케줄러 새로고침
8. 좌측 수주 목록의 "기생산계획량" 컬럼 갱신

9.2 수주 불러오기 흐름

1. 사용자가 좌측 수주데이터에서 품목 체크박스 선택
2. "선택 품목 불러오기" 버튼 클릭
3. 불러오기 모달 표시 (선택 품목 목록 + 추가방식 선택)
4. "기존 계획에 추가" or "별도 계획으로 생성" 선택
5. "불러오기" 버튼 클릭
6. POST /api/production/generate-schedule 호출 (단건)
7. 타임라인 새로고침

9.3 타임라인 스케줄 클릭 → 상세 모달

1. 사용자가 타임라인의 스케줄 바 클릭
2. 스케줄 상세 모달 오픈 (TOPSEAL_PP_MODAL)
3. 기본정보(readonly), 근거정보(readonly), 생산정보(수정가능) 표시
4. 계획기간 수정, 설비할당, 분할 등 작업
5. "저장" → PUT /api/production/plan/:id
6. "삭제" → DELETE /api/production/plan/:id
7. 모달 닫기 → 타임라인 새로고침

9.4 반제품 계획 생성 흐름

1. 우측 완제품 탭에서 스케줄 체크박스 선택
2. "선택 품목 → 반제품 계획" 버튼 클릭
3. POST /api/production/generate-semi-schedule 호출
   - BOM 조회 → 필요 반제품 목록 + 소요량 계산
   - 재고 감안 → 순 필요량 계산
   - 반제품 계획 INSERT (product_type='반제품', parent_plan_id 설정)
4. 반제품 탭으로 자동 전환
5. 반제품 타임라인 새로고침

10. 검색 필드 설정

필드명 타입 라벨 대상 컬럼
item_code text 품목코드 part_code (수주) / item_code (계획)
item_name text 품명 part_name / item_name
plan_date daterange 계획기간 start_date ~ end_date
status select 상태 전체 / 계획 / 진행 / 완료

11. 권한 및 멀티테넌시

11.1 모든 API에 적용

const companyCode = req.user!.companyCode;

if (companyCode === '*') {
  // 최고관리자: 모든 회사 데이터 조회 가능
} else {
  // 일반 회사: WHERE company_code = $1 필수
}

11.2 데이터 격리

  • production_plan_mng.company_code 필터 필수
  • sales_order_mng.company_code 필터 필수
  • inventory_stock.company_code 필터 필수
  • JOIN 시 양쪽 테이블 모두 company_code 조건 포함

12. 우선순위 정리

우선순위 작업 이유
1 (긴급) Phase 1: 기존 렌더링 버그 수정 현재 화면 자체가 정상 동작하지 않음
2 (높음) Phase 2-1, 2-2: 수주/재고 조회 API 좌측 패널의 핵심 데이터
3 (높음) Phase 2-3: 자동 스케줄 생성 API 우측 패널의 핵심 기능
4 (중간) Phase 3: layout_data 보강 안전재고 탭, 반제품 탭, 모달
5 (중간) Phase 2-4~2-7: 나머지 API 병합, 분할, 반제품 계획
6 (낮음) Phase 4: 2레벨 트리 테이블 확장 현재 단순 그룹핑으로도 기본 동작

부록 A: HTML 예시의 모달 목록

모달명 HTML ID 용도
스케줄 상세 모달 scheduleModal 스케줄 기본정보/근거정보/생산정보/계획기간/분할/설비할당/상태/추가정보
수주 불러오기 모달 orderImportModal 선택 품목 목록 + 추가방식 선택 (기존추가/별도생성)
안전재고 불러오기 모달 stockImportModal 부족 품목 목록 + 추가방식 선택
설비 선택 모달 equipmentSelectModal 설비 카드 + 수량할당 + 일정등록
변경사항 확인 모달 changeConfirmModal 자동스케줄 생성 결과 요약 + 상세 비교

부록 B: HTML 예시의 JS 핵심 함수 목록

함수명 기능 매핑 API
generateSchedule() 자동 스케줄 생성 (품목별 합산) POST /api/production/generate-schedule
saveSchedule() 스케줄 저장 (localStorage → DB) POST /api/production/plan (bulk)
mergeSelectedSchedules() 선택 계획 병합 POST /api/production/merge-schedules
generateSemiFromSelected() 반제품 계획 자동 생성 POST /api/production/generate-semi-schedule
saveScheduleFromModal() 모달에서 스케줄 저장 PUT /api/production/plan/:id
deleteScheduleFromModal() 모달에서 스케줄 삭제 DELETE /api/production/plan/:id
openOrderImportModal() 수주 불러오기 모달 열기 - (프론트엔드 UI)
importOrderItems() 수주 품목 불러오기 실행 POST /api/production/generate-schedule
openStockImportModal() 안전재고 불러오기 모달 열기 - (프론트엔드 UI)
importStockItems() 안전재고 품목 불러오기 실행 POST /api/production/generate-schedule
refreshOrderList() 수주 목록 새로고침 GET /api/production/order-summary
refreshStockList() 재고 부족 목록 새로고침 GET /api/production/stock-shortage
switchTab(tabName) 좌측 탭 전환 - (프론트엔드 UI)
switchTimelineTab(tabName) 우측 탭 전환 - (프론트엔드 UI)
toggleOrderDetails(itemGroup) 품목 그룹 펼치기/접기 - (프론트엔드 UI)
renderTimeline() 완제품 타임라인 렌더링 - (프론트엔드 UI)
renderSemiTimeline() 반제품 타임라인 렌더링 - (프론트엔드 UI)
executeSplit() 계획 분할 실행 POST /api/production/split-schedule
openEquipmentSelectModal() 설비 선택 모달 열기 GET /api/equipment (기존)
saveEquipmentSelection() 설비 할당 저장 PUT /api/production/plan/:id
applyScheduleChanges() 변경사항 확인 후 적용 - (프론트엔드 상태 관리)

부록 C: 수주 데이터 테이블 컬럼 상세

그룹 행 (품목별 집계)

# 컬럼 데이터 소스 정렬
1 체크박스 - center
2 토글 (펼치기/접기) - center
3 품목코드 sales_order_mng.part_code (GROUP BY) left
4 품목명 sales_order_mng.part_name left
5 총수주량 SUM(order_qty) right
6 출고량 SUM(ship_qty) right
7 잔량 SUM(balance_qty) right
8 현재고 inventory_stock.current_qty (JOIN) right
9 안전재고 inventory_stock.safety_qty (JOIN) right
10 출하계획량 SUM(plan_ship_qty) right
11 기생산계획량 production_plan_mng 조회 (JOIN) right
12 생산진행 production_plan_mng (status='in_progress') 조회 right
13 필요생산계획 계산값 (잔량+안전재고-현재고-기생산계획량-생산진행) right, 빨간색 강조

상세 행 (개별 수주)

# 컬럼 데이터 소스
1 (빈 칸) -
2 (빈 칸) -
3-4 수주번호, 거래처, 상태배지 order_no, partner_id → partner_name, status
5 수주량 order_qty
6 출고량 ship_qty
7 잔량 balance_qty
8-13 납기일 (colspan) due_date

부록 D: 타임라인 스케줄러 필드 매핑

완제품 타임라인

타임라인 필드 production_plan_mng 컬럼 비고
id id PK
resourceId item_code 품목 기준 리소스 (설비 기준이 아님)
title item_name + plan_qty 표시 텍스트
startDate start_date 시작일
endDate end_date 종료일
status status planned/in_progress/completed/work-order
progress progress_rate 진행률(%)

반제품 타임라인

동일 구조, 단 product_type = '반제품' 필터 적용

statusColors 매핑

상태 색상 의미
planned #3b82f6 (파란색) 계획됨
work-order #f59e0b (노란색) 작업지시
in_progress #10b981 (초록색) 진행중
completed #6b7280 (회색, 반투명) 완료
delayed #ef4444 (빨간색) 지연