본문으로 건너뛰기

업그레이드 노트

판을 올릴 때 연동 쪽이 함께 고쳐야 하는 것과 첫 기동에 일어나는 일을 판별로 적습니다. 올리는 절차(설치 원라이너 재실행)는 업그레이드에 있습니다. 최신 판이 위에 옵니다.

2026.11 — 올리기 전에 할 일과 바뀐 이름​

지원 범위

지원 범위는 2026.11 이후 판 중 최근 3판입니다. 2026.10 이하에서는 업그레이드가 되지 않으니 재설치하세요(시도하면 업그레이드가 실패하고 자동으로 원래 판으로 되돌아갑니다). 업그레이드를 보세요. 아래 바뀐 이름과 연동 변경은 재설치할 때도 그대로 적용됩니다.

아래 순서대로 준비하세요. Cassandra 는 올리면 되돌릴 수 없고, 바뀐 이름에는 호환이 없습니다 — 옛 경로 · 옛 칸 · 옛 도구 이름은 업그레이드 순간 사라지므로 연동을 서버와 같이 올립니다. 현장 앱도 같은 판으로 함께 올립니다. 워크오더 수량 · 이름 변경은 다음 절에 있습니다.

1. 백업 — Cassandra r4 는 되돌릴 수 없습니다​

이 판의 Cassandra 본체는 Aster TSDB v6.0.0-r4 입니다.

r4 로 한 번 뜬 노드는 r3 이하로 되돌릴 수 없습니다

클러스터 메타데이터의 스냅샷 형식이 바뀌어, 옛 본체가 읽지 못합니다. 되돌릴 길을 남기려면 올리기 전에 해 두어야 합니다.

  1. PostgreSQL 전체 백업 — ./backup.sh --postgres full
  2. Aster TSDB 전체 백업 — ./backup.sh --cassandra full(백업과 복구)
  3. 노드마다 Cassandra 데이터 디렉터리의 system_cluster_metadata 를 복사해 둡니다
  4. 그 뒤에 새 판을 올립니다

2. 마이그레이션 V121~ — 첫 기동이 오래 걸릴 수 있습니다​

첫 기동에 Flyway 가 V121~V152 을 한 번에 적용합니다. 알람 표 정리(V121V124) · 다섯 층 설비 트리(V137V139) · 기록 표 키와 정비 이름(V140) · 외래 키(V127~V133) 등 모양을 크게 바꾸는 단계입니다. V123 은 mm_alarm 전체 행을 고치므로, 소요 시간은 알람 행 수에 따라 늘어납니다. 그동안 서버는 응답하지 않으며, 헬스체크가 먼저 unhealthy 를 낼 수 있습니다 — 컨테이너를 재시작하지 말고 로그의 Flyway migration completed. 를 기다리세요.

조건에 맞지 않는 데이터가 있으면 마이그레이션이 멈추고 서버가 뜨지 않습니다. 멈춘 단계의 변경은 되돌려지고 앞선 단계는 남습니다. 로그의 Platform version update failed 뒤에 나오는 문장대로 데이터를 고친 뒤 다시 기동하면 그 단계부터 이어집니다. 아래는 올리기 전 DB 에서 미리 볼 수 있습니다.

-- V121: 0 행이어야 합니다 — 숨겨진 채 켜져 있는 알람
SELECT alarm_seq FROM pp.mm_alarm WHERE shelved AND is_on;

-- V121: 0 이어야 합니다 — 숨겨진 알람에 확인 · 라벨이 붙은 행
SELECT count(*) FROM pp.mm_alarm
WHERE shelved AND (is_read IS TRUE OR read_user_id IS NOT NULL OR disposition IS NOT NULL
OR cause_note IS NOT NULL OR labeled_by IS NOT NULL OR labeled_at IS NOT NULL
OR failure_record_id IS NOT NULL);

