Video summary

Build an Event Ticket Platform with Spring Boot - Full Build - Intermediate Project

Main summary

Key takeaways

Technology

Technology / Product Being Built

A full-stack event ticket platform using:

  • Spring Boot (REST API backend, Spring Security resource server)
  • React SPA (front-end; single-page app consuming the REST API)
  • PostgreSQL (main relational database)
  • Keycloak (authentication/authorization via OAuth2 + OpenID Connect; JWT)
  • Docker Compose (runs PostgreSQL + Adminer, and Keycloak locally)
  • MapStruct + Lombok (DTO/entity mapping and boilerplate reduction)
  • QR code generation using a QR library (generate QR image, store as base64)

Core workflow

  1. Event organizers create events with multiple ticket types.
  2. Attendees browse/search published events, view details, and purchase tickets (mock payment).
  3. Purchased tickets include a unique QR code.
  4. Event staff scan QR codes (or manually enter ticket IDs) to validate tickets at entry, preventing duplicates.

Video Structure / Key Modules and What They Implement

1) Domain analysis + requirements

  • Defines domain concepts: Event, Ticket, QR Code
  • Converts a project brief into user stories and acceptance criteria for:
    • Create event (organizer)
    • Purchase ticket (attendee)
    • Manage ticket sales (organizer analytics/limits/overselling prevention)
    • Validate ticket (staff scanning on mobile; instant feedback; prevent duplicate use)

2) UX/UI planning (personas, journeys, wireframes)

  • Creates user personas and journeys for:

    • Organizers (corporate manager, planning pro, part-time organizer)
    • Attendees (busy parent, young/digital native, corporate networking attendee)
    • Staff (coordinator, entry-level staff)
  • Figma UI wireframes:

    • Organizer pages: create/manage events, ticket sales, ticket types, reporting placeholder
    • Attendee pages: search events, event details, purchase ticket page (mock), tickets dashboard + QR display
    • Staff page: mobile-first QR scanner + manual entry + instant validation result

3) Domain modeling (class diagram → REST API blueprint)

  • Builds a domain/class model including relationships:

    • Event → ticket types → tickets → QR codes
    • Ticket → ticket validations (multiple validations tracked for history)
  • Evolves into a richer class diagram with:

    • cardinality
    • data types (UUIDs, enums, LocalDateTime)
    • required vs optional fields
  • This informs REST resource design.

4) REST API design (per user role)

Endpoints are planned from UI flows:

Organizer (“events” CRUD)

  • POST /api/v1/events (create event)
  • GET /api/v1/events (list events for organizer; paginated)
  • GET /api/v1/events/{eventId} (event details for organizer)
  • PUT /api/v1/events/{eventId} (full update)
  • DELETE /api/v1/events/{eventId} (delete)

Ticket sales / ticket type management

  • Tickets under event (list/retrieve; cancellation via status update)
  • Ticket types under event (list/retrieve; patch name/availability)
  • Validation concept: restrict deletes if tickets exist

Attendee (“published events” + purchase)

Public list/search

  • GET /api/v1/published-events (paginated)
  • optional query parameter for search

Public details

  • GET /api/v1/published-events/{eventId}

Ticket purchase (mock payment)

  • POST /api/v1/published-events/{publishedEventId}/ticket-types/{ticketTypeId}/tickets (mock)

Attendee dashboard

  • GET /api/v1/tickets (list user’s tickets; paginated)
  • GET /api/v1/tickets/{ticketId} (get ticket details)
  • GET /api/v1/tickets/{ticketId}/qr-codes (returns QR image bytes)

Staff validation

  • POST /api/v1/events/{eventId}/ticket-validations (QR scan or manual entry)
  • Planned: validation history listing (optional in this segment)

5) Architecture setup

  • SPA front-end (React) ↔ Spring Boot REST backend
  • PostgreSQL as relational DB
  • Keycloak as auth/authorization server

Notes:

  • React communicates via REST API
  • Keycloak used for JWT validation (resource server)
  • Authorization enforced in Spring Security by roles (organizer/attendee/staff)

Implementation Highlights (What Gets Coded)

Spring Boot project setup

  • Spring Initializer choices:
    • Java 21
    • Maven
    • Dependencies: Spring Web, Spring Security, OAuth2 Resource Server, Spring Data JPA, PostgreSQL driver, Lombok, H2 for tests

Docker Compose infrastructure

  • PostgreSQL + Adminer for viewing data
  • Keycloak container with persisted config (volume) for realms/clients/users

Keycloak setup

  • Realm: event-ticket-platform
  • Client for SPA (OpenID Connect, public access; redirect/callback configured)
  • Users + roles created:
    • Organizer role + user
    • Attendee role + user
    • Staff role + user

Entity modeling (JPA)

Implemented entities:

  • User
  • Event
  • TicketType
  • Ticket
  • TicketValidation
  • QRcode

Key ORM decisions:

  • Single User entity; user “type” handled via Keycloak roles
  • UUID primary keys (except keycloak user ID derived from JWT subject)
  • Audit fields via @CreatedDate / @LastModifiedDate and global JPA auditing enablement
  • Fixes included:
    • Renaming DB column names from reserved keywords like start/end to event start / event end

DTOs, validation, and MapStruct

  • Dedicated request/response DTOs per endpoint (decoupling entities from API contracts)
  • Validation with:
    • @NotBlank, @NotNull, @PositiveOrZero, etc.
    • nested validation via @Valid
  • Global error handling:
    • ConstraintViolationException
    • MethodArgumentNotValidException
    • custom exceptions (e.g., UserNotFoundException, later TicketNotFoundException, etc.)
  • MapStruct mappers convert entity ↔ DTO for request/response paths.

