Java·Spring 백엔드 개발자

임동현

개발부터 운영 서버 배포·장애 대응까지 책임집니다.

공공기관 메일 시스템의 요구사항 분석·기능 개발부터 운영 서버 배포와 오류 대응까지 단독으로 맡고 있습니다. 고운맘은 DB·API 설계부터 백엔드·고객/관리자 화면, 테스트와 AWS 배포까지 1인으로 진행했습니다.

대표 프로젝트 · 2025.12 — 현재

고운맘

상품·주문·결제와 관리자 운영을 연결하고, 중복 요청·부분 실패의 복구 흐름을 설계한 1인 커머스입니다.

1인 개발사업자등록 완료

주문·결제·재고의 최종 상태를 함께 보호합니다.

주문은 만료됐는데 결제가 승인되거나, S3 복사는 끝났는데 DB 기록은 실패할 수 있습니다. 각 단계의 완료 기준을 나누고 중복·실패·재시도 후 주문·원장·재고가 어떻게 남아야 하는지 정했습니다.

요구사항 정의부터 설계·개발·배포·운영 검증까지 직접 맡았습니다. 사업자등록 후 공개 운영 중이며 UI 보완으로 일반 주문은 아직 불가합니다. 아래 사례는 실제 고객 주문 실적이 아닌 개발·테스트 검증 결과입니다.

고운맘 고객 화면: 상품 카테고리와 여성 데일리웨어 소개
고운맘 · 1인 개발 커머스서비스 보기 ↗

공개 고객 화면 · 캡처
UI 보완 중으로 일반 주문은 아직 불가합니다.

서비스
gowoonmom.kr ↗
개발 기간
2025.12 → 현재
담당 범위
설계·개발·테스트·배포
핵심 스택
Spring Boot · Next.js
정의·설계
고객·운영자 요구사항
API·DB·상태 전이
개발·검증
백엔드·프론트엔드
실패 조건·회귀 테스트
배포·운영
AWS 공개 배포
관리자·복구 흐름

장바구니 저장 결과가 불확실할 때의 주문 차단, 결제창 취소 후 재시도, 상품 목록의 일괄 조회와 키보드 조작도 함께 보완했습니다. 구매 흐름의 최근 개선 보기 ↓

AI/Codex는 코드 작성·분석·테스트 작성을 폭넓게 보조했습니다. 요구사항과 허용할 상태, 변경의 채택·검토·배포 책임은 개발자인 제가 맡습니다. 활용 범위와 검증 방식 ↓

백엔드 문제 해결

실패 조건을 정하고, 데이터가 어떻게 남는지 확인했습니다. 핵심 결과를 먼저 보고, 관심 있는 사례의 설계와 검증 과정을 펼쳐 읽을 수 있습니다.

01

주문·재고 / MariaDB에서 동일 옵션의 동시 예약 검증

재고 동시 예약 제어

MariaDB · 동시 요청 2건 중 성공 1건, 거절 1건

문제
같은 재고를 보고 두 요청이 모두 예약하면 초과 판매가 발생
선택
가용 수량 조건과 예약 갱신을 하나의 UPDATE로 처리
검증
MariaDB: 동시 요청 2건 중 1건 성공·1건 거절, 최종 예약 1개
재고 예약 설계·검증 과정

원인과 제약

조회와 갱신이 분리되면 조회 시점의 수량을 갱신 시점에 보장할 수 없습니다. 주문의 예약 경쟁과, 관리자 상품 편집이 최신 재고를 덮어쓰는 충돌은 보호할 범위도 달랐습니다.

대안과 선택 이유

모든 요청에 같은 락을 걸지 않았습니다. 예약은 가용 수량 조건이 포함된 원자적 UPDATE로, 물리 재고 차감과 이력 기록은 비관적 락으로, 관리자 수정은 expectedVersion을 비교하는 낙관적 충돌 검사로 나눴습니다. 예약은 별도 조회 없이 수량 조건과 갱신을 묶고, 차감은 변경 전후 수량과 이력을 함께 보호하기 위해서입니다.

실제 구현

가용 재고 = 실물 − 예약 − 판매 보류입니다. 조건을 만족한 행 수가 요청한 옵션 수와 다르면 트랜잭션 전체를 롤백합니다. 여러 옵션은 ID를 정렬해 처리하고, 옵션 마스터와 inventory_option_balance의 version을 분리했습니다.

검증 시나리오와 결과