-- V128: 0 이어야 합니다 — 고장 기록을 가리키지 못하는 알람 연결
SELECT count(*) FROM pp.mm_alarm a
WHERE a.failure_record_id IS NOT NULL
AND (a.failure_record_id !~ '^[0-9]{1,18}$'
OR NOT EXISTS (SELECT 1 FROM pp.mm_ram_failure f WHERE f.failure_id = a.failure_record_id::bigint));

-- V137: 1 행이어야 합니다 — 설치당 기업은 하나
SELECT enterprise_id FROM pp.mm_enterprise;

3. 바뀐 이름 — 옛 이름 호환은 없습니다​

옛 이름은 받지도 돌려주지도 않습니다. 옛 V5 경로는 404 입니다.

정비 «기록» 은 정비 «오더» 입니다.

어디옛새
V5 경로/api/v5/maintenance-records…/api/v5/maintenance-orders…
V5 경로/api/v5/asset/{asset_id}/maintenance-records/api/v5/asset/{asset_id}/maintenance-orders
MCP 도구list_maintenance_recordslist_maintenance_orders
칸 · 질의record_idmaintenance_order_id — 숫자 → 문자
칸 · 질의kind · status · cancel_reasonmaintenance_kind_code · status_code · cancel_reason_code
칸failure_idfailure_record_seq
칸plan_id · plan_namemaintenance_plan_id(숫자 → 문자) · maintenance_plan_name
칸 · 질의failure_mode · failure_mechanism · failure_cause · maintainable_item뒤에 _code. 표시 이름 *_name 과 cause_code 는 그대로
칸checklist_results[].attachment_idchecklist_results[].maintenance_attachment_seq
첨부 응답attachment_id · record_idmaintenance_attachment_seq · maintenance_order_id
목록 sort 값status · kindstatus_code · maintenance_kind_code
정비 계획 달력record_id · record_status · open_record_id · open_status · record_idsmaintenance_order_id · maintenance_order_status_code · open_maintenance_order_id · open_status_code · maintenance_order_ids
DB 표mm_maintenance_record · mm_ram_failuremm_maintenance_order · mm_failure_record

maintenance_order_id · maintenance_plan_id 를 숫자로 읽거나 비교하지 마세요. 옛 행은 번호를 그대로 둔 문자열("12")이고, 새 행은 MAINTENANCE_ORDER_000013 꼴입니다.

CMMS 웹훅의 키(PP_MAINTENANCE_WEBHOOK_URL) — 받는 쪽을 먼저 고치세요.

옛 키새 키값
record_idmaintenance_order_id문자
kindmaintenance_kind_code같음
statusstatus_code같음
failure_modefailure_mode_code같음
cancel_reasoncancel_reason_code같음
plan_idmaintenance_plan_id문자
checklist_results[].attachment_idchecklist_results[].maintenance_attachment_seq같음

text · event · asset_id · asset_name · description · requested_by · accepted_by · assignee_employee_id · external_system · external_id · owner · anomaly_found · plan_due_at · at · version 은 그대로입니다 — CMMS 웹훅.

그 밖의 기록 키와 ID 칸.

어디옛새
/ram/failures…failure_id · asset_class · equipment_class · code_statusfailure_record_seq · asset_class_code · equipment_class_code · raw_code_status_code
/ram/failures…failure_mode · mechanism · iso_cause · maintainable_itemfailure_mode_code · failure_mechanism_code · failure_cause_code · maintainable_item_code
고장 · 정비 코드 매핑map_id(숫자)fault_code_map_id · maintenance_code_map_id(문자)
/defects…defect_iddefect_record_seq
/order/{id}/notes · /progressnote_id · progress_idorder_note_seq · order_progress_seq
/alarm/config/{id}/revisionsrevision_idalarm_config_revision_seq
근무 계획 구간generation_idasset_plan_generation_seq
알람 labelfailure_idfailure_record_seq

설비 · 사이트.

