프로젝트 목록

Commerce Operations

의류 쇼핑몰 운영 개선

부분 환불 하나가 매출과 고객 집계까지 바꾸고 있었다.

작업 구분
회사 프로젝트
작업 기간
2026.06 — 09
현재 상태
운영 서비스 개선

출발점과 담당 범위

커머스 운영 · 결제와 배송 연동

맡은 범위

관리 화면, PHP 처리, SQLite 집계와 외부 결제·배송·메시지 API를 함께 수정했습니다. 거래 대조와 정정 전 미리보기, 후행 확인까지 맡았습니다.

시작할 때의 상태

기존 상품·주문 데이터와 가격 모듈이 있는 운영 서비스에 참여했습니다.

개발 범위 · 기술 · 협업 자세히 읽기

시작할 때의 상태

기존 상품·주문 데이터와 가격 모듈이 있는 운영 서비스에 참여했습니다. 최초 쇼핑몰 전체를 신규 구축했다고 소개하지 않고, 확인된 운영 개선 범위를 구분합니다.

작업 개요

운영 중인 쇼핑몰의 주문·환불·배송을 개선했습니다. 눈에 보이는 화면 오류에서 출발해 금액을 계산하는 서버와 같은 값을 읽는 관리 화면까지 따라갔습니다.

개발·개선 범위

  • 부분 환불·주문 종결 규칙과 요청 화면
  • 매출·주문·고객 구매액 집계
  • 송장 발급·저장·출력·배송 웹훅
  • 알림톡·문자 공급자 요청 계약
  • 기존 가격 계산을 활용한 상품 피드
사용한 기술
PHP · SQLite · JavaScript · Toss Payments · 배송 API · 알림톡 / SMS

기존 자산 · 외부 서비스 · AI 활용

회사 운영 프로젝트입니다. 기존 상품·주문 처리와 가격 모듈을 활용하고, Claude Code·Codex와 함께 진단·구현했습니다. Toss·배송·메시지 공급자의 API와 내부 상태를 연결한 범위입니다.

제품 화면과 구조 요약

금액 계산원 결제액−누적 환불액집계에 반영할 금액금전 처리 ≠ 주문 종결
Commerce Operations환불과 주문 종결 · 설명용 도식

문제 해결

PG의 부분취소와 주문의 종료는 다른 판단이다

처리가 이어지는 순서
  1. 서버 판정

    결제 잔액·취소액·공제액으로 주문 종결을 계산

  2. 외부 취소

    PG 요청 결과 확인; 내부 DB와 비원자적

  3. 내부 기록

    환불 누적액과 조건에 맞는 주문 상태를 저장

  4. 관련 조회

    대시보드·목록·구매액이 환불 반영 금액을 사용

문제

일부 금액만 환불했는데 주문 전체가 종료되고 매출에서도 전액이 빠졌습니다.

바꾼 점

클라이언트의 종결 값을 없애고 서버가 결제 잔액·취소액·공제액으로 다시 판단하도록 바꿨습니다.

확인한 것

정정 전 미리보기, 당시 PG와 주문 DB의 거래 대조, 종결 규칙의 경우별 검사를 사용했습니다.

조사·판단·검증 과정 읽기

마주한 문제

일부 금액만 환불했는데 주문 전체가 종료되고 매출에서도 전액이 빠졌습니다. 반대로 배송비를 공제한 전체 반품은 PG에서 부분취소로 보여도 업무상 주문은 끝나야 했습니다.

확인한 과정

화면을 열 때 계산한 종결 값을 환불액 변경 후에도 서버가 신뢰하고 있었습니다. 같은 주문 금액을 읽는 대시보드·주문 목록·고객 구매액·등급 계산도 환불을 반영하는지 이어서 확인했습니다.

선택한 방법

클라이언트의 종결 값을 없애고 서버가 결제 잔액·취소액·공제액으로 다시 판단하도록 바꿨습니다. 누적 환불액을 기록하고 관련 집계는 원 결제액에서 환불액을 빼도록 맞췄습니다.

어떻게 확인했는가

정정 전 미리보기, 당시 PG와 주문 DB의 거래 대조, 종결 규칙의 경우별 검사를 사용했습니다. 새 검사가 이전 로직에서는 실패하는지도 확인한 기록을 남겨 수정 효과를 구분했습니다.

