[업데이트] Mublo Framework 1.3.0 - releases

wwiz 2026-08-19 13:38 조회 65 수정됨

Mublo Framework v1.3.0 을 릴리즈했습니다. 이번 버전은 반품과 교환을 하나의 워크플로우로 합치고, 배송이 주문 상태를 실제로 움직이게 만들고, 할인·적립 계산을 저장된 유형대로 바로잡는 것이 중심입니다. 에디터는 MubloEditor 1.7.1 과 공식 플러그인 4종이 함께 실립니다. 데이터베이스 마이그레이션 3건(Shop 031·032·033)이 포함됩니다.

먼저 확인해 주세요 — 실제 결제 금액이 달라질 수 있습니다

쇼핑몰을 쓰는 사이트라면 업그레이드 직후 상품 판매가와 적립액을 반드시 확인하세요.

그동안 가격 계산기가 할인 유형(정률/정액)을 보지 않고 값의 크기로 방식을 추정했습니다. 100 미만이면 %, 100 이상이면 원으로 해석했기 때문에 "정액 50원 할인"이 50% 할인으로, "정률 100% 할인"이 100원 할인으로 뒤집혀 계산되고 있었습니다. 이제 저장된 유형이 계산 방식을 정합니다. 여기에 더해 상품 화면에만 걸리고 장바구니·주문에서는 정가로 돌아가던 설정 기반 할인이 결제 금액에도 적용되고, 저장만 되고 읽는 곳이 없어 항상 0 이었던 등급별 할인·적립이 실제로 적용됩니다.

기존에 기본 할인(BASIC)으로 저장된 설정은 과거 규칙 그대로 계산하므로 갑자기 끊기지는 않습니다.

반품·교환이 하나의 워크플로우로 합쳐졌습니다

지금까지 반품은 고객 화면에 아예 없어서 전화·문의로 요청하면 관리자가 대신 등록했고, 관리자 쪽도 "요청 → 승인" 두 단계뿐이어서 승인하는 순간 물건을 받기도 전에 반품완료가 찍혔습니다.

  • 고객이 직접 반품을 신청할 수 있고, 반품도 교환과 같은 회수·검수를 거칩니다: 신청 → 승인 → 회수중 → 회수완료 → 검수중 → 환불대기 → 반품완료
  • 환불은 자동 실행하지 않습니다. 워크플로우가 환불대기까지 데려다 놓고 관리자가 환불한 뒤 확정합니다. 반품 화면에서 바로 환불할 수도 있으며, 이때 환불 기록은 그 반품 건에 귀속되어 "이 반품 건으로 N원이 이미 환불되었습니다"로 표시됩니다. 금액은 접수 때 계산해 둔 예정액으로 고정합니다 — 어긋난 금액이 나가는 길을 막기 위해서입니다.
  • 수량 단위로 나눠 신청할 수 있습니다. 3개 중 2개는 교환, 1개는 반품처럼 유형을 섞을 수 있고, 남은 수량이 있으면 버튼이 그대로 남아 이어서 신청할 수 있습니다. 이전에는 클레임이 하나라도 있으면 버튼이 사라져 나머지를 신청할 방법이 없었습니다.
  • 교환받은 상품이 또 하자여도 다시 신청할 수 있습니다. 교체품은 고객에게 있으므로 수량을 되돌립니다.
  • 반품·교환 사유가 코드가 아니라 말로 표시됩니다(DEFECT상품 불량). 이 값은 라벨이 아니라 비용 부담을 정합니다 — 불량·오배송·배송지연은 판매자 귀책이라 교환비·반품비를 물리지 않습니다.
  • 고객이 회수·교환 운송장을 볼 수 있습니다. 교환 상품이 언제 오는지 확인할 곳이 생겼습니다.
  • 관리자 주문 목록에 "반품·교환 진행중" 배지가 붙어, 주문 상세로 들어가지 않아도 처리 대기 건을 알 수 있습니다.
  • 교환 옵션이 없는 상품(단종·품절 등)도 반품은 신청할 수 있습니다. 이전에는 바꿔 줄 옵션이 없으면 버튼 자체가 나오지 않아 고객이 할 수 있는 일이 없었습니다.