옛새비고
table_typeasset_class_code화면 말은 «설비 분류». 표 mm_asset_class 의 코드 칸은 code
사이트 statusoperational_status_codeACTIVE → IN_OPERATION, INACTIVE → OUT_OF_SERVICE, CLOSED → DECOMMISSIONED. 모든 층의 공통 칸입니다
트리에 구역 · 라인 · 설비만기업 → 사이트 → 구역 → 라인 → 설비asset_type 에 E · S 가 새로 나옵니다. 설비 수를 셀 때 거르세요

ID 꼴. 새로 만드는 ID 는 도메인 풀네임 + 6자리 번호입니다. 기존 ID 는 그대로 유효하고 바뀌지 않습니다. ID 접두로 층이나 종류를 판단하지 말고 asset_type 을 읽으세요.

도메인옛 꼴(계속 유효)새 꼴
구역 · 라인 · 설비ASSET_…AREA_000001 · LINE_000001 · EQUIPMENT_000001
워크오더ORD_…ORDER_000001
캘린더 · 교대 예외CAL_… · OV_…CALENDAR_000001 · SHIFT_OVERRIDE_000001
설비 관계 · 공정 세그먼트REL_… · SEG_…ASSET_RELATION_000001 · PROCESS_SEGMENT_000001
명령 영역 · 설비 명령CMDAREA_… · CMD_…COMMAND_AREA_000001 · ASSET_COMMAND_000001
이미지IMG_…IMAGE_000001
직원EMP_…EMPLOYEE_…
알람 설정ALARM_CONFIG_00375 · ALARM_CONFIG_<태그 ID>ALARM_CONFIG_000376

번호는 빌 수 있고, 999999 를 넘으면 자릿수가 늡니다. 자세한 것은 도메인 ID 규칙.

알람 설정.

  • POST /alarm/config 에 직접 지은 ID 를 넣으면 422 alarm.invalid.alarm_config_id 입니다. 새 ID 는 GET /alarm/config/new-id 로 받습니다. 옛 꼴의 ID 는 수정만 됩니다.
  • 대역(밴드) 알람 설정은 태그당 하나입니다. 둘째는 409 입니다. EQL 알람 설정은 수에 제한이 없습니다.
  • 대역 알람 설정 ID 를 ALARM_CONFIG_<태그 ID> 로 지어서 찾지 마세요. 새 설정은 그 이름으로 없습니다. GET /alarm/config/list/by-tag?tag_id=… 에서 alarm_config_priority 가 BAND 인 것을 찾습니다.

스테이트먼트 필수 칸​

저장할 때 종류별 필수 출력 칸을 검사합니다. 빠지면 422 asset_statement.eql.missing_columns 로 거절하고, 빠진 칸을 알려 줍니다.

종류필수 칸
EVENTtimestamp · plugin · name · color · from_timestamp · to_timestamp · value
CONTEXT · AGGREGATION · COMMANDtimestamp · plugin · key · value

이미 저장된 문장은 업그레이드로 지워지지도 멈추지도 않습니다. 기동 때 그대로 배포됩니다. 다만 필수 칸이 없는 문장은 전에도 결과가 기록되지 않았고 지금도 그렇습니다 — 이벤트마다 실패로 남고 진단 diagnostic.asset.statement_failing 이 켜집니다. 그런 문장은 수정해서 저장할 때 위 검사에 걸리므로, 칸을 채워야 저장됩니다. 올린 뒤 진단 화면에서 이 코드를 찾아 고치세요.

4. 진단 — CEP 데드레터는 24시간 · 256 MiB 만 남습니다​

CEP 가 처리하지 못한 이벤트를 남기는 데드레터(PP:CEP-DEAD-LETTER)의 상한이 나이와 바이트로 정해졌습니다. 24시간이 지나거나 합계 256 MiB 를 넘으면 오래된 것부터 사라집니다. 세 번 배달돼도 처리되지 못한 이벤트만 들어갑니다. 실패 이벤트를 조사하려면 그 안에 봐야 합니다 — 데이터 보존.

5. CEP — Esper 백엔드와 문장별 CPU 지표가 없습니다​

cep.backend 값은 aster · flink 둘이고, 설정하지 않으면 aster 입니다. 표준 배포 템플릿은 cep.backend=aster 이므로 손으로 고치지 않은 설치는 할 일이 없습니다.

