Architecture at a glance구조 한눈에 보기
Take payment through CheckoutCheckout으로 결제
Connect the platform’s payment workflow to Stripe Checkout.플랫폼의 결제 흐름을 Stripe Checkout에 연결합니다.
Validate the notification결제 알림 검증
Verify the webhook signature before handling the payment notification.결제 알림을 처리하기 전에 웹훅 서명을 검증합니다.
Activate lesson credits수업 크레딧 활성화
Connect the accepted payment to the platform’s credit workflow.확인된 결제를 플랫폼의 크레딧 처리에 연결합니다.
Commit the booking and credit use예약과 크레딧 사용을 함께 저장
Keep the reservation record and credit consumption in one database transaction.예약 기록과 크레딧 차감을 하나의 데이터베이스 트랜잭션으로 처리합니다.
Run external follow-up외부 서비스 후속 처리
Handle Calendar, Meet and email through queue-backed tasks with execution records.Calendar·Meet·이메일은 실행 기록을 갖춘 큐 기반 작업으로 처리합니다.
1. A payment is one step in a larger workflow1. 결제는 더 큰 업무 흐름의 한 단계입니다
For Polyhop, I developed a NestJS/TypeScript backend for teacher and student accounts, lesson products, reservations, credits and payments. I implemented the Stripe integration end to end, including Checkout, signature-verified webhooks and payment-to-credit activation. The product goal connected several systems: a student pays, receives usable lesson credits, books a lesson and receives the scheduling details.Polyhop에서는 교사·학생 계정, 수업 상품, 예약, 크레딧, 결제를 담당하는 NestJS/TypeScript 백엔드를 개발했습니다. Checkout, 서명 검증 웹훅, 결제 후 크레딧 활성화를 포함한 Stripe 연동을 처음부터 끝까지 구현했습니다. 학생이 결제하고, 사용할 수 있는 수업 크레딧을 받고, 수업을 예약하고, 일정 정보를 받는 과정이 여러 시스템에 걸쳐 연결되는 제품이었습니다.
I organized these responsibilities into business modules, including authentication, payments, reservations, credits, calendars and notifications. JWT, roles and Google OAuth served account workflows. Stripe webhook verification served a separate boundary: accepting an external payment notification. Those two kinds of request establish different facts about who is calling and what happened.인증, 결제, 예약, 크레딧, 캘린더, 알림 등 업무 단위로 책임을 나눴습니다. 계정 흐름에는 JWT·역할 권한·Google OAuth를 적용했습니다. Stripe 웹훅 검증은 외부 결제 알림을 받아들이는 별도의 경계였습니다. 두 요청은 호출 주체와 발생한 사건에 대해 서로 다른 사실을 확인합니다.
2. Payment evidence and application state2. 결제의 근거와 애플리케이션 상태
The signature check establishes the notification’s sender and integrity. The payment handler then determines whether the reported payment qualifies for credit activation. The booking workflow can use the activated lesson credits.서명 검사는 알림의 발신 주체와 무결성을 확인합니다. 결제 처리기는 보고된 결제가 크레딧 활성화 대상인지 판단합니다. 예약 흐름에서는 이렇게 활성화한 수업 크레딧을 사용합니다.
Stripe’s official guide explains the verification inputs: the original request body, the Stripe-Signature header and the endpoint secret. This is why preserving the original body matters when a payment notification passes through a web framework or proxy.Stripe 공식 문서는 검증에 필요한 입력으로 원본 요청 본문, Stripe-Signature 헤더, 엔드포인트 비밀값을 설명합니다. 웹 프레임워크나 프록시를 거치는 결제 알림에서도 원본 본문 보존이 중요한 이유입니다.
3. Keep booking and credit accounting together3. 예약과 크레딧 회계를 함께 처리한 이유
I committed booking records and credit consumption together. These writes describe one business action: using a credit to reserve a lesson. Saving only the reservation could leave a booked lesson without its corresponding credit use; saving only the credit change could charge the student without a reservation. A database transaction groups those local changes into an all-or-nothing operation.예약 기록과 크레딧 차감을 함께 커밋했습니다. 두 변경은 크레딧을 사용해 수업을 예약한다는 하나의 업무 행위를 표현합니다. 예약만 저장하면 그에 대응하는 크레딧 사용이 남지 않을 수 있고, 크레딧 변경만 저장하면 예약 없이 차감될 수 있습니다. 데이터베이스 트랜잭션은 이러한 내부 변경을 모두 반영하거나 모두 취소하는 단위로 묶습니다.
Calendar, Meet and email were handled as queue-backed follow-up work, with status, attempt and error records. The architecture used an API Lambda and a separate SQS worker. This separation gave the booking operation a clear local commit boundary and gave external follow-up its own execution state.Calendar·Meet·이메일은 상태·시도·오류 기록을 갖춘 큐 기반 후속 작업으로 처리했습니다. 구조에는 API Lambda와 별도의 SQS 작업자가 포함됩니다. 이렇게 분리해 예약 작업에는 명확한 내부 커밋 경계를 두고, 외부 후속 작업에는 별도의 실행 상태를 부여했습니다.
A database rollback does not undo an email already sent by an external provider. Booking persistence and external delivery therefore need separate outcomes. A committed reservation alone cannot confirm that its invitation was delivered; the follow-up task state must also be inspected.데이터베이스를 롤백해도 외부 제공자가 이미 보낸 이메일까지 되돌릴 수는 없습니다. 예약 저장과 외부 전달은 각각의 결과로 다뤄야 합니다. 예약이 저장되었다는 사실만으로 초대 전달까지 완료되었다고 볼 수 없으므로 후속 작업의 상태도 확인해야 합니다.
4. A synthetic two-credit example4. 크레딧 두 개로 보는 가상 예시
Imagine a student buys two lesson credits. A verified payment notification leads to two credits becoming available. Later, the student books one lesson: the reservation and the change from two available credits to one are committed together. A follow-up task then handles the calendar invitation, meeting details and confirmation email. These invented quantities illustrate the system boundaries.학생이 수업 크레딧 두 개를 구매한다고 가정해 봅니다. 검증된 결제 알림을 통해 사용할 수 있는 크레딧 두 개가 활성화됩니다. 이후 수업 한 번을 예약하면 예약 기록과 사용 가능 크레딧이 두 개에서 한 개로 바뀌는 변경을 함께 커밋합니다. 후속 작업은 캘린더 초대, 미팅 정보, 확인 이메일을 처리합니다. 시스템의 경계를 설명하기 위해 만든 가상의 수치입니다.
If the booking transaction cannot complete, the intended local outcome is neither a saved reservation nor consumed credit. If an external follow-up fails after the commit, the local booking and the failed task are distinct facts to inspect. The task’s status and error records help investigate the follow-up failure.예약 트랜잭션을 완료할 수 없다면 내부적으로는 예약도 크레딧 차감도 저장되지 않는 것이 의도한 결과입니다. 커밋 후 외부 후속 처리가 실패하면 내부 예약과 실패한 작업은 각각 확인해야 할 사실입니다. 작업의 상태와 오류 기록을 바탕으로 후속 처리 실패를 확인합니다.
5. Suggested acceptance checks5. 인수 확인 항목 제안
The following questions are proposed acceptance checks for a review or handover of this architecture.이 구조를 검토하거나 인계할 때 다음과 같은 질문으로 인수 확인 범위를 잡을 수 있습니다. 아래 항목은 검증 제안입니다.
- Payment boundary: which accepted event and payment-state checks authorize credit activation, and does an invalid signature leave credit state unchanged?결제 경계: 어떤 이벤트와 결제 상태를 확인해야 크레딧을 활성화하는가? 잘못된 서명은 크레딧 상태를 변경하지 않는가?
- Local transaction: if the booking write fails, are the reservation and its credit consumption both absent?내부 트랜잭션: 예약 저장이 실패하면 예약과 해당 크레딧 차감이 모두 남지 않는가?
- External follow-up: how much can the task records distinguish among Calendar, Meet and email outcomes after a booking commits?외부 후속 처리: 예약 저장 후 Calendar·Meet·이메일 각각의 결과를 작업 기록에서 어느 수준까지 구분할 수 있는가?
- Authorization: can the relevant teacher, student and administrative actions be exercised only by the intended roles?권한: 교사·학생·운영 기능을 의도한 역할만 실행할 수 있는가?
- Repeated or concurrent requests: how are duplicate payment notifications and simultaneous credit consumption handled?반복·동시 요청: 중복 결제 알림과 동시에 발생하는 크레딧 사용을 어떻게 처리하는가?
- Database-to-queue handoff: how is a committed booking detected if follow-up task submission fails?데이터베이스·큐 인계: 예약은 저장되었지만 후속 작업 전달이 실패한 경우 어떻게 확인하는가?
6. What this case establishes6. 이 사례에서 확인할 수 있는 범위
This case focuses on payment, credit and reservation boundaries, plus external scheduling and notification work. The implementation was part of my February–December 2025 backend role at Polyhop.이 사례는 결제·크레딧·예약의 경계와 외부 일정·알림 처리를 중심으로 설명합니다. 2025년 2~12월 Polyhop 백엔드 개발을 담당하며 구현한 범위입니다.