관리자 메뉴 이름과 주소가 바뀝니다. 교환 관리반품·교환 관리, /admin/shop/exchanges/admin/shop/claims. 북마크를 쓰고 있다면 갱신해 주세요. 기존 반품 데이터는 상태값이 그대로 호환되며, 구 흐름으로 이미 완료된 건에는 회수·검수 기록이 없다는 메모가 붙습니다.

배송과 주문 상태가 실제로 연동됩니다

운송장은 등록해도, 배송완료로 찍어도 주문·주문상품 상태에 아무 영향을 주지 않는 별도 트랙이었습니다. 그래서 배송을 끝내도 교환 신청 버튼이 나타나지 않았고, 관리자가 품목 상태를 결제완료→배송준비→배송중→배송완료로 품목 수만큼 네 번씩 직접 눌러야 했습니다.

  • 운송장을 등록하면 그 운송장이 싣고 있는 상품이 배송중으로, 배송완료로 찍으면 배송완료로 함께 움직입니다.
  • 주문 상태를 바꾸면 주문상품도 따라옵니다. 클레임이 걸린 상품과 그 상태로 갈 수 없는 상품은 건드리지 않습니다.
  • 개별배송 주문의 상태가 실제 진행도를 따릅니다. 가장 뒤처진 상품이 주문의 상태가 되므로 3개 중 1개만 배송완료면 주문은 배송중입니다. 취소·반품이 끝난 상품은 종합에서 빼며, 주문 상태가 뒤로 가는 일은 없습니다.
  • 받은 상품을 먼저 구매확정할 수 있습니다. 구매확정이 상품 단위가 되어, 배송이 시작된 상품에만 버튼이 뜨고 그 상품만 확정됩니다. 전 상품이 확정되면 주문도 구매확정으로 올라가므로 적립 등 확정 후처리는 종전대로 주문 단위로 한 번만 실행됩니다.
  • 상태를 한 번에 목표 단계까지 옮길 수 있고, 주문 상품 목록에서 여러 건을 골라 배송 단계를 일괄 변경할 수 있습니다. 경유한 상태는 이력에만 남고 고객 알림은 최종 상태로 한 번만 나갑니다 — 같은 배송 건으로 연락이 네 번 가지 않습니다.
  • 운송장을 배송 묶음별로 등록할 수 있습니다. 배송비를 따로 받은 묶음은 반품지도 다르므로, 어느 송장이 어느 상품을 싣고 있는지 지정할 수 있습니다. 고객 주문 상세에도 운송장별 상품이 표시되어 "왜 일부만 왔지"가 의문으로 남지 않습니다. 기존 운송장은 주문 전체를 싣는 것으로 해석하므로 동작이 달라지지 않습니다.
  • 택배사 목록에 기타가 추가됩니다. 시드에 없는 지역 택배·용달용이며, 추적 URL 없이 접수만 되고 실제 택배사명은 운송장 메모에 적습니다.
  • 관리자 주문 상세가 처리 흐름을 따라 재배치되고, 배송비 묶음이 둘 이상인 주문은 상품 표가 묶음별로 나뉘어 묶음 머리에 그 묶음의 송장이 함께 붙습니다. 묶음이 하나뿐인 주문은 종전과 같은 평면 목록입니다.

부분 배송된 주문의 전액 환불을 막았습니다

주문 취소 버튼은 주문 상태만 보는데, 주문 상태는 가장 뒤처진 상품을 따릅니다. 그래서 3개 중 1개가 이미 배송완료여도 취소 버튼이 그대로 열려 있었고, 누르면 환불액이 주문 전체 기준으로 잡혀 이미 받은 상품 값까지 돌아갔습니다 — PG 결제면 자동으로. 이제 출고된 상품이 하나라도 있으면 전체 취소를 막고, 버튼 자리에 이유와 다음에 할 일을 안내합니다. 판정은 프론트와 서버가 같은 규칙을 쓰므로 눌러야 거절당하는 버튼이 생기지 않습니다.

