Context and ownership
I built the backend for a TEDx ticketing flow that supported 100+ ticket sales. The service owns ticket lookup, order creation, Xendit invoice creation, payment callbacks, payment/order status, ticket-stock updates, container packaging, and Cloud Run deployment.
The important boundary is that checkout and payment completion happen at different times: the original HTTP request creates an order and invoice, while Xendit later calls the service with the payment result.
Order creation is transactional
createOrder runs inside a Prisma transaction. It loads the requested tickets, validates that every referenced ticket exists and has sufficient availability, calculates the server-side amount, creates or reuses the customer, persists the order and items, creates the Xendit invoice, and stores payment metadata.
Keeping the database mutations together gives the service one explicit order-creation boundary. The trade-off is that the Xendit network call currently happens inside that transaction, so a slow provider request can keep database work open longer than necessary.
A production-hardening step would split external invoice creation from the database transaction with an explicit intermediate state or an outbox/job boundary.
Callback-driven payment state
Xendit payment completion arrives through a callback. The callback handler runs in another Prisma transaction and updates:
Payment -> Order -> Ticket stock
when the provider reports a successful payment.
This keeps the related database mutations together, but the current repository does not implement durable provider-event deduplication. A repeated successful callback can reach the stock-decrement path again. The portfolio therefore should not claim exactly-once delivery or duplicate-safe fulfillment.
Availability is not reservation
Checkout validates current ticket availability, but ticket stock is decremented only after payment succeeds. That means availability checking and stock consumption are separated by external payment time.
The service worked for the delivered event flow, but stronger concurrent guarantees would require reservation/locking semantics, reservation expiry, and idempotent callback processing.
Delivery
The service is containerized with Docker. GitHub Actions authenticates to Google Cloud, builds and pushes the image to GCR, then deploys it to Cloud Run.
That gives the project an end-to-end path from application code to a managed production runtime rather than stopping at local backend implementation.
Result
The delivered service supported 100+ ticket sales and centralized the event’s order, Xendit payment, callback, and stock-update flow.
The main engineering lesson is: database transactions help define local consistency boundaries, but they do not automatically solve external-network latency, repeated callbacks, or inventory reservation.