TicketFlowCloud-native ticketing on Kubernetes
A ticketing platform with seat booking, payment and QR tickets as PDF, split into microservices and deployed on Kubernetes on Azure. A three-person Master's project, built in 48 hours: I owned the back end, the infrastructure and the delivery pipeline.
The project
The brief asked us to demonstrate ten cloud-native concepts on a real application, with a public URL, infrastructure as code and continuous deployment. We picked ticketing because it packs the real problems of a distributed system: two people wanting the same seat, a payment that stops answering, a ticket that must be generated once and only once.
SSamy
Back end, infrastructure, CI/CD
API, worker, payment gateway, Terraform, Kubernetes manifests, pipelines.
FFayrouz
Front end
React app: catalogue, seat map, cart, tickets.
MMelvin
Documentation and defence
Report, demo script, ticket rendering rework.
Figures taken from the GitHub repository.
Architecture
Everything runs in an AKS cluster. Traefik takes the traffic and routes it to the front end or the API; the API is stateless, so it can run as many copies as needed.
The user picks seats: the API places a short Redis lock on each one.
At checkout, the API calls the payment gateway through a circuit breaker, with a timeout and a fallback.
Payment accepted: the API publishes a reservation.paid event to the BullMQ queue.
The worker builds the QR code and the PDF, stores them in object storage, then acknowledges.
The API serves the PDF and the QR check page, never exposing the storage.
The patterns, and where they live
Every concept can be checked in the code. Here are the main ones.
No double booking
Atomic SET NX EX lock on every seat: the first request wins, the second gets a 409, and the lock expires on its own if the user walks away.
api/src/holds.js
A slow payment cannot take the site down
opossum circuit breaker with timeout and fallback: after too many failures, the API answers at once instead of piling up requests.
api/src/payment.js
No message is ever lost
BullMQ queue with five attempts, exponential backoff and a kept failure queue. The worker only acknowledges once the work is done.
api/src/queue.js · worker/src/index.js
One ticket, exactly once
Idempotent worker: early guard, ON CONFLICT DO NOTHING and a booking-seat unique constraint in the database.
worker/src/handlers/reservationPaid.js
A database that survives restarts
PostgreSQL as a StatefulSet with a persistent volume, a headless service and readiness probes.
infra/k8s-aks/ticketflow.yaml
Ready for production
/healthz and /readyz routes, structured pino logs, clean shutdown on SIGTERM, Kubernetes probes everywhere.
api/src/health.js · server.js
Deliberate choices
Three decisions we defended in front of the jury rather than just accepted.
01AKS rather than Azure Container Apps
Container Apps hides Kubernetes. A real cluster let us show StatefulSets, Ingress, probes and high availability. The trade-off: a cost to watch, and a minikube fallback ready for the demo.
02PostgreSQL inside the cluster
Instead of a managed database: the StatefulSet and persistent volume pattern becomes concrete, and the infrastructure stays easy to reproduce.
03Tickets served by the API
Object storage stays private. PDFs go through an authenticated route instead of an exposed storage URL: a better security posture.
Delivery
Terraform provisions the resource group, image registry, AKS cluster, storage and secret vault. On every push to main, GitHub Actions builds and publishes the four images, then updates the cluster.
- 22 June 2026Skeleton and infrastructure
Monorepo, services, Kubernetes manifests, Terraform for Azure.
- 23 June 2026Continuous deployment and audit
Deployment pipeline switched on, compliance audit that caught two blocking defects before the demo, fixed right away.
- 24 June 2026Demo
Deployment guide and demo script: a live commit goes to production during the defence.
- Completed, June 2026Outcome
All ten expected concepts shown in verifiable code, an end-to-end demo, and a documented repository (architecture, API contract, ADRs, deployment guide).
No Azure account needed to try it: the whole project runs locally with a single command, docker compose up.