단계별 처리와 경계

  1. 서버 판정

    결제 잔액·취소액·공제액으로 주문 종결을 계산

  2. 외부 취소

    PG 요청 결과 확인; 내부 DB와 비원자적

  3. 내부 기록

    환불 누적액과 조건에 맞는 주문 상태를 저장

  4. 관련 조회

    대시보드·목록·구매액이 환불 반영 금액을 사용

구조도와 처리 경계 자세히 보기

부분취소 금액과 주문 종결 조건을 분리했다

고객에게 돌려준 금액과 주문 종결을 따로 계산하고, 주문 데이터의 후속 조회까지 구분했습니다.

  • 처리·명시된 호출
  • 비동기·별도 요청
  • 데이터 읽기·참조
  • 실패·제한 분기
부분취소 금액과 주문 종결 조건을 분리했다고객에게 돌려준 금액과 주문 종결을 따로 계산하고, 주문 데이터의 후속 조회까지 구분했습니다. 아래 단계별 설명에서 각 처리와 연결을 글로 읽을 수 있습니다.환불 요청 · 서버의 금액 판정PG 성공 뒤 · 누적 기록과 업무 종결결과·조회취소 요청비종결DB 기록 실패관리자 환불 입력금액·귀책·환불 사유공제액은 서버 정책 적용요청 처리 선점요청 행을 처리 중으로3분 내 중복 요청 거절주문 상태 검사결제완료 주문만 허용이미 종결된 주문은 거절PG 잔액 조회남은 취소 가능액 B조회 실패면 취소 중단서버 금액 계산서버 산정액 A·공제 D종결 여부를 미리 판정외부 PG 취소전액 또는 지정 금액 취소성공 응답 뒤 DB 기록주문 환불 누적누적액에 A 추가공제 배송비는 더하지 않음주문 종결인가full 또는 A + D ≥ B참: 종결 / 거짓: 유지종결 상태 변경취소·환불 상태 조건 갱신성공자만 재고·쿠폰 복구부분 환불 유지주문은 결제완료 유지부분 재고 복구는 수동요청 결과 저장요청 행 완료·PG 결과 기록요청 완료와 주문 종결 구분금액 화면 조회매출·목록·누적 구매액결제완료 금액에서 환불 차감후속 등급 계산이후 주문 때 누적액 조회환불 직후 재계산은 아님기록 실패 로그처리는 그대로 계속대조·보상은 별도 과제
좁은 화면에서는 좌우로 움직여 읽으세요. 키보드로 구조도에 초점을 둔 뒤 방향키를 사용할 수 있습니다.
판정·계산식

B=PG 잔액(없으면 주문 총액), R=요청 취소액, D=max(0, 공제액) full = R ≤ 0 또는 R ≥ B · A = full ? B : R · settle = full 또는 A + D ≥ B

환불액과 업무상 종결은 다르다
B=10만원일 때 R=3만원·D=0이면 3만원 환불 후 주문을 유지합니다. R=9.4만원·D=0.6만원이면 9.4만원만 환불하고 종결합니다. 누적액에는 공제액 D를 더하지 않습니다. (가상 예시)
결제 기록에서 후속 집계까지
당시 PG·DB 대조와 이전 로직의 실패 재현 기록을 확인했습니다. 후속 집계는 결제완료 주문의 총액에서 누적 환불액을 빼서 읽습니다. 등급은 이후 주문 처리에서 계산합니다.
동시 실행 방어의 적용 범위
3분 선점은 환불 요청 화면의 행에만 적용됩니다. 다른 주문 화면은 이 선점을 거치지 않습니다. 종결 상태의 조건부 갱신도 PG 호출 뒤라 중복 금전 실행까지 막지는 못합니다.

이 구조의 한계PG 취소와 DB 기록은 비원자적이며, 누적액 기록 실패를 로그만 남기고 계속 진행하는 경계와 별도 대조가 남아 있습니다.