MariaDB 통합 · 통과재고 1개에 동일 옵션 예약 요청 2건을 동시에 실행
두 스레드를 같은 시작 신호로 출발시키고 서비스의 독립 트랜잭션에서 각각 1개를 예약했습니다. 1건 성공·1건 재고 부족 거절, 최종 reserved_quantity = 1로 초과 예약이 없었습니다. 격리된 로컬 MariaDB 11.4 · 2026.09.20.
H2 통합 · 통과재고 5개·1개인 두 옵션에 각각 2개 예약
한 옵션의 재고가 부족하면 전체 예약이 롤백되어, 두 옵션 모두 예약 수량 0개를 유지했습니다.
H2 통합 · 통과주문 조회 뒤 상품이 판매 중지·숨김 상태로 변경
갱신 시점의 판매 조건으로 예약을 거절하고, 함께 요청한 다른 옵션의 예약도 롤백했습니다.

운영 보호 장치예약 가능한 수량을 DB의 갱신 조건으로 강제합니다. 여러 옵션을 함께 예약할 때 하나라도 조건을 충족하지 못하면 전체 예약을 롤백해, 일부 상품만 예약된 상태가 남지 않도록 처리합니다.

핵심 구현: 재고 예약 SQL

가용 수량과 판매 상태를 UPDATE 조건에 함께 둔 실제 예약 SQL입니다. 변경된 행이 1개가 아니면 서비스에서 예외를 발생시켜 예약을 확정하지 않습니다.

UPDATE inventory_option_balance
  SET reserved_quantity = reserved_quantity + #{quantity},
      version = version + 1
  WHERE option_id = #{optionId}
    AND stock_quantity - reserved_quantity - sales_hold_quantity >= #{quantity}
    AND EXISTS (
        SELECT 1
        FROM product_option po
        JOIN product p ON p.product_id = po.product_id
        WHERE po.option_id = inventory_option_balance.option_id
          AND po.deleted_at IS NULL
          AND po.option_status = 'SELLABLE'
          AND p.deleted_at IS NULL
          AND p.product_status = 'ACTIVE'
    )
02

PortOne·KakaoPay / 중복·지연·순서 역전을 테스트로 재현

중복 결제 처리 방지

H2·PG 모의 검증 · 원장·알림·재고 이력 각 1건

문제
승인 알림을 다시 처리하거나 늦은 승인으로 만료 주문을 되살릴 위험
선택
PG 재조회 후 주문·결제 상태를 잠금 안에서 확인하고 한 번만 반영
검증
H2·PG 모의 서버: 중복 승인에도 원장·알림·재고 이력 각 1건

관리자 화면에서 확인하는 주문·환불 상태

백엔드의 상태 구분을 관리자가 판단할 수 있도록 화면에도 연결했습니다.

관리자 주문 목록에서 주문은 부분환불, 배송은 배송 준비, 결제는 부분 결제취소로 각각 표시한 화면 원본 크기로 보기 ↗
주문·배송·결제 상태를 따로 표시주문의 부분환불 상태와 배송 진행 상태를 함께 확인합니다. 주문번호·수령인·연락처 영역은 캡처에서 제외했습니다.로컬 관리자 주문 목록 · 2026.10.14 캡처
테스트 주문의 부분취소 금액 30,000원을 가디건 1개에 배분하고, 선택 합계가 미배분액과 일치하는지 표시한 실제 환불 품목 배분 화면 원본 크기로 보기 ↗
취소 금액과 환불 품목 배분을 구분미배분액과 선택한 품목의 금액을 비교해 저장 전 확인합니다. 실제 구현 컴포넌트에 테스트 데이터를 사용한 화면이며, 실제 고객 환불 내역은 아닙니다.실제 구현 컴포넌트 · 테스트 데이터 · 2026.10.14 캡처
결제 처리 설계·검증 과정

원인과 제약

결제창, webhook, PG의 실제 상태는 같은 시점에 갱신되지 않습니다. 알림 도착 순서를 결제 상태로 믿을 수 없어 중복 승인, 과거 실패 이벤트, 주문 만료와 늦은 승인을 나눠 다뤘습니다.

대안과 선택 이유

클라이언트 성공 응답이나 webhook의 이벤트 이름만으로 주문을 완료하지 않습니다. 서명 검증 후 PG를 재조회하고, 서버에 저장한 결제 시도와 대조합니다. PG 조회는 DB 상태 변경 트랜잭션 밖에 두어 네트워크 대기 중 잠금을 유지하지 않습니다.

실제 구현

주문 준비 때 가격·배송비를 서버에서 계산하고 재고를 예약합니다. 결제 확정은 주문 → 결제 시도 순으로 잠근 뒤 paymentId·주문·상점·통화·금액과 PAID 상태를 확인합니다. 이미 처리한 원장이 있으면 재고를 다시 차감하지 않고 반환합니다. 새 결제의 원장·주문 완료·재고 차감·알림 outbox는 같은 트랜잭션에 기록합니다.