아직 출고되지 않은 상품만 취소하는 일은 관리자가 상품별로 처리합니다(주문 상세 → 상품 → 관리 → 취소, 이어서 부분 환불). 쿠폰 할인이 주문 단위로만 저장돼 품목별 환불액을 시스템이 정할 수 없고, 그 금액은 사람이 정하는 편이 맞기 때문입니다.

에디터 — MubloEditor 1.7.1 과 공식 플러그인 4종

  • 새 편집 기능: 인용구 스타일 갤러리 34종(기본·컬러·아이콘·알림박스·특수), 체크리스트(체크 상태가 본문에 남아 글 보기에서도 유지됩니다), 목차 삽입(H1~H3 를 훑어 앵커와 함께 넣습니다), 슬래시 커맨드(빈 줄에서 /), 스마트 붙여넣기, 표 안에서 Tab 으로 셀 이동과 표 스타일 창. 저장된 기존 본문은 그대로 열립니다.
  • 워드·엑셀 문서를 본문으로 가져올 수 있습니다. 워드는 문단·제목·굵게/기울임·목록·표를, 엑셀은 첫 시트를 표로 옮깁니다. 서버에 추가로 설치할 것은 없습니다(PHP 내장 기능만 씁니다). PDF 는 아직 지원하지 않습니다 — 텍스트 추출에 외부 프로그램(poppler)이 필요해 설치된 서버에서만 되는 기능이 되기 때문입니다.
  • 링크를 붙여넣으면 미리보기(OG) 카드로 넣을 수 있습니다. 서버가 해당 페이지의 제목·설명·대표이미지를 읽어 카드로 만들고, 읽어 오지 못하면 단순 링크로 넘어갑니다. 결과는 하루 동안 캐시합니다.
  • 공식 플러그인 4종: 이미지+텍스트 레이아웃 10종, 이모티콘/스티커, 문서 가져오기(TXT·MD·HTML·CSV), 문서 내보내기(Word). full 툴바를 쓰는 에디터에 자동으로 붙고, minimal·compact 나 항목을 직접 지정한 에디터는 그대로입니다.
  • 에디터에서 만든 모습 그대로 저장됩니다. 본문 정화기의 인라인 스타일 허용 목록이 서식까지여서 테두리·배경·둥근 모서리·flex 가 저장 때 떨어져 나갔습니다. 그래서 인용구는 34종이 전부 같은 모양이 되고, 체크리스트는 체크박스가 사라지고, 이미지 레이아웃은 세로로 쌓였습니다. 넓힌 것은 CSS 뿐이며 스크립트 채널(script 태그·on* 핸들러·javascript:)은 그대로 막습니다. position·z-index 는 회원 콘텐츠가 페이지 UI 위에 겹칠 수 있어(클릭재킹) 계속 막으므로, 이미지 오버레이 레이아웃은 겹치기 대신 세로로 놓입니다.
  • 툴바 버튼과 모달에 접근성 표시(role, aria-label, aria-modal)가 붙고, 키보드로 모달을 열면 포커스가 모달 안에서 순환하며 ESC 로 닫힙니다.

스티커 라이선스 주의: 스티커의 Twemoji 그래픽은 CC-BY 4.0 이므로, 공개 사이트에서 사용하면 출처 표기가 필요합니다(plugins/stickers/twemoji/LICENSE.txt).

설치 화면

  • 공유호스팅에서 DB 연결 테스트가 접속에 성공하고도 실패로 표시되던 문제를 수정했습니다. 연결 테스트가 SHOW DATABASES 로 데이터베이스 존재를 확인했는데, 이 문장은 글로벌 권한을 요구해서 skip-show-database 로 운영하는 호스팅에서는 계정이 정상이어도 거절당했습니다. 이제 실제 설치 단계와 똑같이 dbname 을 포함해 접속해 보므로 목록 조회 권한이 필요 없고, 연결 테스트를 통과했는데 설치가 실패하는 경우도 사라집니다.
  • DB 연결 실패 원인이 비밀번호 오류 · 데이터베이스 이름 오류 · 서버 접속 불가로 구분되어 표시됩니다. 이전에는 모두 한 줄로 합쳐져 무엇을 고쳐야 하는지 알 수 없었습니다.
  • myuser_db 처럼 밑줄이 든 이름이 LIKE 와일드카드로 동작해 다른 데이터베이스에 잘못 일치할 수 있던 문제도 함께 해소되었습니다. 호스팅이 발급하는 이름은 대부분 밑줄을 포함합니다.
  • 데이터베이스 설정 화면이 브라우저 자동완성·암호관리자에 반응하지 않습니다. 이 화면이 받는 값은 사람의 로그인 자격증명이 아니라 서버 설정값입니다.

