Indie Hackers

I froze my SaaS template because marketing felt endless. Here's what I fixed before relaunching it.

마케팅이 끝없이 느껴져 멈췄던 SaaS 템플릿, 재출시 전에 고친 점

SlotKit 제작자는 에이전시용 예약 시스템 템플릿을 다시 출시하기 전, 결제 우회와 동시 예약 같은 문제를 점검하고 고쳤습니다. v1.5.2에는 결제·웹훅·동시성 테스트 20개와 업그레이드 안내서 등이 추가됐으며, 재출시 뒤에는 유입 경로별 방문과 판매를 추적할 계획입니다.

에디터 노트

판매가 부진한 원인을 마케팅으로만 돌리기 어려워졌습니다. 첫 출시 때 유입과 결제 전환을 기록하지 않아 어느 단계에서 막혔는지 몰랐고, 코드 점검에서는 결제 없이 예약을 확정하는 경로와 동시 예약 문제가 드러났습니다. 기술 수정과 채널별 추적을 함께 시작한 배경이 여기에 있습니다. 다만 v1.5.2의 20개 테스트가 현재 확인하는 범위와 아직 구현하지 않은 결제 만료 처리는 구분해야 합니다. 제작자는 지연 결제 수단과 시간대 재확인 절차를 다음 작업으로 남겼습니다. 댓글에서 제기된 실제 사용자 환경의 예상 밖 오류도 남아 있어, 첫 예약 로그를 다음 점검 기회로 삼겠다는 설명이 이 계획과 맞닿습니다.

AI 요약

SlotKit은 Next.js로 만든 예약 시스템 템플릿입니다. 살롱, 클리닉, 체육관 같은 고객사를 위해 예약 기능을 반복해서 만드는 에이전시를 겨냥합니다. 제작자는 Gumroad에 올리고 홍보 글도 게시했지만 판매가 더디자 프로젝트를 멈췄습니다. 다시 출시하기 전 코드를 점검했고, 한 개 테넌트에서 작동하는 것만으로는 실제 서비스 준비가 끝난 게 아니라는 점을 확인했습니다.

재출시 전후의 변경

제작자는 v1.5에서 점검 중 찾은 문제를 수정했다고 밝혔습니다. 댓글에서 공개 예약 API로 Stripe 결제 없이 유료 예약을 확정할 수 있었던 문제를 설명했습니다. 이제 유료 서비스 예약 요청에는 402 응답을 보내고, 결제 완료는 Stripe 웹훅이 확인할 때까지 대기 상태로 둡니다. 한 시간대를 여러 고객이 동시에 예약하는 경쟁 조건도 처리하도록 바꿨습니다.

업데이트 안내에 따르면 v1.5.2에는 자동화 테스트 20개, 제한 시간을 둔 잠금 대기, 커스터마이즈한 프로젝트를 위한 업그레이드 안내서, 비밀번호 재설정 절차가 포함됩니다. 테스트는 결제 우회와 Stripe 웹훅을 확인하고, 실제 PostgreSQL에 같은 시간대 예약 요청 10개를 동시에 보내는 경우도 다룹니다. 제작자는 이 동시성 테스트를 10회 실행했으며 잠금을 제거하면 매번 테스트가 실패하는지 확인했다고 댓글에 덧붙였습니다.

결제와 예약 만료에 관한 검토는 진행 중입니다. 제작자는 Stripe Checkout 세션이 30분 뒤 만료되면 웹훅이 대기 예약을 취소하고 시간대를 비운다고 설명했습니다. 지연 결제 수단은 아직 처리하지 않으며, 결제 확정 단계에서 시간대가 여전히 비어 있는지도 다시 확인하지 않습니다. 만료 뒤 결제가 도착하면 예약 가능 여부를 재확인하고, 이미 다른 예약이 잡혔다면 자동 환불과 고객 안내를 처리하는 방안을 계획한다고 밝혔습니다. 이 흐름은 아직 구현 완료로 설명하지 않았습니다.

제품과 재출시 계획

기술 스택은 Next.js 16, Supabase, Drizzle, Better Auth, Stripe, Resend입니다. 가격은 한 번 결제하는 149달러이며, 여러 고객사에 쓰거나 화이트라벨을 적용하는 Pro와 Team 라이선스를 둡니다. 별도 설치 지원 상품은 표준 249달러, 브랜딩 포함 399달러라고 댓글에서 밝혔습니다.

