____ _ ____ _
/ ___|_ __ _ _| |__ / ___|| |_ __ _ _ __ ___
| | _| '__| | | | '_ \ \___ \| __/ _` | '__/ __|
| |_| | | | |_| | |_) | ___) | || (_| | | \__ \
\____|_| \__,_|_.__/ |____/ \__\__,_|_| |___/
A restaurant reviews aggregator that brings together ratings, reviews, photos, and videos from multiple sources into a single, fast, local database. Access your aggregated data through a modern web UI, REST API, or command-line interface.
Stop switching between Yelp, Google Maps, TripAdvisor, Instagram, and TikTok to research restaurants. grub-stars indexes your area once, then lets you search locally without repeated API calls.
Key Features:
- πͺ Multi-source aggregation - Combine data from Yelp, Google Maps, TripAdvisor, Instagram, and TikTok
- π Fast local search - Index once, search instantly from SQLite
- π BYOK (Bring Your Own Key) - Use your own API keys
- π Geographic indexing - Index specific areas as needed
- π Lightweight storage - Store URLs to media, not the files themselves
- π Smart deduplication - Automatically merges the same restaurant from different sources
Try it now: https://grub-stars-test.fly.dev
The test environment runs with a mock server that simulates responses from Yelp, Google Maps, and TripAdvisor. You can explore the full functionality without needing any API keys.
Demo data available for:
- Location: "Barrie, Ontario"
- Various restaurant categories (bakeries, cafes, etc.)
Features to try:
- π Search for restaurants by name or category
- π Index the demo location to populate the database
- π·οΈ Browse restaurants by categories
- π± View detailed restaurant information with photos and reviews
The demo resets periodically, so feel free to experiment!
git clone https://github.com/aleccool213/grub-stars.git
cd grub-stars
gem install bundler -v 2.5.23
bundle _2.5.23_ install-
Copy the environment template:
cp .env.example .env
-
Add your API keys to
.env:YELP_API_KEY=your_yelp_key_here GOOGLE_API_KEY=your_google_key_here TRIPADVISOR_API_KEY=your_tripadvisor_key_hereConfigure at least one adapter to get started.
Start the web server to access the web UI and REST API:
bundle _2.5.23_ exec rackupThen open your browser to http://localhost:9292
Web UI Features:
- π Search restaurants by name or category
- π Index new geographic areas
- π·οΈ Browse by categories
- π± Responsive design for desktop and mobile
If you prefer the command-line interface:
ruby -I lib bin/grst index --location "barrie, ontario" # Index all restaurants
ruby -I lib bin/grst index --location "barrie, ontario" --category bakery # Index only bakeries
ruby -I lib bin/grst search --category bakery # Search locally
ruby -I lib bin/grst info --name "restaurant name" # Get detailed infogrub-stars uses a clean layered architecture that separates concerns and makes the codebase testable and extensible:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Presentation Layer β
β βββββββββββββββββββββββ ββββββββββββββββββββββββ β
β β Web UI β β REST API β β
β β (Browser) β β (lib/api/server.rb)β β
β βββββββββββββββββββββββ ββββββββββββββββββββββββ β
β β
β CLI (optional) β
β (lib/cli.rb) β
ββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β Services (lib/services/) β
β Business operations & use cases β
ββββββββ¬βββββββββββββββββββββββββββββββ¬βββββββββββββββββ
β β
ββββββββΌβββββββββββββββ βββββββββββΌββββββββββββββββ
β Domain β β Infrastructure β
β Pure logic β β Repositories β
β Models β β Database (SQLite) β
β Matcher β β External API Adapters β
βββββββββββββββββββββββ βββββββββββββββββββββββββββ
Layers:
- Presentation - Web UI (vanilla JavaScript), REST API (Sinatra), and CLI (Thor) - all thin wrappers that delegate to services
- Services (
lib/services/) - Use cases: indexing, searching, getting details, listing categories - Domain (
lib/domain/) - Pure business logic and models (Restaurant, Rating, Review, etc.) - Infrastructure (
lib/infrastructure/) - Repositories, database, and external API adapters
See ARCHITECTURE.md for detailed design documentation.
- β Yelp - Ratings, reviews, photos
- β Google Maps - Ratings, reviews (up to 5), photos
- β TripAdvisor - Ratings, reviews, photos
- π§ Instagram - Photos and videos only
- π§ TikTok - Videos only
Ruby tests (CLI, API, domain logic):
ruby -I lib $(bundle _2.5.23_ show rake)/exe/rake test # Run all tests
ruby -I lib $(bundle _2.5.23_ show rake)/exe/rake test:integration # Run integration tests only
ruby -I lib $(bundle _2.5.23_ show rake)/exe/rake test:unit # Run unit tests onlyJavaScript tests (Web UI):
npm test # Run all JS tests
npm run test:install # Install Playwright (first time only)lib/
βββ domain/ # Pure business logic (zero dependencies)
βββ infrastructure/ # Database, repositories, adapters
βββ services/ # Application use cases
βββ api/ # REST API (Sinatra)
βββ cli.rb # CLI interface (Thor)
web/ # Web UI (vanilla JavaScript + HTML)
βββ index.html # Search page
βββ details.html # Restaurant details
βββ index-location.html # Indexing page
βββ js/ # JavaScript components and tests
βββ css/ # Styles
tests/
βββ unit/ # Fast tests with mocks
βββ integration/ # Full-stack tests
Backend:
- Ruby - Core language
- Sinatra - REST API framework
- Thor - CLI framework
- Sequel - Database ORM
- SQLite3 - Local database
- Faraday - HTTP client for adapters
- dotenv - Environment management
Frontend:
- Vanilla JavaScript - No framework dependencies
- HTML5 & CSS3 - Modern web standards
- Playwright - Headless testing
- Yelp: https://www.yelp.com/developers/v3/manage_app
- Google Places: https://console.cloud.google.com/apis/credentials
- TripAdvisor: https://www.tripadvisor.com/developers
- ARCHITECTURE.md - Detailed architecture and design patterns
- REFACTORING_SUMMARY.md - Recent refactoring to layered architecture
- CLAUDE.md - Project guidance for Claude Code
- docs/testing.md - Testing guide
- docs/user-guide.md - Detailed user guide
- docs/cli.md - CLI architecture details
When you index a location (via Web UI or CLI), grub-stars:
- Queries all configured adapters (Yelp, Google Maps, etc.) for restaurants in the area
- Uses a matcher with confidence scoring to identify duplicate restaurants across sources
- Stores everything in a local SQLite database
You can optionally filter by category during indexing to focus on specific restaurant types.
The matcher prevents duplicates by scoring similarity:
- Name similarity: ~30 points
- Address match: points based on similarity
- GPS proximity: points based on distance
- Phone number match: additional points
Restaurants scoring >50 are considered the same and their data is merged.
All searches happen locally against SQLite through the Web UI, REST API, or CLI, so they're instant. No API calls required after indexing.
The REST API provides programmatic access to all functionality:
# Start the server
bundle _2.5.23_ exec rackup -p 3000| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check |
/categories |
GET | List all categories |
/locations |
GET | List all indexed locations |
/restaurants/search?name=X |
GET | Search by name |
/restaurants/search?category=X |
GET | Search by category |
/restaurants/:id |
GET | Get restaurant details |
/index |
POST | Index restaurants (body: {"location": "city", "category": "optional"}) |
{
"data": <result>,
"meta": { "timestamp": "...", "count": 10 }
}For detailed API examples and integration guides, see docs/api.md.
- Local-first: Fast queries without repeated API calls
- Selective indexing: Index only areas you care about, optionally filtered by category
- Flexible refresh: Re-index anytime to get fresh data
- Bring Your Own Key: You control your API usage and costs
- Lightweight: Store media URLs, not files
This is a personal project, but contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Submit a pull request
MIT License - see LICENSE file for details
- Add Instagram adapter (photos/videos only)
- Add TikTok adapter (videos only)
- Add caching layer for API responses
- Export functionality (CSV, JSON)
- Restaurant comparison features
- Mobile app for native iOS/Android access
Built with β€οΈ using Ruby and clean architecture principles