검증 시나리오와 결과

H2 + PG 모의 서버 · 통과동일 PAID webhook 동시 처리
결제 원장·알림 outbox·재고 차감 이력이 각각 1건만 생성.
H2 + PG 모의 서버 · 통과승인 이후 과거 FAILED/CANCELLED 이벤트 도착
PG의 최신 PAID 상태 유지. 중복 완료·환불·재고 변동 없음.
H2 + PG 모의 서버 · 통과PG 조회 지연 중 주문 정리 배치가 먼저 만료 처리
주문을 다시 완료하지 않고 늦은 결제 복구 건을 1개 생성. 보상 취소 후 재실행은 추가 처리 없음.
단위 테스트 · 통과주문 준비의 결제 ID 불일치·취소 전 금액 불일치
잘못된 결제 완료·취소를 거절하고 재고를 변경하지 않음.

운영 보호 장치만료 후 승인된 결제는 이미 반환한 재고를 다시 차감하지 않고 환불 복구 대상으로 분리합니다. 자동 취소를 확정할 수 없는 경우는 수동 검토로 남겨, 불확실한 결제를 정상 주문으로 처리하지 않습니다.

03

이미지 공개 처리 / 부분 성공과 작업 재시작을 테스트로 재현

S3와 DB의 부분 실패 복구

H2·S3 모의 검증 · 복사 요청 2회, 객체 생성 1회

문제
S3에는 파일이 생겼지만 DB에는 완료 기록이 없어 재시도 판단이 불확실
선택
DB에 outbox를 남기고 외부 복사와 완료 기록을 분리
검증
H2·S3 모의 객체: 중단 후 복사 요청 2회에도 객체 생성은 1회
이미지 복구 설계·검증 과정

원인과 제약

DB와 S3는 하나의 로컬 트랜잭션으로 커밋할 수 없습니다. 복사 응답 유실이나 실행기 종료를 단순 실패로 취급하면, 이미 만들어진 파일을 모른 채 같은 작업을 다시 실행할 수 있습니다.

대안과 선택 이유

외부 I/O를 긴 DB 트랜잭션에 넣는 대신 작업을 DB outbox에 남겼습니다. 별도 메시지 브로커 없이 기존 DB에서 재시도 상태를 관리하되, DB 기록과 파일 저장 사이에 일시적인 상태 차이가 생기는 방식임을 전제로 했습니다.

실제 구현

이미지 자산과 COPY 작업을 같은 트랜잭션에 저장합니다. worker는 짧은 트랜잭션으로 작업을 선점한 뒤 트랜잭션 밖에서 복사합니다. 응답이 불확실하면 HEAD와 메타데이터를 확인하고, 유효한 lease 소유자만 완료 상태를 기록합니다.

검증 시나리오와 결과

H2 통합 · 통과자산·COPY 작업 저장 중 트랜잭션 롤백
자산과 outbox 어느 한쪽만 남지 않음.
H2 + S3 모의 객체 · 통과복사 성공 직후 DB 완료 기록 전 중단, lease 만료 후 새 worker 실행
복사 요청 2회에도 새 객체 생성은 1회. 자산 ACTIVE, 작업 CLEANED 확인. 다시 실행해도 추가 복사 없음.
H2 통합 · 통과lease가 만료된 기존 worker가 결과 기록 시도
완료·재시도·영구 실패 어느 결과도 이전 소유권으로 덮어쓰지 못함.

운영 보호 장치복사 결과가 불확실하면 저장된 객체와 메타데이터를 재확인하고, 메타데이터 충돌은 영구 실패로 기록합니다. lease 소유권을 잃은 worker의 완료·실패 기록을 거절해 이전 실행 결과가 현재 작업 상태를 덮어쓰지 못하게 합니다.

04

인증·인가 / 예방 설계와 경계 조건 단위 테스트

동시 토큰 갱신과 재사용 구분

단위 검증 · 정상 경합과 오래된 재사용 구분

문제
모든 토큰 재사용을 공격으로 보면 정상적인 동시 갱신도 세션 종료로 이어짐
선택
토큰 교체 직후의 동시 갱신 충돌과 오래된 토큰 재사용을 구분
검증
단위 테스트: 5초 이내 충돌에는 새 토큰 미발급, 이후 재사용은 family 폐기
토큰 갱신 설계·검증 과정

원인과 제약

