The interviewer just said…
“What APIs or services would you expose?”
They have your entities. Now they want boundaries — who owns which operation, and what methods a client (or controller) would call.
What you should do next
Propose five services. One orchestrator (BookingService), three domain services, one stub. Write method signatures only — no implementation yet. Say which service owns seat state transitions (ShowService).
Service map
┌──────────────┐ ┌─────────────┐ ┌───────────────┐
│ MovieService │ │ ShowService │ │ TicketService │
│ search │ │ seats │ │ tickets │
└──────┬───────┘ └──────┬──────┘ └───────┬───────┘
│ │ │
└────────────────────┼────────────────────┘
▼
┌─────────────────┐
│ BookingService │ ◄── orchestrates saga
└────────┬────────┘
│
┌────────▼────────┐
│ PaymentService │ ◄── stub in v1
└─────────────────┘
MovieService — discovery by city
Owns read-only movie/theater/show discovery. No seat mutations.
public class MovieService {
// Movies currently playing in a city (distinct movie names/ids)
Set<String> searchMovieForCity(String city);
// Shows for a movie (theater, time) — extend in later iterations
List<String> searchShowForMovie(String movieId);
// Which theaters host a given show
List<String> searchTheaterForShow(String showId);
}
Reference: MovieService.searchMovieForCity walks TheaterRepo → ShowRepo and collects movie IDs.
ShowService — seat inventory
Only service that should flip ShowSeat.status (reserve, book, release).
public class ShowService {
List<ShowSeat> getAvailableSeats(String showId);
void reserveSeat(String showId, List<String> seatIds) throws ReserveException;
void bookSeat(String showId, List<String> seatIds) throws BookingException;
void releaseSeat(List<String> seatIds, String showId);
}
Implementation note for later: reserveSeat checks all requested seats are AVAILABLE, sets RESERVE + reserveTime. bookSeat moves RESERVE → BOOKED. releaseSeat → AVAILABLE.
BookingService — saga orchestrator
Coordinates the multi-step flow. Does not mutate seat rows directly — delegates to ShowService.
public class BookingService {
String bookShow(String showId, String userId, List<String> seats);
void cancelTicket(String ticketId);
}
Expected internal sequence for bookShow:
showService.reserveSeat(showId, seats);
String paymentId = paymentService.initiatePayment(userId, showId, seats);
showService.bookSeat(showId, seats);
return ticketService.bookTicket(userId, showId, seats, paymentId);
In hub/scripts/movie-ticket-sourced/ v1 demo, payment is commented out and "paymentId" is hardcoded — fine for LLD.
TicketService + PaymentService (stub)
public class TicketService {
String bookTicket(String userId, String showId, List<String> seats, String paymentId);
Ticket findById(String id);
}
public class PaymentService {
String initiatePayment(String userId, String showId, List<String> seats)
throws PaymentException;
void refund(String paymentId);
}
TicketService generates a UUID and saves to TicketRepo. PaymentService is stubbed — “Real gateway out of scope; I return paymentId or throw PaymentException.”
Exception types (mention on board)
| Exception | When |
|---|---|
ReserveException |
Seat not AVAILABLE at reserve time |
PaymentException |
Charge failed |
BookingException |
Could not confirm after payment |
TicketException |
Ticket row failed after seats BOOKED |
These drive compensating actions in BookingService (next implementation chapters).
Client entry points: search → MovieService.searchMovieForCity; seats → ShowService.getAvailableSeats; book/cancel → BookingService. Method names are your API in LLD — no controller layer required.