🎬 Just Built a Production-Ready Movie Recommendation System! 🚀
Author Email: manish_srivastava1@yahoo.com
A full-stack Movie Recommendation & Booking Platform that combines AI/ML algorithms with modern microservices architecture!
This document describes the request flow between the Angular frontend and backend microservices with API Gateway and Load Balancing support.
flowchart TD
subgraph Frontend ["FRONTEND - Angular"]
W["Welcome<br>Component"]
ML["Movie List<br>Component"]
B["Booking<br>Component"]
HttpClient["HttpClient<br>Angular"]
W --> HttpClient
ML --> HttpClient
B --> HttpClient
end
HttpClient -- "HTTP Requests - All through Gateway" --> APIGW["API Gateway<br>:8081"]
APIGW -.->|"Gateway Routes<br/>/movies/**<br/>/api/recommendations/**<br/>/api/ticket-booking/**"| LB["Load Balancer<br/>Round-Robin"]
APIGW -- Direct --> MovieService1["Movie Service<br/>Direct"]
LB -- Route --> MovieService["Movie Service<br/>:8083"]
LB -- Route --> RecommendationService["Recommendation Service<br/>:8083"]
LB -- Route --> TicketBookingService["Ticket Booking Service<br/>:8085"]
Component: welcome.component.ts
Frontend (Welcome Component)
↓ GET http://localhost:8081/movies
Movie Service (:8081)
↓ Query Database
MySQL Database
↓ Return Movies
Movie Service
↓ JSON Response
Frontend (Displays Featured Movie)
Frontend (Welcome Component)
↓ GET http://localhost:8081/api/recommendations/user/{userId}/hybrid?limit=10
Movie Service (API Gateway) (:8081)
↓ RecommendationGatewayController receives request
↓ LoadBalancer selects instance (currently single instance)
↓ Routes to: GET http://recommendation-service:8083/recommendations/user/{userId}/hybrid?limit=10
Recommendation Service (:8083)
↓ GET http://movie-service:8081/movies (fetch all movies)
↓ GET http://movie-service:8081/ratings/user/{userId} (fetch user ratings)
↓ GET http://movie-service:8081/ratings (fetch all ratings)
Movie Service (:8081)
↓ Query Database
MySQL Database
↓ Return Data
Movie Service
↓ JSON Response
Recommendation Service (Processes with AI algorithms)
↓ JSON Response (Recommendations)
Movie Service (API Gateway) - Forwards response
↓ JSON Response (Recommendations)
Frontend (Displays Recommendations)
Key Points:
- Frontend only communicates with Movie Service (API Gateway pattern)
- Movie Service routes
/api/recommendations/**requests to Recommendation Service - LoadBalancer selects available instance (ready for horizontal scaling)
- Recommendation Service acts as a proxy/aggregator that calls Movie Service internally
- Uses WebClient (Spring WebFlux) for reactive HTTP calls
- Implements Hybrid Algorithm (Collaborative + Content-Based Filtering)
Component: movie-list.component.ts
Frontend (Movie List Component)
↓ GET http://localhost:8081/movies
Movie Service (:8081)
↓ Query Database
MySQL Database
↓ Return Movies (sorted by movieId DESC, top 30)
Movie Service
↓ JSON Response
Frontend (Displays Movie Grid)
Frontend (Movie List Component)
↓ GET http://localhost:8081/movies/search?query={searchTerm}
Movie Service (:8081)
↓ Query Database (LIKE search on title, genre, director)
MySQL Database
↓ Return Matching Movies
Movie Service
↓ JSON Response
Frontend (Displays Search Results)
Frontend (Movie List Component)
↓ GET http://localhost:8081/movies/genre/{genre}
Movie Service (:8081)
↓ Query Database (WHERE genre = {genre})
MySQL Database
↓ Return Filtered Movies
Movie Service
↓ JSON Response
Frontend (Displays Filtered Results)
Frontend (Movie List Component)
↓ POST http://localhost:8081/ratings
│ Body: { userId, movieId, rating }
│ Headers: Authorization: Bearer {token}
Movie Service (:8081)
↓ Insert/Update Rating in Database
MySQL Database
↓ Save Rating
Movie Service
↓ JSON Response (Success)
Frontend
↓ Dispatch Custom Event: 'ratingSubmitted'
Welcome Component (Listens for event)
↓ Reload Recommendations
Component: booking.component.ts
Service: booking.service.ts
Frontend (Booking Component)
↓ GET http://localhost:8081/movies/{movieId}
Movie Service (:8081)
↓ Query Database
MySQL Database
↓ Return Movie Details
Movie Service
↓ JSON Response
Frontend (Displays Movie Info)
Frontend (Booking Component)
↓ GET http://localhost:8081/theaters
↓ GET http://localhost:8081/theater-movies?movieId={movieId}
Movie Service (:8081)
↓ Query Database
MySQL Database
↓ Return Theaters & Showtimes
Movie Service
↓ JSON Response
Frontend (Displays Theater Selection)
Frontend (Booking Component)
↓ POST http://localhost:8081/bookings
│ Body: {
│ userId, theaterMovieId, numberOfSeats,
│ pricePerTicket, discountCode
│ }
│ Headers: Authorization: Bearer {token}
Movie Service (:8081)
↓ Validate Request
↓ Insert Booking in Database
MySQL Database
↓ Save Booking
Movie Service
↓ JSON Response (Booking Details)
Frontend (Displays Confirmation)
Frontend (Booking Component)
↓ GET/POST http://localhost:8081/api/ticket-booking/...
│ Example: GET /api/ticket-booking/seats/{theaterMovieId}
Movie Service (API Gateway) (:8081)
↓ TicketBookingGatewayController receives request
↓ LoadBalancer selects instance (currently single instance)
↓ Routes to: GET http://ticket-booking-service:8085/seats/{theaterMovieId}
Ticket Booking Service (:8085)
↓ Process Request (seat selection, ticket generation, etc.)
↓ JSON Response
Movie Service (API Gateway) - Forwards response
↓ JSON Response
Frontend (Displays Ticket Information)
Component: sign-in-modal.component.ts
Frontend (Sign In Component)
↓ POST http://localhost:8081/auth/login
│ Body: { email, password }
Movie Service (:8081)
↓ Validate Credentials
↓ Query Database
MySQL Database
↓ Return User Data
Movie Service
↓ Generate JWT Token
↓ JSON Response: { token, user }
Frontend
↓ Store in localStorage:
│ - authToken
│ - user (JSON)
↓ Update UI (Show Logged-in State)
Frontend (Registration Component)
↓ POST http://localhost:8081/user
│ Body: { userID, name, email, password, ... }
Movie Service (:8081)
↓ Validate Data
↓ Insert User in Database
MySQL Database
↓ Save User
Movie Service
↓ JSON Response (User Created)
Frontend (Show Success Message)
Gateway Routing Pattern with Load Balancing:
Frontend (:4200)
↓ GET http://localhost:8081/api/recommendations/user/4/hybrid?limit=10
Movie Service Gateway (:8081)
↓ RecommendationGatewayController receives request
↓ LoadBalancer selects instance from available instances
↓ Routes request to Recommendation Service
↓ GET http://recommendation-service:8083/recommendations/user/4/hybrid?limit=10
Recommendation Service (:8083)
↓ Processes request and returns recommendations
Movie Service Gateway (:8081)
↓ Forwards response to Frontend
Frontend (:4200)
↓ Receives recommendations
Gateway Routing Pattern with Load Balancing:
Frontend (:4200)
↓ GET http://localhost:8081/api/ticket-booking/seats/{theaterMovieId}
Movie Service Gateway (:8081)
↓ TicketBookingGatewayController receives request
↓ LoadBalancer selects instance from available instances
↓ Routes request to Ticket Booking Service
↓ GET http://ticket-booking-service:8085/seats/{theaterMovieId}
Ticket Booking Service (:8085)
↓ Processes request and returns seat information
Movie Service Gateway (:8081)
↓ Forwards response to Frontend
Frontend (:4200)
↓ Receives seat information
Internal Network Communication (Docker Network):
Recommendation Service (:8083)
↓ GET http://movie-service:8081/movies
↓ GET http://movie-service:8081/ratings/user/{userId}
↓ GET http://movie-service:8081/ratings
Movie Service (:8081)
↓ Process Request
↓ Query Database
MySQL Database
↓ Return Data
Movie Service
↓ Return JSON
Recommendation Service
↓ Process with Algorithms
↓ Return Recommendations
Key Points:
- Frontend never directly calls Recommendation Service or Ticket Booking Service - all requests go through Movie Service Gateway
- Movie Service Gateway routes:
/api/recommendations/**→ Recommendation Service (via LoadBalancer)/api/ticket-booking/**→ Ticket Booking Service (via LoadBalancer)
- LoadBalancer automatically selects available instances (currently single instance, ready for scaling)
- Uses Docker service names (
movie-service,recommendation-service,ticket-booking-service) for internal communication - Gateway pattern abstracts microservices from the client
Movie Service acts as API Gateway for all client requests:
| Frontend Request | Gateway Route | Target Service | Access Pattern | Load Balancing |
|---|---|---|---|---|
/movies/** |
Direct (Movie Service) | Movie Service | Direct | N/A |
/ratings/** |
Direct (Movie Service) | Movie Service | Direct | N/A |
/bookings/** |
Direct (Movie Service) | Movie Service | Direct | N/A |
/theaters/** |
Direct (Movie Service) | Movie Service | Direct | N/A |
/api/recommendations/** |
Routes to Recommendation Service | Recommendation Service (:8083) | Via Gateway | ✅ Enabled |
/api/ticket-booking/** |
Routes to Ticket Booking Service | Ticket Booking Service (:8085) | Via Gateway | ✅ Enabled |
/api/payments/** |
Routes to Payment Service | Payment Service (:8082) | Via Gateway | Ready |
/api/users/** |
Routes to User Service | User Service (:8084) | Via Gateway | Ready |
Current Configuration:
- LoadBalancer: Spring Cloud LoadBalancer (Round-Robin algorithm)
- Service Discovery: Manual configuration via
ServiceInstanceListSupplier - Current Instances: Single instance per service (ready for horizontal scaling)
- Health Checks: Can be added for automatic failover
How It Works:
- Gateway Controller receives request
- LoadBalancer selects instance from configured list
- Request routed to selected instance
- Response forwarded back to client
Scaling:
- To add more instances, update
LoadBalancerConfig.javawith additionalDefaultServiceInstance - LoadBalancer automatically distributes requests across all instances
- No code changes needed in Gateway Controllers
- Single Entry Point: Frontend only needs to know one URL (
http://localhost:8081) - Centralized Authentication: All requests validated at gateway
- Service Abstraction: Internal service structure hidden from clients
- Load Balancing: Distributes traffic across service instances
- Monitoring: Centralized logging and metrics
- Security: Single point for CORS, rate limiting, etc.
- Scalability: Easy horizontal scaling without frontend changes
Movie Service Gateway Controllers:
RecommendationGatewayController- Routes/api/recommendations/**TicketBookingGatewayController- Routes/api/ticket-booking/**- Uses
WebClient(Spring WebFlux) with@LoadBalancedfor reactive HTTP calls - LoadBalancer automatically selects instance from configured list
- Forwards requests to target services on Docker network
- Returns responses transparently to frontend
| Service | Internal Port | External Port | Purpose | Access Pattern | Load Balancing |
|---|---|---|---|---|---|
| Frontend | 80 (nginx) | 4200 | Angular App | Direct | N/A |
| Movie Service | 8081 | 8081 | API Gateway + Main API | Gateway for all services | N/A |
| Payment Service | 8082 | 8082 | Payment Processing | Via Gateway (/api/payments/**) |
Ready |
| Recommendation Service | 8083 | 8083 | AI Recommendations | Via Gateway (/api/recommendations/**) |
✅ Enabled |
| User Service | 8084 | 8084 | User Management | Via Gateway (/api/users/**) |
Ready |
| Ticket Booking Service | 8085 | 8085 | Booking Management | Via Gateway (/api/ticket-booking/**) |
✅ Enabled |
| MySQL | 3306 | 3306 | Database | Internal only | N/A |
| Config Service | 8888 | 8888 | Configuration Server | Internal only | N/A |
Note: External ports for Payment, Recommendation, User, and Ticket Booking services are optional - they can be removed from Docker port mappings since clients access them through the Movie Service Gateway.
Frontend Origin: http://localhost:4200
Backend Services allow requests from:
http://localhost:*http://127.0.0.1:*
Configuration Files:
MovieService/src/main/java/com/spring5/movieservice/common/WebConfig.java(if exists)- Gateway handles CORS for all routed services
- User logs in → Frontend stores
userIdin localStorage - Welcome page loads → Checks
isLoggedInflag - Frontend calls:
GET http://localhost:8081/api/recommendations/user/4/hybrid?limit=10 - Movie Service Gateway receives request at
/api/recommendations/** - LoadBalancer selects instance (currently single instance:
recommendation-service-1) - Movie Service Gateway routes to:
GET http://recommendation-service:8083/recommendations/user/4/hybrid?limit=10 - Recommendation Service:
- Fetches all movies from Movie Service
- Fetches user's ratings from Movie Service
- Fetches all ratings from Movie Service
- Runs Collaborative Filtering algorithm
- Runs Content-Based Filtering algorithm
- Combines results (Hybrid)
- Returns top 10 recommendations
- Movie Service Gateway forwards response to Frontend
- Frontend displays recommendations sorted by score
- User clicks "Rate Movie" → Opens rating modal
- User selects rating (1-5 stars)
- Frontend calls:
POST /ratingswith{ userId, movieId, rating } - Movie Service saves rating to database
- Frontend dispatches
ratingSubmittedevent - Welcome Component listens for event
- Welcome Component reloads recommendations (after 500ms delay)
- Updated recommendations appear in UI
- User clicks "Book Now" → Navigates to
/book?movieId=123 - Booking Component loads:
- Movie details:
GET /movies/123 - Theaters:
GET /theaters - Showtimes:
GET /theater-movies?movieId=123
- Movie details:
- User selects theater, showtime, seats
- Frontend calculates price breakdown (client-side)
- User confirms →
POST /bookingswith booking details - Movie Service creates booking
- Frontend displays confirmation
- User clicks "Book Now" → Navigates to
/book?movieId=123 - Booking Component loads:
- Movie details:
GET http://localhost:8081/movies/123(direct) - Theaters:
GET http://localhost:8081/theaters(direct) - Showtimes:
GET http://localhost:8081/theater-movies?movieId=123(direct)
- Movie details:
- User selects theater, showtime
- Frontend calls:
GET http://localhost:8081/api/ticket-booking/seats/{theaterMovieId}(via gateway) - Movie Service Gateway receives request
- LoadBalancer selects instance (currently single instance:
ticket-booking-service-1) - Ticket Booking Service returns available seats
- User selects seats and confirms booking
- Frontend calls:
POST http://localhost:8081/bookings(direct to Movie Service) - Movie Service creates booking
- Frontend displays confirmation
- HTTP Errors: Displayed in UI with error messages
- Network Errors: "Failed to load movies. Make sure the backend is running."
- CORS Errors: Logged to console, silently fail for recommendations
- 404 Not Found: Returns appropriate error message
- 400 Bad Request: Validation errors returned
- 500 Internal Server Error: Logged, generic error returned
- Service Unavailable: Recommendation Service falls back to popular movies
- LoadBalancer Failover: If instance fails, LoadBalancer can retry on next instance (when multiple instances configured)
- Frontend: Angular 17+ (Standalone Components), HttpClient, RxJS
- Backend: Spring Boot, Spring MVC, Spring WebFlux (WebClient)
- Load Balancing: Spring Cloud LoadBalancer (Round-Robin)
- Database: MySQL 8.0
- Containerization: Docker, Docker Compose
- Networking: Docker Bridge Network (
movie-booking-network)
- Authentication: JWT tokens stored in localStorage
- Authorization: Bearer token sent in
Authorizationheader - CORS: Configured to allow only localhost origins
- SQL Injection: Prevented by using parameterized queries (Spring Data)
- XSS: Angular automatically escapes HTML
- Gateway Security: Single point for security policies
- Pagination: Movies limited to top 30 newest
- Caching: Recommendations cached (can be implemented)
- Lazy Loading: Components loaded on demand
- Reactive Programming: WebFlux for non-blocking I/O
- Database Indexing: On
movieId,userId,genrecolumns - Load Balancing: Distributes load across instances
API Gateway: Add Spring Cloud Gateway for routing✅ Implemented: Movie Service acts as API Gateway- Service Discovery: Implement Eureka or Consul for dynamic service discovery
Load Balancing: Multiple instances of services✅ Implemented: Spring Cloud LoadBalancer configured (single instance ready for scaling)- Caching Layer: Redis for frequently accessed data
- Message Queue: RabbitMQ/Kafka for async processing
- Monitoring: Prometheus + Grafana for metrics
- Health Checks: Add health check-based instance selection
- Circuit Breaker: Implement resilience patterns (Resilience4j)