여러 요청이 동시에 갱신하면 앞선 요청이 교체한 토큰을 뒤의 요청이 다시 제시합니다. 반대로 교체된 토큰을 계속 허용하면 탈취된 토큰의 사용을 끊기 어려워, 교체 직후의 짧은 경합을 별도로 처리했습니다.

대안과 선택 이유

JWT Access Token은 프론트 메모리, Refresh Token은 HttpOnly Cookie로 분리해 장기 토큰을 스크립트가 직접 읽지 못하게 했습니다. 서버는 원문 대신 SHA-256 해시와 세션 계열(family)을 저장합니다. 매 갱신마다 교체하되 정상 동시 갱신 충돌과 오래된 토큰 재사용을 다르게 처리합니다.

실제 구현

사용자 행 잠금과 조건부 revoke로 이전 토큰을 한 번만 교체합니다. ROTATED 후 5초 이내 요청은 동시 갱신 충돌로 거절하되 새 토큰을 발급하거나 family를 폐기하지 않습니다. 그 이후 재사용은 해당 family를 폐기합니다.

운영 프로필의 Refresh Cookie 기본값은 Secure·SameSite=Strict입니다. 관리자 API는 서버에서 ADMIN/OWNER, AI 개발 기능은 OWNER 권한을 검사하며 화면 숨김에만 의존하지 않습니다.

검증 시나리오와 결과

단위 테스트 · 통과갱신 요청의 승자 커밋이 늦고 패자가 뒤늦게 처리됨
사용자 잠금·토큰 갱신 순서를 확인하고 정상 경합을 재사용 공격으로 오판하지 않음.
단위 테스트 · 통과5초를 지난 ROTATED 토큰 또는 다른 사유로 폐기된 토큰 제시
같은 family를 폐기. 최근 ROTATED 요청에는 새 토큰을 발급하지 않음.
단위 테스트 · 통과로그아웃에 제시된 토큰
그 토큰의 family 전체를 폐기.

운영 보호 장치교체 직후의 동시 갱신 요청에는 새 토큰을 발급하지 않으면서 정상 세션은 유지합니다. 5초가 지난 교체 토큰의 재사용은 해당 Refresh Token family를 폐기해 그 세션 계열의 추가 갱신을 차단합니다.

주문 전 확인부터 화면 복구까지 함께 맞췄습니다.

서버의 상태를 보호하는 것에 더해, 고객 화면도 확인된 수량·금액과 처리 결과를 따라가도록 보완했습니다.

저장 결과를 모르면 이전 금액으로 주문하지 않습니다.

수량을 저장했더라도 응답이 유실되면 화면의 값은 확정할 수 없습니다. 미저장 입력·저장 중·응답 오류에서는 주문을 차단하고, 재조회한 서버 수량과 금액으로만 주문을 이어갑니다.

확인 결과응답 유실·잘못된 금액·가격 변경 후 재조회, 수량 저장 중 중복 조작 차단을 확인했습니다.

결제창을 닫아도 재시도와 완료를 구분합니다.

결제창의 반환값만으로 주문을 완료하지 않습니다. 서버 확인을 기다리고, 취소 뒤에는 준비 상태를 다시 확인해 결제창을 엽니다. 승인 대기 중에는 복구 정보를 유지하고, 완료된 비회원 주문의 장바구니는 한 번만 정리합니다.

확인 결과회원·비회원 결제 진행, 취소·닫기 후 재시도와 동일 완료 결과의 중복 차감 방지를 확인했습니다.

상품 카드마다 옵션을 다시 조회하지 않습니다.

상품 ID를 모아 색상·사이즈를 일괄 조회하고, 큰 진열도 최대 500개 ID씩 나눕니다. 메인 더보기는 후보 13개로 다음 페이지 여부를 판단하고, 표시할 12개의 상품·옵션만 조회합니다.

확인 결과24개 상품의 옵션 조회 1회, 더보기의 ID·상품·옵션 조회 각 1회, 빈 결과에서 불필요한 추가 조회 생략을 확인했습니다.

키보드 조작도 저장·닫기 흐름을 따라갑니다.

수량 입력에서 Tab으로 버튼을 거쳐 나갈 때도 변경을 저장합니다. 대화상자는 포커스 이동·Escape·닫은 뒤 복귀를 공통 처리하고, 주소 검색을 취소한 뒤 늦게 도착한 결과는 무시합니다.

확인 결과수량 저장과 초점 유지, 중첩 대화상자의 포커스 복구, 주소 검색 취소·재열기를 확인했습니다.

검증 · 프론트는 JSDOM(모의 브라우저 DOM)·모의 API/결제 SDK·메모리 저장소, 상품 조회는 백엔드 단위 테스트로 확인했습니다. 실제 PG 승인, MariaDB 실행계획과 실기기 키보드 검증은 이 결과의 범위에 포함하지 않습니다.