Feature-by-Feature: What Worked + Notable Bugs/Fixes

Create event (organizer)

  • Implemented:

    • DTOs for create request/response
    • service layer creates Event + nested TicketTypes via cascading
    • global exception handler returns consistent error format (HTTP codes + { "error": "..." })
  • Bug/fix:

    • Initial failures due to:
      • reserved SQL keywords (start, end)
      • controller annotation mismatch (@RequestParam vs @PathVariable)

List events for organizer (dashboard)

  • Paginated listing:
    • GET /api/v1/events?page=&size=...
  • DTO summary response includes:
    • event ID/name/start/end/venue/sales window/status + ticket type summaries

Get event details for organizer (edit form)

  • GET /api/v1/events/{eventId}
  • Returns full event details including ticket types; used to populate edit UI.

Update event (full update)

  • PUT /api/v1/events/{eventId}
  • Full replacement model:
    • updates fields
    • reconciles ticket types:
      • remove ticket types not present in request (orphan removal)
      • update existing ones by ID
      • create new ones when ticket type ID is null
  • Bug/fix note:
    • Ensures method is transactional to avoid inconsistent partial updates.

Delete event

  • DELETE /api/v1/events/{eventId}
  • UI button triggers confirmation modal
  • Returns 204 No Content on success

Public published events listing + search

  • Endpoint made public using Spring Security matchers:
    • GET /api/v1/published-events
  • Search:
    • GET /api/v1/published-events?Q=term
    • Uses PostgreSQL text search across name and venue
    • Filters by EventStatus = published

Get published event details (attendee view)

  • GET /api/v1/published-events/{eventId}
  • Public details DTO subset (no organizer/audit details)
  • Returns ticket type list used on ticket purchase page.

Purchase Ticket + QR Code Generation

QR code generation

  • Added QR code persistence fields:
    • stores QR image as B64 in a text column
  • Generates:
    • a manual UUID for QR code ID (baked into QR value)
    • QR image = PNG → bytes → base64 string
  • Uses a QR library (ZXing mentioned)
  • Saves QRcode entity linked to Ticket.

Ticket purchase

  • New ticket creation flow (no third-party payments; mock payment):
    • validates user + ticket type existence
    • checks available inventory and prevents overselling
    • implements concurrency control:
      • pessimistic lock on TicketType fetch (PESSIMISTIC_WRITE)
    • creates:
      • a Ticket (status purchased)
      • a QRcode for that ticket
  • Bug/fix:
    • Fixed NullPointerException where QR code repository was null due to missing dependency wiring/final injection.

Purchase endpoint

  • POST /api/v1/.../ticket-types/{ticketTypeId}/tickets
  • Returns 204 No Content (no ticket payload in response)

Role-based Security

JWT role extraction

  • Custom Converter parses JWT claim:
    • realm_access.roles
  • Converts RO_* roles (Keycloak convention) into Spring Security GrantedAuthoritys.

Endpoint authorization rules

  • Spring Security configured to restrict:
    • Organizer endpoints (event controller) to ROLE_organizer
  • Staff-only access added for ticket validation endpoint:
    • ROLE_staff

Tickets Dashboard + QR Retrieval

List tickets

  • GET /api/v1/tickets
  • Paginated listing for the logged-in user.

Get ticket details

  • GET /api/v1/tickets/{ticketId}
  • Returns flattened ticket + ticket type + event details for display.

Get ticket QR image

  • GET /api/v1/tickets/{ticketId}/qr-codes
  • Returns raw image bytes with correct Content-Type and Content-Length.

Ticket Validation (Staff Scanning + Manual Entry)

Validation service

Implemented TicketValidation creation for two input modes:

  • QR code scan:
    • uses QRcode lookup by id and status=active
  • Manual entry:
    • uses ticket ID directly

Validation logic:

  • Prevents duplicate redemption:
    • if any prior validation on the ticket is valid, the next becomes invalid.

Validation endpoint

  • POST endpoint under event route:
    • POST /api/v1/events/{eventId}/ticket-validations
  • Input DTO contains:
    • id and validationMethod (QR scan vs manual)

UI testing

  • Demonstrated:

    • scanning QR twice yields valid then invalid
    • manual entry yields valid then invalid
  • Bug discovered/fixed:

    • validation method incorrectly hardcoded as QR code scan in one branch; corrected so manual validations record correct method.

Notable “Analysis/Tutorial” Takeaways

  • Strong emphasis on deriving backend API from:
    • domain model + user stories + UI flows
  • Clear separation:
    • entities vs DTOs per endpoint
    • request DTOs vs response DTOs
  • Correct handling of:
    • validation errors and consistent API error response schema
    • transactional boundaries for write operations
    • reserved SQL keywords and ORM column naming
  • Local development stack:
    • Dockerized Postgres and Keycloak
    • Adminer for schema debugging
  • Security:
    • JWT role extraction from Keycloak
    • role-based endpoint access using Spring Security request matchers

Main Speakers / Sources (from the Subtitles)

  • Primary speaker/instructor: “I’ll show you the process that I use…” (unnamed in the subtitles)
  • Sources referenced in the video text:
    • Devto.com (premium UI lessons)
    • DevTiscord server (downloadable resources/source code/materials)
    • Keycloak documentation / libraries (e.g., MapStruct/Lombok/ZXing mentioned during implementation)

Original video