AI로 앱을 만들면 생각보다 빨리 “되는 것처럼 보이는 화면”이 나옵니다.
로그인도 되고, 예약 버튼도 눌리고, 주문 완료 페이지도 뜹니다.
그래서 많은 사람이 여기서 착각합니다.
“이제 결제만 붙이면 되겠는데?”
문제는 바로 그 다음입니다.
결제, 예약, 재고, 포인트, 쿠폰처럼 돈과 상태가 바뀌는 기능은 로컬 테스트에서 멀쩡해 보여도 실제 배포 후에 터질 수 있습니다.
특히 바이브 코딩이나 AI 코딩으로 만든 앱이라면 더 조심해야 합니다. AI는 문법상 그럴듯한 코드는 잘 만들지만, 동시에 여러 사용자가 누르거나 같은 요청이 두 번 들어오는 상황까지 항상 안전하게 처리해주지는 않습니다.
이 글은 레이스 컨디션을 공부하자는 글이 아닙니다.
AI로 만든 앱을 실제 서비스로 배포하기 전에, 결제 사고와 중복 주문을 피하려면 무엇을 봐야 하는지 정리한 글입니다.

결론부터: 결제 붙이기 전에는 이 4개를 봐야 합니다
AI가 만든 앱에 결제나 예약 기능을 붙이기 전에는 최소한 아래 4가지를 확인해야 합니다.
| 확인할 것 | 막는 문제 | 예시 |
|---|---|---|
| 조건부 업데이트 | 재고 1개에 주문 2개 | 티켓, 좌석, 쿠폰 |
| 트랜잭션 | 재고만 줄고 주문은 실패 | 주문, 포인트, 예약 |
| Row Lock | 읽고 계산하는 사이 데이터 변경 | 할인 계산, 좌석 배정 |
| Idempotency Key | 더블클릭·재시도로 중복 결제 | 결제, 웹훅, 주문 생성 |
여기서 중요한 건 용어 자체가 아닙니다.
AI에게 “이 코드 안전해?”라고 물으면 답이 애매합니다.
하지만 이렇게 물으면 달라집니다.
이 구매 API에 race condition이 있는지 봐줘.
재고 차감과 주문 생성이 같은 transaction 안에 있는지 확인해줘.
같은 idempotency key로 요청이 두 번 와도 주문이 하나만 생기게 해줘.
AI 코딩 시대에는 코드를 직접 다 쓰는 능력보다, AI가 만든 코드를 승인해도 되는지 판단하는 능력이 더 중요해집니다.
1. 재고를 읽고 줄이는 코드가 가장 먼저 위험합니다
AI가 구매 기능을 만들면 보통 이런 흐름이 나옵니다.
재고를 읽는다
→ 재고가 0보다 크면
→ 재고를 1 줄인다
→ 주문을 만든다
혼자 테스트하면 잘 됩니다.
문제는 실제 서비스에서는 혼자가 아니라는 점입니다.
재고가 1개 남은 상품을 두 명이 거의 동시에 구매하면 어떻게 될까요?
둘 다 재고를 1로 읽을 수 있습니다.
둘 다 “구매 가능”이라고 판단할 수 있습니다.
결과적으로 재고는 1개인데 주문은 2개가 생깁니다.
이게 레이스 컨디션입니다. MITRE의 CWE-362 Race Condition 설명에서도 공유 자원에 동시에 접근할 때 생기는 대표적인 약점으로 다룹니다.
이 문제를 줄이려면 앱 코드에서 재고를 읽고 판단하지 말고, 데이터베이스에 한 번에 요청해야 합니다.
UPDATE tickets
SET stock = stock - 1
WHERE id = :ticket_id
AND stock > 0;
핵심은 WHERE stock > 0입니다.
“재고가 있으면 줄여줘”를 애플리케이션이 아니라 데이터베이스가 한 번에 처리하게 만드는 방식입니다. PostgreSQL의 UPDATE 동작은 PostgreSQL UPDATE 공식 문서에서 확인할 수 있습니다.
AI에게는 이렇게 말하면 됩니다.
재고를 먼저 조회한 뒤 앱 코드에서 stock > 0을 검사하지 말고,
stock > 0 조건이 들어간 단일 UPDATE로 바꿔줘.
성공 여부는 affected rows 또는 RETURNING 결과로 판단하게 해줘.
2. 재고 차감과 주문 생성은 따로 두면 안 됩니다
조건부 업데이트를 했다고 끝이 아닙니다.
재고 차감은 성공했습니다.
그런데 주문 생성 직전에 서버가 죽으면 어떻게 될까요?
결과는 이렇습니다.
재고는 줄었다
주문은 없다
사용자는 구매하지 못했다
운영자는 사라진 재고를 본다
이런 상태를 부분 쓰기라고 볼 수 있습니다.
작업의 절반만 성공한 것입니다.
결제, 예약, 포인트, 쿠폰에서 이 문제는 생각보다 치명적입니다.
- 포인트는 차감됐는데 주문이 없다.
- 쿠폰은 사용 처리됐는데 결제가 실패했다.
- 좌석은 예약 불가인데 예약자는 없다.
- 재고는 줄었는데 구매 내역이 없다.
그래서 상태가 함께 바뀌는 작업은 트랜잭션으로 묶어야 합니다.
트랜잭션 시작
→ 재고 차감
→ 주문 생성
→ 모두 성공하면 커밋
→ 하나라도 실패하면 롤백
PostgreSQL 기준 트랜잭션은 BEGIN, COMMIT, ROLLBACK 흐름으로 관리하며, 관련 개념은 PostgreSQL 트랜잭션 문서에서 확인할 수 있습니다.
AI가 만든 코드를 볼 때는 이렇게 물어보세요.
재고 차감과 주문 생성이 같은 database transaction 안에 있나요?
주문 생성이 실패하면 재고 차감도 rollback되나요?
같은 함수 안에 코드가 붙어 있다고 안전한 게 아닙니다.
같은 트랜잭션 안에 있어야 안전합니다.
3. 읽고 계산한 뒤 수정하는 로직은 Row Lock을 봐야 합니다
모든 구매 로직이 단순하지는 않습니다.
예를 들어 이런 경우가 있습니다.
좌석 정보를 읽는다
→ 사용자 등급을 확인한다
→ 할인율을 계산한다
→ 예약 가능 여부를 다시 본다
→ 좌석을 확정한다
→ 주문을 만든다
이런 로직은 단순한 UPDATE 한 줄로 끝나지 않습니다.
중간에 읽고 계산하는 시간이 생깁니다.
그 사이 다른 사용자가 같은 좌석이나 같은 재고를 건드리면 문제가 생길 수 있습니다.
이때 검토할 것이 Row Lock입니다. PostgreSQL에서는 SELECT ... FOR UPDATE 같은 방식으로 선택한 행을 잠글 수 있으며, 자세한 잠금 동작은 PostgreSQL explicit locking 문서에서 확인할 수 있습니다.
다만 Row Lock은 무조건 쓰는 답이 아닙니다.
잠금을 잡은 채 결제 API를 호출하거나 오래 걸리는 작업을 하면 성능 문제가 생깁니다.
기준은 간단합니다.
| 상황 | 먼저 볼 해결책 |
|---|---|
| 단순히 재고 1개 줄이기 | 조건부 UPDATE |
| 재고 차감 + 주문 생성 | 트랜잭션 |
| 여러 값을 읽고 계산한 뒤 수정 | 트랜잭션 + Row Lock 검토 |
| 외부 결제 API 호출 | 잠금 구간 밖으로 분리 |
AI에게는 이렇게 요청하면 됩니다.
이 로직은 데이터를 읽고 할인 계산 후 다시 수정합니다.
단일 UPDATE로 줄일 수 없다면 transaction 안에서 SELECT ... FOR UPDATE 같은 row lock이 필요한지 검토해줘.
단, 외부 결제 API 호출은 잠금 구간 밖으로 분리할 수 있는지도 봐줘.
4. 더블클릭과 재시도는 프론트에서 막는 게 아닙니다
AI가 만든 앱에서 정말 자주 놓치는 부분이 있습니다.
사용자가 구매 버튼을 눌렀습니다.
화면이 느립니다.
실패한 줄 알고 한 번 더 누릅니다.
또는 모바일 앱이 네트워크 오류로 같은 요청을 다시 보냅니다.
또는 결제사가 같은 웹훅을 다시 보냅니다.
서버 입장에서는 같은 의도가 두 번 들어온 것입니다.
이때 서버가 둘 다 새 요청으로 처리하면 주문이 두 개 생깁니다.
결제라면 더 심각합니다. 중복 결제가 됩니다.
이 문제는 버튼 비활성화만으로는 막을 수 없습니다.
서버가 “이 요청은 전에 처리한 요청”이라고 기억해야 합니다.
그때 쓰는 방식이 Idempotency Key입니다.
구매 시작 시 고유한 키를 만든다
→ 같은 구매 재시도에는 같은 키를 보낸다
→ 서버는 키를 먼저 확인한다
→ 이미 처리한 키면 새 주문을 만들지 않고 이전 결과를 돌려준다
Stripe도 결제 API에서 Idempotent requests 문서를 따로 제공할 만큼, 결제 시스템에서는 중요한 패턴입니다.
AI에게는 이렇게 시키면 됩니다.
이 주문 생성 API에 idempotency key를 추가해줘.
같은 user_id와 같은 idempotency key로 요청이 반복되면 주문을 새로 만들지 말고 이전 결과를 반환하게 해줘.
idempotency key 저장은 unique constraint 또는 upsert로 보호해줘.
중요한 점은 하나 더 있습니다.
Idempotency Key를 확인하는 코드도 안전해야 합니다.
단순히 “키가 있는지 조회하고, 없으면 저장”으로 만들면 그 사이에도 레이스 컨디션이 생길 수 있습니다.
그래서 데이터베이스의 UNIQUE 제약이나 ON CONFLICT 같은 방식으로 막아야 합니다.
AI에게 바로 던질 배포 전 코드 리뷰 프롬프트
아래 프롬프트는 저장해두고 그대로 써도 됩니다.
아래 코드는 AI가 만든 구매/예약/결제 관련 API입니다.
문법이나 스타일보다 운영 안정성 관점에서 리뷰해 주세요.
1. 재고, 좌석, 포인트, 쿠폰을 먼저 조회한 뒤 앱 코드에서 검사하는 read-check-write 구조가 있는지 봐 주세요.
2. 단일 조건부 UPDATE로 바꿀 수 있는 부분이 있는지 제안해 주세요.
3. 재고 차감, 주문 생성, 포인트 차감, 쿠폰 사용 처리가 같은 transaction 안에 있는지 확인해 주세요.
4. 중간 실패 시 partial write가 생기는지 봐 주세요.
5. 여러 값을 읽고 계산한 뒤 수정하는 구간에는 row lock이 필요한지 검토해 주세요.
6. 더블클릭, 앱 재시도, 결제 웹훅 재전송에 대비한 idempotency key가 있는지 확인해 주세요.
7. idempotency key 저장 자체가 unique constraint 또는 upsert로 보호되는지 봐 주세요.
8. 재고 1개에 동시에 구매 요청 2개를 보내는 테스트 케이스를 제안해 주세요.
이 프롬프트의 핵심은 “좋게 고쳐줘”가 아닙니다.
AI가 놓치기 쉬운 실패 이름을 직접 지정하는 것입니다.
배포 전 체크리스트
AI로 만든 앱에 결제, 예약, 재고 기능을 붙이기 전에는 최소한 아래만 확인하세요.
□ 재고나 포인트를 먼저 조회한 뒤 앱 코드에서 검사하고 있지 않은가?
□ 단순 차감은 조건부 UPDATE로 처리하고 있는가?
□ 재고 차감과 주문 생성이 같은 트랜잭션 안에 있는가?
□ 주문 생성 실패 시 재고나 포인트가 롤백되는가?
□ 여러 단계를 읽고 계산한다면 Row Lock이 필요한지 검토했는가?
□ 사용자의 더블클릭과 앱 재시도에 대비한 Idempotency Key가 있는가?
□ 결제 웹훅 event id를 중복 저장하지 않도록 막고 있는가?
□ 재고 1개에 동시 구매 요청 2개를 보내는 테스트를 해봤는가?
이 중 하나라도 답이 애매하면, 아직 결제를 붙일 단계가 아닐 수 있습니다.
FAQ
개인 프로젝트도 이렇게까지 해야 하나요?
돈, 예약, 재고, 포인트, 쿠폰이 없다면 과할 수 있습니다.
하지만 결제나 예약이 들어가는 순간 개인 프로젝트라도 확인해야 합니다. 사용자 수가 적어도 더블클릭, 네트워크 재시도, 결제 웹훅 재전송은 언제든 생길 수 있습니다.
버튼 비활성화로 중복 주문을 막으면 안 되나요?
버튼 비활성화는 사용자 경험 개선일 뿐입니다.
서버 안정성의 대체재가 아닙니다. 사용자는 새로고침할 수 있고, 앱은 재시도할 수 있고, 결제사는 같은 이벤트를 다시 보낼 수 있습니다. 중복 주문과 중복 결제는 서버에서 Idempotency Key로 막아야 합니다.
결론: AI 앱은 “작동”보다 “동시에 작동해도 안전한가”를 봐야 합니다
AI로 앱을 만드는 속도는 정말 빨라졌습니다.
하지만 빠르게 만든 앱이 곧바로 운영 가능한 앱이라는 뜻은 아닙니다.
특히 결제, 예약, 재고, 포인트처럼 상태가 바뀌는 기능은 “내 컴퓨터에서 한 번 눌렀을 때 잘 됐다”로 판단하면 위험합니다.
배포 전에 이 네 가지를 꼭 확인해야 합니다.
조건부 UPDATE
트랜잭션
Row Lock
Idempotency Key
AI가 코드를 쓰는 시대에도 이해는 외주화할 수 없습니다.
AI가 만든 앱에 결제를 붙이기 전, 마지막 질문은 이것이어야 합니다.
이 코드는 한 명이 한 번 눌렀을 때만 안전한가,
아니면 여러 명이 동시에 누르고 같은 요청이 다시 와도 안전한가?
'SW > 인공지능' 카테고리의 다른 글
| AI 에이전트 만들기, Genspark·n8n·Hermes·Python 선택 기준 (0) | 2026.08.15 |
|---|---|
| AI 도구 추천, 많이 사지 말고 5개만 남기세요 (0) | 2026.08.11 |
| AI 에이전트를 회사 업무에 붙여보려다 깨닫는 7가지 운영 리스크 (0) | 2026.08.07 |
| AI를 회사 업무에 붙이기 전에 확인할 것: 데모는 되는데 운영에서 깨지는 이유 (0) | 2026.08.06 |
| AI한테 "무슨 주식 사?" 물어봤다가, AI 주식 추천 그대로 믿으면 안 되는 이유 (0) | 2026.08.05 |