회사에서 해결한 운영 장애

엔소프트웨어 · 2025.07.01 - 재직 중. Java/Spring 기반 업무 시스템 개발·운영 중 발생한 행정우편 첨부 오류를 분석하고 수정 배포했습니다.

대표 운영 사례 · 엔소프트웨어

행정우편 첨부파일 삭제 장애 해결

메일 단독 담당자로서 일반 메일의 정리 작업이 다른 사용자의 행정우편 첨부파일을 삭제하는 원인을 식별하고, 저장·정리 로직을 수정했습니다.

문제
일반 메일의 정리 작업이 다른 사용자가 작성 중인 행정우편의 첨부파일까지 삭제했습니다.
핵심 판단
행정우편 화면이 아니라 두 기능이 공유하는 파일의 저장·삭제 범위를 수정했습니다. 난수 하위 폴더로 분리하고 해당 폴더만 정리하도록 제한했습니다.
확인 결과
정상 첨부·발송과 동시 사용을 확인했습니다. 원인을 파악한 당일 저녁 수정 배포했고, 이후 동일 오류는 재발하지 않았습니다.
원인 추적 · 수정 내용 · 배포와 검증 과정

배포 인수 범위

IE → Whale 전환 사업에서 메일 담당자가 퇴사해, 운영 배포 1개월 전 메일 배포 업무를 인수했습니다. 전달받은 파일·설정 목록에 따라 수행한 메일 배포와 이후 기능 개발·유지보수·운영 오류 대응이 제가 맡은 범위입니다.

사업건 운영 배포는 금요일 새벽부터 토요일 점심까지 진행했습니다. 다음 주 화요일에 첨부파일 삭제 오류의 원인을 파악하고, 당일 저녁 수정 사항을 운영에 반영했습니다.

오류가 나타난 기능과 원인 기능이 달랐습니다.

Windows에서 파일을 우클릭해 ‘행정우편 보내기’를 선택하면 메일쓰기 화면이 열리고, 서버 임시폴더의 첨부파일을 참조합니다. 이 파일이 작성 도중 사라져 첨부 처리와 기능 이용에 오류가 발생했습니다.

원인은 일반 메일 발송 후 공용 임시폴더 전체를 삭제하는 정리 로직이었습니다. 한 사용자의 정리 작업이 다른 사용자의 작성 중인 작업에 영향을 주는, 공유 임시 디렉터리의 삭제 범위 오류였습니다.

두 기능이 공유 임시폴더에서 간섭하는 흐름장애 원리를 설명하기 위한 개념 흐름입니다. 내부 경로와 사용자 정보는 사용하지 않았습니다.
  1. 사용자 A · 행정우편

    ‘행정우편 보내기’ 실행 → 첨부파일을 공용 임시폴더에 저장

  2. 사용자 A · 작성 중

    메일쓰기 화면에서 저장된 첨부파일 참조

  3. 사용자 B · 일반 메일

    메일 발송 완료 → 정리 로직이 공용 임시폴더 전체 삭제

  4. 사용자 A · 첨부 오류

    작성 중 참조하던 파일이 사라져 첨부파일 처리 실패

저장·정리 범위와 삭제 보호 조건을 수정했습니다.

  1. 첨부파일 저장 영역 분리

    행정우편 첨부파일을 공용 임시 경로 하위의 난수 이름 폴더에 저장하도록 변경했습니다.

  2. 정리 대상 제한

    첨부 처리 후에는 해당 하위 폴더만 삭제하도록 정리 로직을 보완했습니다.

  3. 삭제 전 보호 조건 추가

    시스템 설정에서 임시 저장소 경로를 가져와 삭제 대상을 검증하고, 공용 임시 저장소 루트와 추가로 지정한 보호 경로는 삭제하지 않도록 방어했습니다.

검증과 운영 결과 수정 후 행정우편의 첨부·발송이 정상 동작하는지 직접 확인했습니다. 일반 메일 발송과 행정우편 작성을 동시에 진행하는 상황도 확인했으며, 수정 사항을 운영에 반영한 이후 동일 오류는 재발하지 않았습니다.

담당 업무와 경력 요약 ↓

엔소프트웨어 · 2025.07.01 - 재직 중

배포 한 달 전 인수한 메일을 단독 운영

1인 담당