단계별 설명 · 구조도를 글로 읽기
  • 관리자 환불 입력

    금액·귀책·환불 사유 · 공제액은 서버 정책 적용

    • 요청 처리 선점 (처리·명시된 호출)
  • 요청 처리 선점

    요청 행을 처리 중으로 · 3분 내 중복 요청 거절

    • 주문 상태 검사 (처리·명시된 호출)
  • 주문 상태 검사

    결제완료 주문만 허용 · 이미 종결된 주문은 거절

    • PG 잔액 조회 (처리·명시된 호출)
  • PG 잔액 조회

    남은 취소 가능액 B · 조회 실패면 취소 중단

    • 서버 금액 계산 (데이터 읽기·참조)
  • 서버 금액 계산

    서버 산정액 A·공제 D · 종결 여부를 미리 판정

    • 외부 PG 취소 (취소 요청)
  • 외부 PG 취소

    전액 또는 지정 금액 취소 · 성공 응답 뒤 DB 기록

    • 주문 환불 누적 (데이터 읽기·참조)
  • 주문 환불 누적

    누적액에 A 추가 · 공제 배송비는 더하지 않음

    • 주문 종결인가 (처리·명시된 호출)
    • 금액 화면 조회 (데이터 읽기·참조)
    • 후속 등급 계산 (데이터 읽기·참조)
    • 기록 실패 로그 (DB 기록 실패)
  • 주문 종결인가

    full 또는 A + D ≥ B · 참: 종결 / 거짓: 유지

    • 종결 상태 변경 (처리·명시된 호출)
    • 부분 환불 유지 (비종결)
  • 종결 상태 변경

    취소·환불 상태 조건 갱신 · 성공자만 재고·쿠폰 복구

    • 요청 결과 저장 (처리·명시된 호출)
  • 부분 환불 유지

    주문은 결제완료 유지 · 부분 재고 복구는 수동

    • 요청 결과 저장 (처리·명시된 호출)
  • 요청 결과 저장

    요청 행 완료·PG 결과 기록 · 요청 완료와 주문 종결 구분

  • 금액 화면 조회

    매출·목록·누적 구매액 · 결제완료 금액에서 환불 차감

  • 후속 등급 계산

    이후 주문 때 누적액 조회 · 환불 직후 재계산은 아님

  • 기록 실패 로그

    처리는 그대로 계속 · 대조·보상은 별도 과제

구조 탐색과 실제 소스 대조를 바탕으로 편집한 작동도입니다. 런타임 전체의 자동 검증을 뜻하지 않습니다.

문제 해결

송장 API의 성공 응답만으로는 배송 업무가 끝나지 않았다

문제

송장 발급이 실패하거나 발급 후 DB에 남지 않았고, 저장한 출력 링크를 다시 열면 사용할 수 없는 문제가 이어졌습니다.

바꾼 점

요청의 계약 유형과 개별 항목 응답 처리를 교정했습니다.

확인한 것

당시 인계 기록에서 발급·저장·출력 경로의 수정과 배포 확인을 대조했습니다.

조사·판단·검증 과정 읽기

마주한 문제

송장 발급이 실패하거나 발급 후 DB에 남지 않았고, 저장한 출력 링크를 다시 열면 사용할 수 없는 문제가 이어졌습니다.

확인한 과정

실제 배송 계약 유형과 요청 값이 다르고, 응답의 중첩 구조와 항목별 결과를 빠뜨린 부분을 찾았습니다. 출력 링크는 영구 주소가 아니라 한 번 사용하도록 발급되는 값이었습니다.

선택한 방법

요청의 계약 유형과 개별 항목 응답 처리를 교정했습니다. 출력할 때 링크를 발급받도록 시점을 바꾸고, 배송 웹훅의 주문 매칭과 최초 운송장 저장 시 알림을 연결했습니다.

어떻게 확인했는가

당시 인계 기록에서 발급·저장·출력 경로의 수정과 배포 확인을 대조했습니다. 최상위 접수 성공, 항목별 발급 결과, 내부 저장을 별도의 확인 지점으로 나눴습니다.

결과와 현재의 경계

결과, 그리고 지금.

환불의 금전 처리와 주문 종결을 분리하고, 환불액을 반영하지 않던 집계 소비처를 함께 수정했습니다. 송장 발급부터 DB 저장·출력까지 공급자의 실제 계약에 맞춰 연결했습니다.

이 경험의 범위

당시 운영 기록과 소스에서 확인된 개선입니다. PG와 DB는 하나의 트랜잭션이 아니므로 영구 정합성이나 모든 경로의 중복 환불 방지를 보장하지 않습니다.

작성 기준: 2026년 9월 작업 기록·소스 대조. 과거 검증 결과를 현재의 모든 동작에 대한 보증으로 사용하지 않습니다.

역할과 협업 이야기하기