A Ruby on Rails API that provides car recommendations based on user preferences and external AI-powered ranking scores. Designed to handle millions of records with optimized database performance.
This API endpoint delivers personalized car recommendations by:
- Matching cars with user's preferred brands and price ranges
- Integrating AI-powered recommendation scores
- Implementing efficient database queries and caching strategies
- Sorting results by match quality, AI rank, and price
- Supporting pagination and filtering options
- Handling service resilience and data staleness
The system is built to:
- Scale efficiently with millions of database records
- Process complex filtering and sorting operations
- Handle external service interruptions gracefully
- Maintain responsive performance under load
The application follows a service-oriented architecture with:
-
Controllers (API/V1)
- Handle HTTP requests
- Basic parameter validation
- Error responses
-
Services
- CarQueryService: Main business logic for filtering and sorting cars
- LabelService: Determines match quality labels
- RecommendationCacheService: Handles external recommendation data
-
Models
- Car: Core vehicle data
- Brand: Brand information
- User: User preferences and settings
-
Clone the repository
-
Build the application:
./car-market build
-
Start the application:
./car-market start
-
Setup the database:
./car-market db:setup
-
Run the test suite:
./car-market rspec
Available commands:
./car-market start # Start the application
./car-market stop # Stop all containers
./car-market clean # Remove all containers and networks
./car-market console # Access Rails console
./car-market rspec # Run tests
./car-market db:migrate # Run database migrations
./car-market logs # View application logs
-
Install dependencies:
bundle install
-
Setup database:
rails db:create db:migrate
-
Run the test suite:
rspec
- Ruby 2.7.2
- Rails 6.1.3
- PostgreSQL (pg ~> 1.1)
- Puma 5.0 (Web Server)
- HTTParty (HTTP Client)
- Bootsnap (Boot Time Optimizer)
- RSpec Rails (~> 6.0)
- Factory Bot Rails (~> 6.2.0)
- Faker (Test Data Generation)
- Shoulda Matchers (~> 5.0.0)
- RSwag (API Documentation)
- rswag-api
- rswag-specs
- rswag-ui
- Byebug (Debugger)
- Annotate (Model/Route Annotation)
- Spring (Development Server)
- Listen (~> 3.3)
- Docker
- PostgreSQL 13 (Container)
- Docker Network for Service Communication
Parameters:
- user_id (required): ID of the user for preferences
- query (optional): Filter by brand name
- price_min (optional): Minimum price filter
- price_max (optional): Maximum price filter
- page (optional): Page number for pagination
Response Format:
[
{
"id": 1,
"brand": {
"id": 1,
"name": "Toyota"
},
"model": "Camry",
"price": 25000,
"rank_score": 0.95,
"label": "perfect_match"
}
]
The application integrates with an external AI recommendation service that provides personalized car suggestions. This service:
- Uses modern AI algorithms to rank cars based on user preferences
- Provides daily-updated recommendations for each user
- Returns rank scores between 0 and 1 (higher scores indicate stronger recommendations)
- Delivers the top 10 most relevant cars per user
- Endpoint:
https://bravado-images-production.s3.amazonaws.com/recomended_cars.json?user_id=<USER_ID>
- Response format:
[
{
"car_id": 179,
"rank_score": 0.945
}
]
The application is designed to handle:
- Service unavailability
- API errors
- Stale data (updated once per day)
- Missing recommendations
To optimize performance and handle service limitations:
- Recommendations are cached daily
- Fallback to database-only sorting when AI service is unavailable
- Efficient merging of AI recommendations with database queries
- Background job updates for recommendation data
The AI recommendations influence the car listing by:
- Contributing to the sorting algorithm (after label matching)
- Providing personalized rank scores in the API response
- Complementing user's explicit preferences (brands and price range)
Example of how recommendations affect results:
{
"id": 179,
"brand": {
"id": 39,
"name": "Volkswagen"
},
"model": "Derby",
"price": 37230,
"rank_score": 0.945, // AI-provided score
"label": "perfect_match" // Based on user preferences
}
-
Containerization
- Docker-based development environment
- Consistent environment across team members
- Easy setup and deployment
- Isolated dependencies
-
Service Objects
- Separates business logic from controllers
- Improves maintainability and testing
- Allows for easy modification of sorting/filtering logic
-
Database Optimization
- Uses SQL for efficient sorting
- Implements proper indexing
- Minimizes memory usage
-
Code Organization
- Clear separation of concerns
- Modular design
- Easy to extend and modify
This application was designed to simulate a system handling millions of database records, with a focus on database performance and scalability. Key optimizations include:
- Efficient indexing on frequently queried columns
- Optimized join operations between cars and brands
- Proper use of foreign keys for referential integrity
- Strategic use of database constraints
- Uses SQL-level filtering instead of Ruby-level filtering
- Implements database-side pagination
- Minimizes memory usage through lazy loading
- Leverages PostgreSQL's built-in full-text search capabilities
- External recommendation scores are cached
- Brand-related queries are optimized
- Proper use of connection pooling
- Query result caching where appropriate
The application includes performance specs that simulate:
- Large datasets (millions of car records)
- Multiple concurrent users
- Complex filtering and sorting operations
- Heavy read operations with occasional writes
- SQL query logging for development
- Database performance metrics tracking
- Query execution plan analysis
- Memory usage monitoring
These optimizations ensure the application remains responsive and efficient even with:
- Large number of records
- Complex filtering operations
- Multiple concurrent users
- Frequent API requests
- Web Application (Ruby 2.7.2)
- PostgreSQL 13
- Custom networking for service communication
- Volume mapping for persistent data
- Environment-specific configurations
- Build containers using
./car-market build
- Start services with
./car-market start
- Run tests via
./car-market rspec
- Access logs through
./car-market logs
- Clean up using
./car-market clean
After setting up the application and running the seeds (./car-market db:setup
), you can interact with the API using the following examples:
Get car recommendations for the seeded user:
curl "http://localhost:3000/api/v1/cars?user_id=1"
Search for Volkswagen cars:
curl "http://localhost:3000/api/v1/cars?user_id=1&query=volkswagen"
Find cars between 30,000 and 45,000:
curl "http://localhost:3000/api/v1/cars?user_id=1&price_min=30000&price_max=45000"
View the second page of results:
curl "http://localhost:3000/api/v1/cars?user_id=1&page=2"
Search for Alfa Romeo cars under 40,000:
curl "http://localhost:3000/api/v1/cars?user_id=1&query=alfa&price_max=40000"
The API returns cars with the following information:
{
"id": 1,
"brand": {
"id": 1,
"name": "Alfa Romeo"
},
"model": "Giulia",
"price": 38000,
"rank_score": 0.95,
"label": "perfect_match"
}
Labels:
perfect_match
: Car matches both preferred brand and price rangegood_match
: Car matches preferred brand onlynull
: No specific match
Note: The seeded user (id: 1) has:
- Preferred brands: Alfa Romeo, Volkswagen
- Preferred price range: 35,000-40,000
- Email: [email protected]
Rank scores are cached recommendations from an external service and range from 0 to 1, where higher scores indicate stronger recommendations.