컴플레인 접수 불일치
10건 미만
- 근거 종류
- 사용자 보고값
- 기준 시점
- 2026-08
고객 컴플레인으로 접수된 결제·예약 불일치 기준이며 시스템 전수 집계가 아닙니다.
관찰 범위: 시스템 전수 집계가 아니며 실제 불일치 건수의 하한입니다.
데이터를 불러오는 중입니다...
모든 설계를 혼자 맡은 1인 백엔드 겸 프론트엔드 개발자로서 PHP·React 공존 구조, 인증과 결제·예약 보상 흐름, API Key 서버 프록시를 설계·구현하며 프로젝트 전반을 주도했습니다.
모든 설계를 혼자 맡았고, 1인 백엔드 겸 프론트엔드 개발자로서 기존 그누보드 자산 위의 PHP·React 공존 구조와 인증, 결제·예약 연동, 보상취소, API Key 프록시를 설계·구현하며 프로젝트 전반을 주도했습니다.
컴플레인 접수 불일치
10건 미만
고객 컴플레인으로 접수된 결제·예약 불일치 기준이며 시스템 전수 집계가 아닙니다.
관찰 범위: 시스템 전수 집계가 아니며 실제 불일치 건수의 하한입니다.
운영 관찰 기간
2024년 오픈 ~ 현재 진행 중
2024년 오픈 이후 현재까지 유지보수하면서 같은 유형의 문제를 파악하지 못했다는 인터뷰 회고입니다.
관찰 범위: 시스템 전수 집계가 아니라 유지보수 과정에서 확인한 관찰 범위입니다.
문제는 세 갈래였습니다. 기존 그누보드 자산을 활용하면서 예약·로그인·마이페이지에는 React를 결합해 신규 리조트 서비스를 구축해야 했습니다. PHP와 React가 같은 origin에서 경로와 인증 상태를 공유해야 했고, 결제는 PHP 서버에서 처리한 뒤 예약·티켓 생성이 별도 단계로 이어져 중간 실패 시 결제와 실제 예약 상태가 어긋날 수 있었습니다.
또한 프로젝트 중간에 React 환경변수가 빌드 산출물에 포함된다는 점을 몰랐던 사실을 확인했습니다. 외부 API Key가 클라이언트에서 보일 수 있는 구조였기 때문에 결제 안정화와 함께 시크릿 경계도 바로잡아야 했습니다.
기존 그누보드 자산과 PHP 결제 흐름을 활용해야 했습니다. 서브도메인 분리는 CORS와 쿠키 공유, 기존 SEO·링크 유지 부담을 만들었고, 외부 PMS와 결제 시스템의 응답과 장애는 내부 트랜잭션 하나로 묶을 수 없었습니다.
WebView에서 자동로그인 토큰이 유실되는 원인은 앱 개발자에게 전달받은 내용이라 직접 규명한 사실처럼 단정할 수 없습니다.
서브도메인 분리는 실제로 검토했습니다. 그러나 CORS와 쿠키 공유 복잡도, 기존 SEO·링크 단절 가능성을 감수하기보다 같은 origin 안에서 Nginx 경로를 나누는 편이 기존 자산과 일정에 맞았습니다.
기존 자산 위에 PHP와 React를 함께 두는 방향은 신규 구축의 제약 안에서 내린 판단이었습니다.
Node.js에서는 ORM 트랜잭션으로 결제 상태 변경을 묶어 왔지만, 기존 PHP 결제 흐름에 같은 방식을 그대로 적용하기 어려웠습니다. 외부 결제와 PMS까지 하나의 트랜잭션으로 묶는 대신 중간 단계가 실패하면 역방향으로 되돌리는 보상 방식을 택했습니다. API Key 대응은 대안 비교가 아니라 잘못 이해한 시크릿 경계를 발견한 뒤 수정한 작업입니다.
같은 결제 후 예약 미생성 현상에서 서로 다른 세 원인과 대응이 어떻게 갈리는지 보여줍니다.
결제 승인 뒤 예약·티켓 생성 결과를 확인해 성공 시 예약을 완료하고, 응답 미도달·외부 장애·timeout 오판 시 각각 자동 보상취소, 장애 구간 로그 확인, timeout 정책 보강으로 대응했습니다.
서버가 결제 보상취소를 수행하고 결과를 남깁니다.
로그의 최초 발생 시각과 종료 시각을 대조해 장애 구간을 확인했습니다.
당시 API 문제로 약 20초까지 지연된 상태를 확인하고 30초 UX와 결제 안전성을 비교해 장애 대응값 60초를 선택했습니다. 이후 API가 수정되어 현재는 과거처럼 오래 걸리지 않습니다.
기존 그누보드 자산 위에 신규 서비스를 구축하면서 같은 origin 안에서 PHP와 React가 공존하도록 Nginx 경로를 분기했습니다. React 경로를 직접 열어도 빌드 진입점으로 연결하고, PHP와 React가 같은 JWT를 사용하도록 PHP 쪽에 JWT 검증 미들웨어를 추가했습니다.
WebView 자동로그인 토큰 유실 원인은 앱 개발자에게 전달받은 내용으로만 한정했습니다. 원인을 직접 규명했다고 쓰는 대신, 앱 개발자와 브릿지 인터페이스를 맞추고 토큰을 네이티브 앱에 전달한 구현 사실을 남겼습니다.
결제 승인 뒤 예약·티켓 생성이 실패하거나 응답이 프론트에 도달하지 못하면 PHP 서버가 결제를 자동 보상취소하도록 만들었습니다. 외부 PMS 장애는 로그의 최초 발생 시각과 종료 시각을 대조해 장애 구간을 확인했습니다.
세 번째 원인은 timeout 정책이었습니다. 외부 근거 없이 12초로 임의 설정한 뒤 정상 처리 중인 요청을 실패로 오판했습니다. 당시 약 20초까지 걸린 응답은 PMS의 정상 평균 속도가 아니라 해당 API에 문제가 있어 지연된 상태였습니다. 사용자 경험상 30초도 검토했지만 결제 안전성을 우선해 장애 대응값을 60초로 늘렸고, 이후 해당 API가 수정되어 현재는 과거처럼 오래 걸리지 않습니다. 이 경험을 통해 timeout은 임의의 숫자가 아니라 정상 응답 범위, 장애 상태, 실패 비용을 구분해 정해야 한다는 점을 배웠습니다.
프로젝트 중간에 React 환경변수가 빌드 산출물에 포함되고 브라우저에서 확인될 수 있다는 사실을 발견했습니다. 클라이언트 환경변수에 시크릿을 둘 수 있다고 잘못 이해했던 문제였습니다. 외부 API 호출을 PHP 프록시 뒤로 옮기고 API Key는 서버 환경변수에서만 읽도록 수정했습니다.
고객 컴플레인으로 접수된 결제·예약 불일치는 2026-08 기준 10건 미만이었습니다. 이는 시스템 전수 집계가 아니라 실제 불일치의 하한입니다.
응답 미도달, PMS 장애, 조기 timeout 오판을 차례로 추적하면서 자동 보상취소와 장애 로그 확인, timeout 정책을 보강했습니다. 2024년 오픈부터 현재까지 유지보수하는 동안 같은 유형의 문제를 추가로 파악하지 못했지만, 이 역시 전수 집계가 아닌 운영 관찰 범위입니다.
외부 근거 없이 임의 설정한 timeout은 정상 요청도 실패로 오판하게 만들 수 있었습니다. 당시 약 20초 지연은 API 문제로 발생한 상태였고 현재는 해당 API가 수정됐습니다. 다음에는 정상 응답 범위와 장애 상태를 구분하고 외부 계약과 실패 비용을 확인한 뒤 timeout을 정해야 합니다. 이 작업에서는 30초 사용자 경험과 60초 결제 안전성 사이에서 조기 취소의 실패 비용이 더 크다고 보고 장애 대응값 60초를 선택했습니다.
SPA의 시크릿 경계를 잘못 이해했던 사실도 숨기지 않습니다. 클라이언트 빌드 산출물은 공개된다는 원칙을 이후 설계의 출발점으로 삼았고, 프록시를 만드는 데서 끝내지 않고 시크릿이 머무는 경계를 서버로 옮겼습니다.
자동 보상취소만 구현하는 데서 끝내지 않고 장애 구간을 확인할 수 있는 로그와 timeout 정책을 함께 다뤄야 서로 다른 실패를 구분할 수 있다는 점이 가장 크게 남았습니다.