cep.backend=esper 로 두면 CEP 가 뜨지 않습니다

오타와 같이 값을 대며 부팅이 멈춥니다. 올리기 전에 plantpulse-cep.properties 에서 그 줄을 aster 로 바꾸거나 지우세요.

  • Esper 로 돌리던 설치는 올리기 전에 GET /api/v1/eql/portability 로 Aster CEP 가 받지 못할 문장을 확인합니다. 받지 못한 문장은 지워지지 않고 REJECTED 로 남습니다 — 한계와 거부 토큰.
  • GET /api/v1/eql/{name}/metrics 가 없어졌습니다. 문장별 CPU · 벽시계 시간도 게이지 · REST · 콘솔 패널 · 저장 모두 없습니다. 문장 지표는 GET /api/v1/eql/metrics/snapshot 의 매치율 · 출력율을 씁니다. PlantPulse Dashboard 의 EQL_CPU_TIME 패널에는 값이 들어오지 않습니다.
  • 읽는 코드가 없어진 설정: cep.ha.* · cep.monitor.statement_metrics_enabled · cep.monitor.cpu_estimate_max_error · cep.performance.cpu_warn_threshold_ns · cep.performance.wall_warn_threshold_ns · cep.storage.max_inflight_writes. 룰 상태 보존은 cep.aster.state.* 입니다 — 프로퍼티 참조.

6. 올린 뒤에​

  • 설정 화면에 PP_UI_CONSOLE_URL 을 넣습니다. 비어 있으면 알람 메일에 링크가 없고 QR 라벨을 만들 수 없습니다. 현장 앱을 쓰면 PP_UI_FRONTLINE_URL 도 넣습니다.
  • QR 공개 페이지는 모든 사이트에서 꺼진 채로 시작합니다.
  • 설정 화면의 MAIL_SMTP_* 값이 발송에 적용되지 않던 결함과 STARTTLS 가 «No appropriate protocol» 로 실패하던 결함이 고쳐졌습니다. 메일이 실제로 나가기 시작할 수 있으니 설정을 확인하세요 — 메일 설정.

2026-11-05 전의 2026.11 판에서 붙인 플러그인 — RAM_FAILURE_CODE_TAG · OEE_PRODUCT_BAD_COUNT_CODED 는 옛 문장이 남아 없는 태그(<태그>_CODE · <태그>_CAUSE)를 듣습니다. 다시 적용만 하면 «이미 있음 (건너뜀)» 이라 문장이 바뀌지 않습니다. 그 문장을 지운 뒤(DELETE /api/v5/asset/{asset_id}/statement/{statement_name}) 플러그인을 다시 적용하면서 코드 태그 · 불량 원인 태그를 고르십시오. 다른 문장은 그대로 둡니다. 다시 적용하기 전에 난 고장은 코드 없음으로 남습니다. 코드 태그가 실제로 <고장 태그 ID>_CODE 로 있어 잘 돌던 설치는 할 일이 없습니다.

2026.11 — 워크오더 수량과 이름을 ISA-95 / B2MML 로​

워크오더의 수량이 «숫자 하나» 에서 값 + 단위 객체(ISA-95 / B2MML QuantityValueType)로 바뀌었습니다. 칸 이름도 ISO 22400 용어로 바뀌었고, 불량이 폐기와 재작업으로 나뉘었습니다. 같은 판에서 워크오더·캘린더·고객·제품의 칸 이름도 ISA-95 / B2MML 이름으로 바뀌었습니다(title → order_name, fix_start_timestamp → planned_start_timestamp …, 아래 이름 바꿈). 호환 칸·호환 경로·별칭은 없습니다 — 옛 이름을 읽거나 보내는 연동은 업그레이드와 함께 고쳐야 합니다.