고친 것

  • 옵션 프리셋에 도메인 경계가 생겼습니다. 프리셋의 조회·수정·삭제·상품적용이 preset_id 만으로 이뤄져, 멀티도메인 환경에서 관리자가 자기 도메인 바깥의 프리셋을 읽고 고치고 지울 수 있었습니다. 프리셋을 상품에 적용할 때는 프리셋과 상품 양쪽의 도메인을 확인합니다.
  • 수동 진열 상품 블록에 먼저 들른 방문자의 가격이 다른 방문자에게 그대로 나가던 문제를 고쳤습니다. 등급별 할인이 반영되면서 이 블록은 보는 회원의 등급에 따라 다른 HTML 을 그리게 됐는데 행 캐시 키에 회원·등급 차원이 없었습니다. 이제 이 블록은 캐시하지 않습니다. 장바구니·주문은 주문 시점에 다시 계산하므로 청구 금액은 영향받지 않았습니다.
  • 자동 생성 상품코드 충돌로 상품 등록이 실패하던 문제를 고쳤습니다. 코드가 전역 유니크인데 4자리 난수로 뽑고 재시도가 없어서, 하루 118건 정도면 충돌 확률이 50%에 이르렀습니다. 이제 그날의 마지막 번호 다음을 씁니다. 상품코드를 직접 입력해 겹친 경우도 저장 전에 걸러 "이미 사용 중인 상품코드입니다"라고 알려 줍니다. 기존 코드와 형식(G-YYYYMMDD-NNNN)은 그대로입니다.
  • 교환 신청이 저장 단계에서 실패하던 문제를 고쳤습니다. 회수지 우편번호 칸이 VARCHAR(10) 인데 거기 들어가는 값은 주문의 암호화된 우편번호였습니다. 고객이 회수지를 따로 적지 않으면 항상 그 값으로 채워지므로 이 경로의 교환 신청은 Data too long 으로 통째로 실패했습니다. 관리자 화면에서 회수지 우편번호가 암호문으로 보이던 것도 함께 해결됩니다.
  • 검수 창에서 취소를 눌러도 검수가 실행되던 문제를 고쳤습니다. 검수 메모를 묻는 prompt() 가 취소의 null 을 빈 문자열로 덮어, 취소와 "메모 없이 확인"이 구별되지 않았습니다. 검수는 회수품 재고 복구와 상태 전이가 딸린 되돌릴 수 없는 처리입니다.
  • 검수 거절에 사유가 필수가 됩니다. 회수품만 고객에게 되돌아가고 이유는 어디에도 남지 않을 수 있었습니다.
  • 클레임 송장에 택배사를 고르지 않아도 저장되던 문제를 고쳤습니다. 게다가 주문 화면의 송장 수정은 클레임 송장을 "교환 관리에서 처리해주세요"라며 거절하는데 정작 교환 관리에 수정 기능이 없어 아무도 고칠 수 없었습니다. 이제 택배사가 필수이고, 반품·교환 관리의 배송 표에서 택배사·송장번호·메모를 고칠 수 있습니다.
  • 교환 완료·반송 완료·종결 버튼이 조건을 갖추기 전에는 눌리지 않고 이유를 알려 줍니다. 배송 표의 상태도 READY·IN_TRANSIT 대신 준비·배송중으로 나옵니다.
  • 교환·반품 신청이 끝나도 진행 내역이 상품 아래에 남습니다. 처리가 완료되는 순간 사라지고 좁은 칸의 작은 글씨로만 남아, 고객이 자기 교환·반품이 어떻게 됐는지 확인할 곳을 잃었습니다.
  • 전량 반품이 끝난 상품은 구매확정할 수 없습니다. 반품이 완료돼도 주문상품 상태가 배송완료로 남아, 돌려보낸 상품을 고객이 구매확정할 수 있었습니다.
  • 반품·교환 신청 창이 열려도 뒤 페이지가 같이 스크롤되던 문제, 교환 신청 버튼을 누르면 후기 작성 창이 함께 뜨던 문제를 고쳤습니다.
  • 상품 목록의 선택 삭제에 확인 절차가 생겼습니다. 관리자 목록 9개 중 상품만 확인 없이 즉시 지워졌습니다.
  • 상품에 할인 값을 0 으로 두고 기본 할인을 고르면 쇼핑몰 설정값을 읽기도 전에 "할인 없음"으로 빠져나가던 문제를 고쳤습니다.