메일 배포를 인수한 뒤 전달받은 파일·설정 목록으로 배포하고, 고객사의 기능 개선 요청과 운영 오류에 대응했습니다.

  • 고객사 요구사항 분석, 기존 기능 유지보수와 신규 기능 개발
  • 타 시스템 연계 API 개발 및 유지보수
  • 메일 시스템 운영 서버 배포와 오류 원인 분석·로직 수정

담당 범위 공공기관 메일 시스템 개발·운영을 단독 담당합니다. 요구사항 분석부터 기능 개발, 운영 서버 배포와 오류 대응까지 맡았습니다.

JavaSpring LegacyJSPOracle DB연계 API

행정우편 장애 해결 사례 ↑

엔소프트웨어 · 인사·노무 개선 사업

인사·노무 기능 개발과 입력 오류 안내

3인 팀

메일 시스템을 단독 운영하면서 인사·노무 개선 사업의 기능 개발을 병행했습니다. 팀장 1명·사원 개발자 2명의 3인 팀에서 연가 부여, 근무성적평정 PDF 생성과 급여명세서 업로드 오류 안내를 구현했습니다.

전체 10개 과업 중 5개 과업을 개별 담당해 완료하고, 1개 과업을 공동 완료했습니다.

  • 1년 미만 대상자에게 연가를 1일씩 부여하는 스케줄러 추가
  • OZ Report 기반 근무성적평정 PDF 생성 기능 구현
  • 급여명세서 엑셀 업로드 시 양식의 잘못된 부분을 상세 오류 메시지로 안내하도록 개선

JavaSpring LegacyJSPOracle DBSchedulerOZ Report

폐쇄망 상주 환경에서 기존 시스템을 직접 분석·수정하고 운영 배포를 수행했습니다.

감프정보기술 · 2024.11.25 - 2025.05.23

제약 생산관리 시스템 유지보수·QA 지원

MES·WMS·Smart EBR의 제조지시·포장지시 기능 검증, 결함 확인과 사용자 지침서 작성을 담당했습니다. SQL Server 데이터 조회·검증과 C#/.NET WinForms 화면 수정·기능 개선을 지원했습니다.

회사명과 근무 기간, 담당 업무와 익명화한 장애 원리만 공개합니다. 고객 기관명, 내부 경로·서버 주소·화면·로그·운영 데이터는 포함하지 않았습니다.

AI 활용과 검증

AI가 만든 변경을 격리된 작업 공간에서 테스트하고, 검토·승인 후 반영하는 개발 도구를 구현했습니다.

완료 응답과 실제 성공은 다릅니다.

모델이 작업을 끝냈다고 답해도 검증 성공으로 간주하지 않습니다. 실행기가 실제 명령을 수행하고 코드 변경 내용과 검증 결과를 검토 대상으로 남깁니다.

AI 응답과 실행 결과 분리

생성 중 원본 코드가 바뀔 수 있습니다.

개발 요청을 로컬 PC의 격리된 소스에서 실행합니다. 승인 뒤에도 기준 파일 해시가 다르면 원본 반영을 중단합니다.

격리 실행 · 승인과 반영 분리

생성 콘텐츠가 현재 상품과 다를 수 있습니다.

상품 상세 제작의 입력 스냅샷·불변 revision·상품 기준 해시로 생성 기준과 반영 대상을 구분하고, 컷별 결과를 검토한 뒤 반영합니다.

소유자 전용 개발·콘텐츠 제작 도구

AI 보조와 사람의 책임을 분리했습니다.

AI가 보조한 작업

AI/Codex를 요구사항 정리, 구현, 코드 탐색, 테스트 작성과 리뷰에 폭넓게 활용했습니다.

직접 판단하고 책임진 부분

결제 완료 기준, 재고 변경 조건, 자동 복구와 수동 검토의 경계를 결정하고 변경의 채택·검증·배포를 책임집니다.

직접 구현한 AI 개발 오케스트레이션

웹은 개발 요청·상태·결과를 저장하고, 개발 PC의 실행기가 격리된 소스에서 분석 → 계획 → 구현 → 실제 명령 검증 → 독립 리뷰를 진행합니다. 운영 서버에서 테스트·빌드를 실행하지 않습니다.

소유자의 검토·승인과 원본 반영은 별도 단계입니다. 기준 파일 해시가 다르면 반영을 중단하며 commit·push·운영 배포는 자동 실행하지 않습니다. 개발 PC가 꺼져 있으면 요청은 대기합니다.

구현 상세: JSON Schema로 단계 결과 형식을 제한하고, 상태 머신으로 진행 단계를 관리합니다. heartbeat·lease로 실행기의 작업 소유권을 확인합니다. 상품 상세 제작은 입력 스냅샷·불변 revision·상품 기준 해시로 생성 결과와 반영 대상을 구분합니다.