기준: V5 API 5.0 · 수량 계약 2026-10-30 · 이름 웨이브 2026-10-31 · server-web 974891b4(수량 웨이브는 30b7d9af 부터) · Flyway V99·V100·V103 · core 마이그레이션 V12V16·V21V23 · 이벤트 스키마 plantpulse.order.*·plantpulse.calendar.* major 2, plantpulse.kpi.oee.finalized major 1.

무엇이 바뀌나​

영역바뀐 것자세히
V5 수량 칸target_units+unit → planned_quantity, total_good_count → good_quantity, total_bad_count → scrap_quantity, total_production_count → produced_quantity 등. 값은 {quantity_string, data_type, unit_of_measure} 객체Order 서비스 — 수량
폐기 · 재작업scrap_quantity 는 폐기만(ISO 22400 SQ), 재작업은 새 칸 rework_quantity(RQ). 옛 total_bad_count 는 불량 합이었다 — 합이 필요하면 둘을 더한다. 화면도 폐기만인 자리는 «폐기», 합은 «불량»Order 서비스 — 폐기와 재작업
단위UN/ECE Rec 20 허용 목록 13개(EA·H87·C62·BX·SET·KGM·GRM·TNE·LTR·MLT·MTQ·MTR·MTK). 실적은 워크오더 단위로만 받는다(환산 없음). 거절은 422 E1002 + reason(quantity.unit_mismatch·quantity.not_integer …)Order 서비스 — 요청 규칙과 거절
제품 기본 단위제품의 unit_of_measure 가 새 워크오더의 기본 단위가 된다. 옛 값은 코드로 옮긴다(BOX→BX, KG→KGM, PCS·개→EA …), 알 수 없는 값은 «단위 없음»(그 제품의 새 워크오더는 EA)생산 관리 — 수량과 단위
우선순위priority 가 B2MML Priority 정수로(1 긴급·2 높음·3 보통·4 낮음, 작을수록 높다). 옛 URGENT·HIGH·NORMAL·LOW 는 1~4 로 옮겨진다
기간 KPI단위가 하나면 숫자 그대로 + unit_of_measure, 섞이면 합치지 않고 quantities_by_unit같은 곳
EMS 단위당 값energy_per_unit_kwh·co2_per_unit_kg 옆에 분모 단위 unit_of_measure같은 곳
이름 (워크오더·캘린더·고객·제품)title → order_name, fix_start_timestamp/fix_end_timestamp → 워크오더는 planned_start_timestamp/planned_end_timestamp, 캘린더는 start_timestamp/end_timestamp, external_order_id → external_id, external_po_id → customer_po_id, 고객·제품의 external_customer_id/external_product_id → external_id(+ external_system). V5·SDK·이벤트·MCP·플로우 노드·DB 칸 모두. 별칭 없음이름 바꿈
외부 워크오더 식별(external_system, external_id) 쌍. V5 POST·PUT·PATCH /order 가 둘 다 받고 응답·실적 문서가 둘 다 싣는다. GET /order/performance/by-external/{external_order_id} 는 지우고 …/by-external/{external_system}/{external_id} 로. 워크오더 하나는 GET /order/by-external/{system}/{external_id}MES 연동
이벤트plantpulse.order.* 에 planned_quantity_unit_of_measure·external_system, plantpulse.kpi.oee.finalized 에 *_quantity + unit_of_measure(정본)와 재작업 rq·rq_quantity. 타입 변경 없이 끝에 덧붙임. 이름 바꿈으로 plantpulse.order.*·plantpulse.calendar.* 는 스키마 major 2(dataschema 끝이 :2)Order 서비스 — 수량
플로우OEE_EVENT 의 수량이 Quantity 객체(rework_quantity 추가). flow_create_work_order 는 단위 값이 필수(경로 unit_of_measure_field, 기본 data.unit_of_measure). 이 노드의 경로 설정 이름도 바뀌었다(title_field → order_name_field …)플로우
화면수량마다 단위 기호가 붙는다(언어 무관 — EA, kg, L, m² …). 워크오더 양식에 단위 칸생산 관리 — 수량과 단위