제거된 기능

  • 쇼핑몰 → 등급별 혜택 관리자 화면이 사라집니다. 이 화면이 저장하던 등급 가격정책(할인율·적립율·무료배송·자동쿠폰)은 어떤 계산에도 연결된 적이 없어, 값을 넣어도 아무 일도 일어나지 않았습니다. 등급별 할인·적립의 저장소는 쇼핑몰 설정의 "레벨별 할인 값"과 상품별 등급 설정으로 확정했으므로, 같은 목적의 화면 두 벌 중 쓰이지 않던 쪽을 걷었습니다. 무료배송·자동쿠폰은 이 화면에서도 동작한 적이 없으며, 이번 변경으로 새로 빠지는 기능은 없습니다. shop_level_pricing 테이블은 남겨 둡니다.
  • 쇼핑몰 설정의 할인·적립 유형 선택지에서 쇼핑몰 기본설정 적용·기본 할인이 빠집니다. 설정 자신을 가리키는 자기참조라 어떤 할인으로도 풀리지 않던 값입니다. 이제 없음·등급별·정률·정액만 고를 수 있습니다. 상품 등록 화면은 그대로입니다 — 상품에서 "쇼핑몰 기본설정 적용"은 유효한 선택입니다.
  • 대응 메서드가 없어 호출하면 500 이 나던 상품 이미지·상세 삭제 라우트(/admin/shop/products/delete-image·delete-detail)를 제거했습니다. 호출하는 화면도 없어 동작하던 기능이 빠지는 것은 아닙니다.
  • 에디터 배포본에서 개발용 파일을 걷어냈습니다 — demo.html, plugins/upload/upload.html, README.md, package.json, MubloEditor.d.ts. 앞의 둘은 public 아래라 주소만 알면 그대로 열리던 페이지였습니다.

호환성 주의 (커스텀 확장·스킨 개발자)

번들 확장·스킨은 모두 대응되어 있습니다. 직접 만든 것이 있다면 아래를 확인하세요.

  • ExchangeServiceClaimService: 두 유형을 모두 소유하게 되어 이름이 바뀌었습니다. isExchangeable()isClaimable(), hasCompletedExchange()hasCompletedClaim(), ClaimRepository::hasBlockingNonExchangeClaim()hasBlockingClaimOfOtherType(). request() 에 클레임 유형 인자가 붙었고(기본값 EXCHANGE), 반품 종료용 completeRefund() 가 생겼습니다.
  • OrderService::requestItemReturn()·processItemReturn() 제거: 클레임 워크플로우가 대신합니다.
  • 주문 상세 스킨 변수: $exchangeClaimsByDetail$claimsByDetail(반품·교환을 모두 담습니다), $claimableByDetail 추가, $shipmentItemNames(운송장 id → 상품명 목록) 추가. 기존 커스텀 스킨은 새 값을 쓰지 않아도 그대로 동작합니다.
  • 고객 클레임 신청 경로 변경: POST /shop/order/{orderNo}/items/{detailId}/exchange.../claim (return_type 포함).
  • 관리자 라우트 변경: /admin/shop/exchanges/admin/shop/claims.
  • 데이터 위치 변경: 검수 결과(inspection_result)와 회수품 재고 복구 시각이 교환 대상 상품 테이블에서 클레임 본체(shop_returns)로 옮겨졌습니다. 반품에는 교환 대상 행이 없어 적을 곳이 없었습니다.
  • 추가된 API: OrderServiceadvanceItemsToState()·advanceItemsToAction()·findStateIdByAction(), ShipmentServicegetShippingGroups()·itemNamesByShipment(). ShipmentService 생성자의 네 번째 인자(ShipmentGroupResolver)는 선택이므로 기존 호출부는 그대로 두어도 됩니다.
  • 에디터 스킨: toolbarItemsblockquote 를 넣어 쓰고 있다면 버튼 위치는 그대로지만, 눌렀을 때 기본 blockquote 로 감싸는 대신 스타일 갤러리가 열립니다.