아키텍처와 데이터 모델

상품 수정이 과거 주문을 바꾸지 않도록 스냅샷을 남기고, 주문 만료와 늦은 결제 승인을 별도로 관측합니다. 앞의 문제 해결 사례를 뒷받침하는 시스템 구성과 핵심 데이터 관계입니다.

핵심 아키텍처단일 백엔드 + 관계형 DB
API ↔ PortOneWorker ↔ S3이미지 → CloudFront
배포 구성: AWS Lightsail · Docker Compose · Nginx · HTTPS. 외부 연동은 DB 커밋과 같은 완료 시점으로 가정하지 않습니다.

현재 규모의 선택주문·결제·재고의 핵심 변경은 하나의 DB 트랜잭션에서 다룹니다. 서비스 간 분산 트랜잭션 없이 핵심 데이터의 정합성을 유지하고, DB와 외부 시스템 사이의 실패는 outbox·재조회·보상 처리로 복구하도록 구성했습니다.

DOMAIN MAP

업무 수명주기에 따라 데이터 경계를 분리했습니다.

· 데이터 모델 기준
01회원 · 인증사용자·세션·동의·OAuth
02상품 · 재고옵션 마스터·실시간 재고·변동 이력
03장바구니 · 주문주문 스냅샷·멱등 시도
04결제 · 환불결제 원장·취소·수동 검토
05배송 · 알림운송장·감사 이력·outbox
06이미지 자산업로드·활성화·보관·삭제

커머스 데이터에 더해 AI 개발 작업은 단계·검증·승인 이력으로, 상품 상세 제작은 입력 스냅샷·이미지 자산·불변 revision으로 관리합니다. 아래 ERD에서 회원 참조는 비회원·탈퇴 주문을 위해 선택값이며, 옵션·재고의 1:1은 도메인 생성 규칙을 포함합니다.

CORE COMMERCE ERD

주문·결제·재고·배송의 핵심 관계

1 필수 하나 0..1 선택적 하나 0..N 없거나 여러 개 1..N 하나 이상

각 그룹에서 관계와 핵심 컬럼을 함께 볼 수 있습니다. 한글 이름은 데이터의 역할, 영문 이름은 실제 테이블·컬럼입니다.

주문·재고주문 당시 정보와 실시간 재고의 변경 범위를 분리합니다. 관계·컬럼 보기접기

회원

user_account

PK user_id

회원 주문을 연결합니다. 비회원 주문과 회원 참조가 해제된 주문도 보존합니다.

주문

sales_order

PK order_id
FK user_id · 선택

배송비 정책 버전
shipping_policy_version

주문 준비 시 적용한 배송비 기준을 남깁니다.

주문상품 스냅샷

sales_order_item

PK order_item_id
FK order_id · option_id

당시 상품명
product_name_snapshot
당시 단가
unit_price_snapshot
주문 수량
quantity

옵션 마스터

product_option

PK option_id

상품 편집 버전
version

실시간 재고

inventory_option_balance

PK / FK option_id

실물 수량
stock_quantity
예약 수량
reserved_quantity
판매보류 수량
sales_hold_quantity
재고 변경 버전
version
  • 주문상품 0..N ↔ 옵션 1sales_order_item.option_id로 실제 판매 옵션을 참조하면서 당시 상품명과 단가는 별도로 보존합니다.

보호하는 기준가용 재고는 실물 − 예약 − 판매보류로 계산합니다. 상품 편집과 재고 변경의 버전을 나눠, 오래된 상품 수정이 최신 재고를 덮어쓰지 않도록 합니다.

결제·환불결제 관측, 확정 원장, 개별 취소 요청을 구분합니다. 관계·컬럼 보기접기

주문

sales_order

PK order_id

결제 관측과 원장을 같은 주문에 연결합니다.

결제 관측·계약

payment_attempt

PK payment_id
UNIQUE / FK order_id

서버 기준 결제금액
expected_amount
관측·복구 상태
status
보상 취소 참조 · 선택
recovery_cancellation_id

확정 결제 원장

payment

PK payment_id
FK order_id

결제 상태
payment_status
승인 금액
approved_amount
누적 취소 금액
cancelled_amount

취소·환불 요청

payment_cancellation

PK cancellation_id
FK order_id
FK payment_id · 선택

요청 처리 상태
status
현금 환불 금액
cash_refund_amount

주문상품별 환불 배분

payment_cancellation_item

FK cancellation_id
FK order_item_id