숫자가 바뀌지는 않습니다. 업그레이드 전의 워크오더는 모두 EA 로 옮겨지고, 정수 개수는 그대로이므로 OEE·가용성·성능·품질과 수량 합계는 업그레이드 전후에 같습니다. 재작업은 기존 REWORK 불량 기록의 합으로 채워지고 (없으면 0), 그만큼만 scrap_quantity 가 옛 total_bad_count 보다 작아집니다.

이름 바꿈 — 옛 이름과 새 이름​

워크오더·캘린더의 칸 이름을 ISA-95 / B2MML 이름 하나로 맞췄습니다. 와이어·SDK·이벤트·DB 칸이 모두 같은 새 이름이고 옛 이름의 별칭·호환 뷰·이중 쓰기는 없습니다(server-web 974891b4, Flyway V103 order_calendar_names_isa95).

옛 이름새 이름바뀌는 곳
titleorder_name워크오더 — V5 요청·응답·/order/query 행, SDK setOrder_name, 이벤트 plantpulse.order.*(모든 종류에 덧붙음, deleted 포함), MCP list_work_orders·get_work_order_kpi, DB mm_order·mm_order_revision, Cassandra tm_asset_order
fix_start_timestamp / fix_end_timestampplanned_start_timestamp / planned_end_timestamp워크오더 — 위와 같은 곳. MCP 의 fix_start_at/fix_end_at 은 planned_start_at/planned_end_at
fix_start_timestamp / fix_end_timestampstart_timestamp / end_timestamp캘린더 — V5 요청·응답·개정 이력, SDK setStart_timestamp/setEnd_timestamp, 이벤트 plantpulse.calendar.created·updated·entry.*, DB mm_calendar·mm_calendar_revision·mm_shift
target_unitsplanned_quantityDB 칸 mm_order·mm_order_revision·mm_order_oee. V5·SDK·이벤트는 이미 planned_quantity 였다
external_order_idexternal_id워크오더 — V5 요청·응답·실적 문서·/order/query 필터, SDK setExternal_id·OrderQuery.externalId(..), 이벤트, MCP get_work_order_kpi, DB
external_po_idcustomer_po_id워크오더 — V5 요청·응답·실적 문서, SDK setCustomer_po_id, 전이 이벤트(started~aborted), MCP, DB
external_customer_id / external_product_idexternal_id + 새 칸 external_system고객·제품 — V5 요청·응답, SDK, DB. 쌍으로 찾기 GET /customer/by-external/{system}/{external_id}·/product/by-external/… 가 새로 생겼다
baseline_fix_start / baseline_fix_endbaseline_planned_start_timestamp / baseline_planned_end_timestamp워크오더 deviation 객체(V5·SDK·MCP)
정렬 fix_start_desc / fix_start_ascplanned_start_desc / planned_start_asc/order/query 의 sort
플로우 title_field · target_units_field · external_order_id_field · external_po_id_fieldorder_name_field · planned_quantity_field · external_id_field · customer_po_id_fieldflow_create_work_order 노드 설정. 기본 경로도 data.order_name · data.planned_quantity · data.planned_start_timestamp · data.planned_end_timestamp · data.external_id · data.customer_po_id 로