업그레이드 방법

새로 설치: MubloFramework-v1.3.0.zip (vendor 포함 배포본) 을 받아 설치하면 됩니다.

v1.2.0 에서 업그레이드: 패치 zip(mublo-1.2.0-to-1.3.0-patch.zip, 변경 파일 135개)을 설치 루트에 덮어쓰고, 아래 파일 16개를 삭제한 뒤 마이그레이션을 실행하면 됩니다.

packages/Shop/Controller/Admin/ExchangeController.php
packages/Shop/Controller/Admin/LevelPricingController.php
packages/Shop/Repository/LevelPricingRepository.php
packages/Shop/Service/ExchangeService.php
packages/Shop/Service/LevelPricingService.php
packages/Shop/tests/Unit/Service/ExchangeServiceTest.php
packages/Shop/views/Admin/Exchange/List.php
packages/Shop/views/Admin/Exchange/View.php
packages/Shop/views/Admin/Exchange/_shipment_form.php
packages/Shop/views/Admin/LevelPricing/Index.php
public/assets/lib/editor/mublo-editor/MubloEditor.d.ts
public/assets/lib/editor/mublo-editor/README.md
public/assets/lib/editor/mublo-editor/demo.html
public/assets/lib/editor/mublo-editor/package.json
public/assets/lib/editor/mublo-editor/plugins/upload/README.md
public/assets/lib/editor/mublo-editor/plugins/upload/upload.html

위 파일을 지우면 packages/Shop/views/Admin/Exchange/packages/Shop/views/Admin/LevelPricing/ 이 빈 디렉토리로 남습니다. 디렉토리째 삭제하세요.

마이그레이션 3건을 반드시 실행하세요. 관리자 → 시스템 → 마이그레이션 에서 대기 중인 항목(Shop 031·032·033)을 실행합니다. 마이그레이션은 자동으로 적용되지 않으며, 파일만 바꾸고 실행하지 않으면 새 코드가 아직 없는 컬럼을 읽어 화면이 깨집니다. 대시보드에 알림이 뜨지 않으므로 직접 확인해야 합니다.

이번 릴리즈는 composer 의존성 변경이 없으므로 vendor 디렉토리는 건드리지 않아도 됩니다. 자세한 절차는 패치 zip 안의 PATCH-NOTES.txt 를 참고하세요.

v1.2.0 미만에서 올라오는 경우에는 먼저 v1.2.0 까지의 업그레이드 절차를 완료한 뒤 이 패치를 적용하거나, 전체 배포본으로 파일을 교체하세요.

상세 변경 내역

이번 릴리즈에 포함된 PR 목록입니다. 각 링크에서 해당 변경의 코드와 논의를 볼 수 있습니다.

  • #36 — 설치: DB 연결 테스트가 목록 조회 권한을 요구하지 않게 수정
  • #37 — Shop: 할인·적립 유형과 등급별 설정이 실제 가격에 반영되게 수정
  • #38 — Shop: 프리셋 도메인 경계와 상품 관리 허점 보완
  • #39 — 문서: 사라진 1.2.0 릴리즈 섹션 복원
  • #40 — Shop: 수동 진열 상품 블록을 행 캐시에서 제외
  • #41 — Shop: 상품코드를 직접 입력해 겹쳤을 때 원인 안내
  • #42 — 에디터: MubloEditor 1.7.1 + 공식 플러그인 4종
  • #43 — 에디터: 문서 가져오기(DOCX·XLSX)와 링크 카드 서버 기능
  • #44 — Shop: 송장이 상태를 끌고 가고, 반품이 교환과 같은 워크플로우를 사용

1명이 반응했습니다.

글쓰기

댓글 0

등록된 댓글이 없습니다.