첫 출시 때는 유입과 결제 전환을 추적하지 않아 판매가 부진한 이유를 알 수 없었습니다. 이번에는 링크마다 UTM 태그를 붙이고, 2~3주 뒤 채널별 Gumroad 방문과 판매를 비교해 성과가 있는 채널에 집중할 계획입니다. 제작자는 dev.to, Indie Hackers, X에서 시작하고 Product Hunt도 몇 주 뒤 고려한다고 했습니다. 살롱과 클리닉 가운데 한 업종을 골라 메시지를 좁히고, 두 브라우저가 같은 시간대를 예약하려는 장면과 취소 뒤 시간대가 다시 열리는 장면을 짧은 데모로 보여주겠다고 답했습니다.

Indie Hackers 반응

  • @Víctor — 코드만 보면 이상이 없어도 실제 사용자는 다른 문제를 찾습니다. 제 앱은 가장 빨리 응답하는 서버를 골라야 했는데 브라우저가 응답 속도가 아니라 목록 순서대로 서버를 골랐습니다. 세계 반대편 사용자가 먼 지역 서버를 거쳤고, 사용자의 제보를 받은 뒤 모니터링을 만들어 확인했습니다.
    • @SlotKit — 실제 트래픽이 아직 없어서 첫 예약을 다음 점검 기회로 삼고 웹훅 실패, 409, 503을 기록하려고 합니다. 잘못된 지역 서버 선택은 사용자 제보로 알게 됐나요, 모니터링으로 알게 됐나요?
    • @Víctor — 먼저 사용자 제보를 받았고, 그 뒤 모니터링을 만들어 문제와 수정 결과를 확인했습니다.
  • @deployvet — 트랜잭션 안에서 시간대를 확인하고 리소스별 잠금을 거는 방식이 적절합니다. Stripe 웹훅도 멱등성을 확인해야 합니다. checkout.session.completed 이벤트가 재전송돼도 예약이 두 번 확정되거나 취소된 예약이 되살아나면 안 됩니다. 결제 화면에 있는 동안 시간대를 짧게 점유하나요, 결제 성공 뒤에만 잠그나요?
  • @BuilderPot — 결제 우회 수정에 자동 회귀 테스트가 있나요? 유료 서비스 요청이 402를 받는지, 웹훅이 올 때까지 결제 예약이 대기 상태인지 확인하는 테스트가 제품 페이지의 근거가 될 수 있습니다.
    • @SlotKit — 코드는 수정했지만 자동 회귀 테스트는 아직 없습니다. 유료 서비스 결제 우회, 동시 예약, 시간대를 테스트 목록에 넣겠습니다.
    • @SlotKit — v1.5.2에 테스트를 추가했습니다. 유료 서비스 요청은 402를 받고, 서명된 웹훅이 확인할 때까지 예약은 대기 상태입니다. 실제 PostgreSQL에서 같은 시간대 예약 10건을 동시에 보내는 테스트도 10회 실행합니다. 잠금을 빼면 매번 테스트가 실패하는 것을 확인했습니다.
  • @Rao Rabi — 누군가 결제를 시작한 뒤 나가고, 시간대가 풀려 다른 사람이 예약한 다음에 결제하면 어떻게 처리하나요? 만료된 예약과 늦은 결제의 관계도 동시 예약 방지 못지않게 중요합니다.
    • @SlotKit — 현재 예약 점유 시간은 Stripe Checkout 세션의 30분 수명입니다. 세션이 만료되면 웹훅이 대기 예약을 취소하고 시간대를 비웁니다. 지연 결제 수단은 아직 처리하지 않으며 결제 확정 때 시간대가 비어 있는지 다시 확인하지 않습니다. 결제가 풀린 예약에 도착하면 시간대를 확인하고, 이미 찼다면 자동 환불과 고객 안내를 처리할 계획입니다.
  • @jessekraaijeveld — 커스터마이즈한 코드에 업데이트를 적용하는 과정도 구매자가 궁금해할 수 있습니다. 업그레이드 안내서나 수정한 데모를 보여주면 인수 뒤 어떤 일을 해야 하는지 알기 쉽습니다.
    • @SlotKit — 커스터마이즈한 포크를 위한 Git 병합 방식, ZIP과 diff 방식, 데이터베이스 안내, 수정해도 업데이트 충돌이 적은 파일을 정리한 안내서를 작성했습니다.

원문: Indie Hackers / 번역·요약: Trawling