어떤 주문상품이 취소·환불 대상인지 개별 요청에 연결합니다.

  • 주문 1 ↔ 결제 원장 0..N · 취소 요청 0..N두 테이블 모두 order_id로 주문을 직접 참조합니다. 결제 원장 없이 예약을 해제하는 취소 요청도 기록합니다.
  • 주문상품 1 ↔ 환불 배분 0..Norder_item_id로 환불 대상을 원래 주문상품에 연결합니다.
  • 결제 관측 0..1 ↔ 보상 취소 0..1늦은 승인 보상환불은 선택적·고유 참조인 recovery_cancellation_id로 연결합니다.

보호하는 기준PG 상태의 관측과 확정 원장을 구분하고, 만료 주문의 늦은 승인은 보상 취소로 추적합니다. 결제 관측과 원장은 같은 결제 식별자를 사용하며, 두 테이블 간 직접 FK는 두지 않았습니다.

배송·알림현재 배송과 감사 이력, 외부 발송 작업의 수명을 나눕니다. 관계·컬럼 보기접기

주문

sales_order

PK order_id

배송과 외부 알림 작업을 주문에 연결합니다.

현재 배송

shipment

PK shipment_id
UNIQUE / FK order_id

한 주문의 현재 배송 정보를 한 행으로 관리합니다.

배송 감사 이력

shipment_history

FK shipment_id · order_id

현재 배송 정보와 별도로 변경 이력을 보존합니다.

주문

sales_order

PK order_id

고객 알림 작업

notification_outbox

FK order_id

발송 상태
status
발송 시도 횟수
attempt_count
예약·재시도 시각
scheduled_at
작업 선점 만료
claim_expires_at
  • 주문 1 ↔ 배송 감사 이력 0..N배송 이력도 order_id로 주문을 직접 참조합니다.

보호하는 기준알림 작업을 주문 트랜잭션에 기록하고 외부 발송은 분리합니다. 미접수가 확인된 재시도 가능 실패는 다시 처리하고, 타임아웃 등 결과가 불확실한 발송은 별도 상태로 보류해 중복 발송 위험을 관리합니다.

주문상품의 1..N과 옵션별 재고의 1:1은 생성 시 지키는 업무 규칙을 포함합니다. 전체 스키마에서 핵심 관계와 대표 컬럼만 추렸으며, 실제 회원·주문 데이터는 표시하지 않습니다.

01 · Snapshot

과거 주문을 현재 상품 정보로 다시 계산하지 않습니다.

상품명·옵션·단가·배송지·배송비 정책은 주문과 주문상품에 당시 값으로 보존합니다.

02 · Consistency

옵션 마스터와 실시간 재고의 충돌 경계를 분리했습니다.

상품 편집은 master version, 주문·결제·재고 조정은 inventory version을 사용합니다. 오래된 상품 편집 값이 재고를 덮어쓰지 않도록 변경 범위를 분리했습니다.

03 · Operations

실패와 수동 판단도 데이터로 남깁니다.

결제·환불 수동 검토, 배송 변경, 알림 재시도와 이미지 outbox를 운영 이력으로 추적합니다.

위 ERD는 전체 스키마 중 주문 정합성을 설명하는 핵심 관계와 대표 컬럼을 추린 것입니다. 실제 회원·주문 데이터는 공개하지 않습니다.

기술 스택

기술을 사용한 환경을 함께 표시했습니다. 회사에서는 기존 업무 시스템을, 고운맘에서는 서비스 전체를 설계·개발했습니다.

Backend

Java 17 · Spring Boot 3 · Spring Security · Spring Data JPA · MyBatis · Spring Legacy

실무: Java·Spring Legacy / 고운맘: Spring Boot·Security·JPA·MyBatis

Frontend

Next.js 16 · React 19 · TypeScript 5 · Tailwind CSS · Zustand · JSP

실무: JSP / 고운맘: Next.js·React·TypeScript

Database / Infra

MariaDB · Oracle DB · SQL Server · AWS Lightsail · S3 · CloudFront · Docker Compose · Nginx

실무: Oracle·SQL Server / 고운맘: MariaDB·AWS 배포

Test / QA

JUnit 5 · MockMvc · H2 · Testing Library · Playwright · ESLint

고운맘: 자동화 테스트 / 감프정보기술: 기능 검증·사용자 문서

Integration / Auth

PortOne · OAuth · JWT · AWS SDK for Java · OZ Report

실무: OZ Report·업무 연계 API / 고운맘: 결제·인증·이미지 연계

이력서와 연락처

경력과 대표 프로젝트를 정리한 2쪽 이력서입니다. 상세 설계와 검증 과정은 위 사례에서 확인할 수 있습니다.

고운맘 서비스: gowoonmom.kr