옛 이름은 받지 않습니다 — 조용히 무시되는 곳이 있으므로 연동을 먼저 고치세요.

  • POST·PUT /order 에 옛 이름을 보내면 그 칸은 읽히지 않습니다. order_name 이 비므로 검증 오류로 거절되고(order_name 은 필수, 공백 불가 — order.name.required), 계획 시각도 빈 값이 됩니다. 새 이름과 옛 이름을 섞어 보내면 저장은 되지만, PUT 은 요청 칸 전체를 바꾸므로 옛 이름으로 보낸 external_order_id·external_po_id 는 지워집니다.
  • PATCH /order 에 옛 이름을 보내면 422 «not patchable» 입니다.
  • /order/query?external_order_id=… 는 무시하지 않고 422 로 거절합니다 — external_id 와 external_system 을 쓰세요.
  • 이벤트는 major 2 로만 나갑니다. major 1 스키마 파일은 재생용으로 남아 있을 뿐, 새로 나가는 이벤트는 새 이름을 싣습니다.
  • /kpi/* 응답과 plantpulse.kpi.oee.finalized 의 칸 이름은 이번 바꿈의 대상이 아닙니다(그대로).

업그레이드 전에 — 외부 식별 쌍의 중복 확인​

새 판은 외부 식별 쌍이 둘 다 비어 있지 않은 워크오더끼리 유일하도록 인덱스를 겁니다(Flyway V100, ux_mm_order_external_pair). 이미 같은 쌍을 가진 워크오더가 둘 이상 있으면 그 단계가 실패하므로, 올리기 전에 확인하세요. 아래 SQL 은 올리기 전의 DB 에서 돌리므로 옛 칸 이름 external_order_id 를 씁니다(V103 이 뒤에 external_id 로 바꿉니다).

SELECT external_system, external_order_id, count(*)
FROM pp.mm_order
WHERE external_system <> '' AND external_order_id <> ''
GROUP BY 1, 2
HAVING count(*) > 1;

0 행이어야 합니다. 행이 나오면 한쪽의 external_system 이나 external_order_id 를 고친 뒤 올립니다. external_order_id 만 있고 external_system 이 비어 있는 워크오더는 쌍이 아니므로 대상이 아닙니다(그대로 남습니다).

첫 기동에 일어나는 일​

저장소언제하는 일
PostgreSQLserver-web 기동(Flyway V99 order_quantity_isa95 · V100 order_external_id_pair_unique)수량 칸을 numeric(18,4) 로 바꾸고 워크오더마다 unit_of_measure 를 'EA' 로 채운다. mm_order_oee.total_rework_count 를 더해 REWORK 불량 기록 합으로 채운다. 제품 단위를 코드로 옮기고 priority 를 정수로 바꾼다
PostgreSQL이어서 Flyway V103 order_calendar_names_isa95위 이름 바꿈 표의 DB 칸을 RENAME COLUMN 으로 바꾼다 — 데이터·인덱스·제약·뷰는 따라간다. 고객·제품에 external_system 칸과 쌍 유일 인덱스를 더하고(기존 행의 시스템은 비워 둔다), 워크오더 status 가 WAIT·START·PAUSED·END·ABORTED 밖이면 멈춘다. 상태 변경은 개정 행과 함께만 되도록 트리거를 건다
Cassandra · 저장 EQL플랫폼 첫 기동(core V21~V23)tm_asset_order 에 order_name·planned_start_timestamp·planned_end_timestamp 를 더하고 옛 칸 값을 옮긴다(V21·V22, 몇 초, 옛 칸은 지우지 않는다). 저장된 설비 스테이트먼트(EQL)의 옛 속성 이름을 새 이름으로 고쳐 쓴다(V23, SYSTEM 개정) — 고치지 못한 문은 진단 diagnostic.asset.statement_not_renamed 로 남는다
Cassandra플랫폼 첫 기동버전 마이그레이션이 작은 표(OEE·EMS 의 current·order, tm_asset_order)에 새 decimal 수량 칸과 unit_of_measure 를 더하고 기존 행을 채운다('EA') — 몇 초. 큰 표(OEE·EMS 의 rolling·rollup·history, tm_kpi_oee_count)는 기동 뒤 백그라운드로 옮긴다. 기동 자체는 평소와 같다
  • 큰 표를 옮기는 동안 이력 KPI 는 옛 칸에서 같은 값으로 읽힙니다. 표마다 이전이 끝나면 저절로 새 칸만 읽습니다. 진행은 server-web 기동 로그에 «Cassandra migration» 으로 시작하는 줄로 나옵니다(docker logs plantpulse-server-web | grep 'Cassandra migration').
  • 옛 정수 칸(target_units·total_production_count·total_good_count·total_bad_count)은 이전이 끝나면 더 이상 읽지도 쓰지도 않습니다. 칸을 지우는 것은 이 판이 아니라 나중 판의 일입니다. 새로 설치한 클러스터에는 처음부터 없습니다.

연동이 고칠 것 — 점검표​

  • SDK — plantpulse-api 를 새 판으로 올린다. setTarget_units(…)/setUnit(…) 는 없다 → setPlanned_quantity(Quantity.of("500", "EA")).
  • V5 응답을 읽는 코드 — 옛 칸 이름(target_units, total_good_count, total_bad_count, total_production_count, good_count/bad_count(수량 기록), out_of_plan_*_count …)을 새 이름으로. 값은 숫자가 아니라 quantity_string 문자열이다 — double 로 바꾸지 말고 10진 타입으로 읽는다.
  • 불량 합계를 쓰던 곳 — 옛 total_bad_count 를 scrap_quantity 로 바꾸기만 하면 재작업이 빠진다. 불량 합이 필요하면 scrap_quantity + rework_quantity.
  • 거절 처리 — 수량 거절은 422 E1002, 분기는 응답의 reason(quantity.*)으로. 수량 칸에 숫자를 그대로 넣으면 400 E1000.
  • 실적·보정 입력 — 워크오더의 단위로 보낸다. 개수 단위(EA·H87·C62·BX·SET)에 소수를 보내면 422 quantity.not_integer.
  • 기간 KPI 를 합치는 화면·리포트 — good_count 등이 null 이면 quantities_by_unit 을 본다. 단위가 다른 수량을 더하지 않는다.
  • 이름 바꿈 — V5 요청·응답을 다루는 코드에서 title·fix_start_timestamp·fix_end_timestamp·external_order_id·external_po_id(워크오더), fix_start_timestamp·fix_end_timestamp(캘린더), external_customer_id·external_product_id(고객·제품)를 새 이름으로. 별칭이 없으므로 서버와 같이 올린다.
  • SDK 세터 이름 — setTitle→setOrder_name, setFix_start_timestamp→setPlanned_start_timestamp(캘린더는 setStart_timestamp), setExternal_order_id→setExternal_id, setExternal_po_id→setCustomer_po_id, OrderQuery.externalOrderId(..)→externalId(..).
  • MES 실적 수집 — 외부 번호로 찾던 호출을 by-external/{external_system}/{external_id} 로. 워크오더를 만들 때 external_system 도 넣는다.
  • PostgreSQL 을 직접 읽는 SQL — 계획 수량은 mm_order.planned_quantity(옛 target_units)이고 문자열에서 numeric 이 된다(문자열로 읽으면 '1200.0000' 꼴). mm_order_oee 의 수량 칸도 bigint 에서 numeric(18,4). 단위는 새 칸 unit_of_measure. 그 밖에 위 이름 바꿈 표의 DB 칸 이름도 바뀐다.
  • 플로우 — OEE_EVENT 를 읽는 스크립트는 data.payload.good_quantity.quantity_string 으로. flow_create_work_order 노드에 단위 경로를 채운다. 이 노드에 title_field·target_units_field·external_order_id_field·external_po_id_field 를 직접 적어 둔 플로우는 그 설정이 읽히지 않고 새 기본 경로(data.order_name …)를 쓰므로, 새 설정 이름으로 다시 적는다. 워크오더·캘린더 이벤트의 옛 키를 읽는 스크립트도 새 이름으로.
  • 설비 스테이트먼트(EQL) — 업그레이드 뒤 진단 화면에 diagnostic.asset.statement_not_renamed 가 있으면 그 문의 옛 이름(fix_start_timestamp·title·external_order_id …)을 손으로 고친다.
  • 이벤트 소비자 — plantpulse.order.*·plantpulse.calendar.* 는 major 2 의 새 키(planned_start_timestamp·external_id·order_name …, 캘린더는 start_timestamp·end_timestamp)를 읽는다. plantpulse.kpi.oee.finalized 는 *_quantity 칸을 읽는다. sq 는 폐기만이고 재작업은 rq. 정수 gq·sq·rq·pq 는 소수 단위에서 실리지 않고 다음 major 에서 빠진다.