Case study

Close

Event Management System

An event ticketing API in Rust, built to practice Clean Architecture and domain-driven design.

Overview

A REST API for selling event tickets, built as a study case on Clean Architecture and domain-driven design. It covers events, ticket categories, bookings, payments, check-in, refunds and reports.

Problem

The course gave us 20 user stories for an event ticketing system, from creating events to paying out refunds. Each one had business rules, such as payment deadlines and no refunds for checked-in tickets.

We had to show where each rule lives and keep the core free of the web framework and the database.

Requirements

  • All 20 user stories work through REST endpoints
  • Business rules live in the domain layer
  • Outside services sit behind application ports
  • The API is documented with OpenAPI

Architecture

Four crates, one per layer. The domain crate holds the aggregates, value objects and domain events. The application crate holds command and query handlers and the ports. The infrastructure crate implements the ports with PostgreSQL and simulated services, and the api crate exposes it all with Rocket.

Technology choices

Rust
The type system makes invalid states hard to write in the domain.
Rocket
Simple routing and request guards for the API layer.
PostgreSQL and SQLx
Checked queries and real transactions across aggregates.
OpenAPI
Swagger UI let us try every endpoint while building.

Implementation

The domain has four aggregates: events, bookings, tickets and refunds. Each one guards its own rules and raises events such as EventPublished, BookingPaid and TicketCheckedIn.

  • Handlers load aggregates through repository ports and save them in one transaction.
  • A transaction manager covers operations that touch several aggregates.
  • Authentication is header based on purpose, since it was outside the case study.

Major challenges

  • Deciding which aggregate owns each rule
  • Expiring unpaid bookings on time without a background job
  • Splitting the work between two people without stepping on each other

Testing

30 unit tests on the event, booking and refund aggregates check the business rules, such as paying after the deadline, paying the wrong amount, and refunding a checked-in ticket. We tried every endpoint through Swagger UI against PostgreSQL in Docker.

Results

  • All 20 user stories implemented as command and query handlers with REST endpoints
  • 14 domain events and 4 application ports, documented in the README
  • Swagger UI and an OpenAPI spec served by the API

What I'd improve

  • Replace the header-based sign-in with real authentication
  • Add integration tests that run against the database

Code