๐Ÿบ BrewQuest AI - Backend API

Rails 7.1 API backend for the BrewQuest AI beer discovery platform, providing RESTful endpoints for AI-powered recommendations, chat, ratings, and community features.

๐ŸŽฏ Overview

The BrewQuest AI backend is a robust Rails API that powers the beer discovery platform. It handles user authentication, beer data management, AI-powered recommendations, real-time chat, community forums, and gamification features. The API is designed to support the Next.js frontend while being flexible enough for future mobile applications.

โœจ Features

๐Ÿง  AI Integration

  • BrewMatch AI: Personalized beer recommendation engine
  • BrewChat AI: Intelligent chatbot with beer knowledge
  • Flavor Analysis: Taste profile generation from user ratings
  • OpenAI Integration: Ready for production AI features (mock implementation for demo)

๐Ÿ—„๏ธ Data Management

  • Beer Database: 15+ craft beers with detailed profiles
  • User Ratings: Rating system with notes and timestamps
  • Recommendations: AI-generated beer suggestions with scoring
  • Chat History: Conversation storage with encrypted messages
  • Forum System: Community discussions with categories

๐Ÿ‡ป๐Ÿ‡ณ Vietnamese Content

  • Local craft breweries (Pasteur Street, Heart of Darkness, Furbrew)
  • Vietnamese beer styles and cultural context
  • Food pairing suggestions for Vietnamese cuisine
  • Localized responses in both Vietnamese and English

๐ŸŽฎ Gamification

  • Points system for user activities
  • Achievement badges based on behavior
  • Progress tracking and statistics
  • Leaderboard capabilities

๐Ÿ” Security & Performance

  • JWT-based authentication (Devise + JWT)
  • CORS configured for frontend integration
  • Redis for caching and background jobs
  • PostgreSQL for robust data storage
  • Rate limiting and input validation

๐Ÿ›  Tech Stack

  • Framework: Ruby on Rails 7.1 (API-only mode)
  • Ruby Version: 3.3.1
  • Database: PostgreSQL 13+
  • Cache/Queue: Redis 6+
  • Authentication: Devise + JWT
  • Background Jobs: Sidekiq
  • AI Integration: OpenAI API (ruby-openai gem)
  • File Storage: AWS S3 (with Active Storage)
  • HTTP Client: HTTParty for external APIs
  • Testing: RSpec + FactoryBot

๐Ÿ“‹ Prerequisites

  • Ruby 3.3.1
  • PostgreSQL 13+
  • Redis 6+
  • Bundler
  • (Optional) OpenAI API key for production AI features

๐Ÿš€ Quick Start

1. Installation

# Install dependencies
bundle install

2. Environment Configuration

Create a .env file in the root directory:

# Database
DATABASE_URL=postgresql://localhost/brewquest_development

# Rails
RAILS_ENV=development
SECRET_KEY_BASE=your_secret_key_here

# Redis
REDIS_URL=redis://localhost:6379/0

# Frontend CORS
FRONTEND_URL=http://localhost:3000

# AI Integration (Optional - for production)
# OPENAI_API_KEY=your_openai_api_key_here

# AWS S3 (Optional - for file uploads)
# AWS_ACCESS_KEY_ID=your_aws_access_key
# AWS_SECRET_ACCESS_KEY=your_aws_secret_key
# AWS_REGION=us-east-1
# AWS_BUCKET=brewquest-ai

Copy the example environment file:

cp .env.example .env

3. Database Setup

# Create database
rails db:create

# Run migrations
rails db:migrate

# Seed with sample data (15 beers, test user, ratings, etc.)
rails db:seed

The seed file creates:

  • Test user: test@brewquest.ai / password123
  • 15 craft beers (Vietnamese and international)
  • 7 sample ratings
  • 15 AI recommendations
  • 2 chat messages
  • Sample forum posts

4. Start the Server

# Start Rails server
rails server -p 3001

# Or with Puma directly
bundle exec puma -p 3001

# Start Sidekiq (in another terminal)
bundle exec sidekiq

The API will be available at http://localhost:3001

๐Ÿ“ Project Structure

backend/
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ controllers/
โ”‚   โ”‚   โ””โ”€โ”€ api/
โ”‚   โ”‚       โ””โ”€โ”€ v1/              # API v1 endpoints
โ”‚   โ”‚           โ”œโ”€โ”€ beers_controller.rb
โ”‚   โ”‚           โ”œโ”€โ”€ ratings_controller.rb
โ”‚   โ”‚           โ”œโ”€โ”€ recommendations_controller.rb
โ”‚   โ”‚           โ”œโ”€โ”€ chat_messages_controller.rb
โ”‚   โ”‚           โ”œโ”€โ”€ forum_posts_controller.rb
โ”‚   โ”‚           โ”œโ”€โ”€ dashboard_controller.rb
โ”‚   โ”‚           โ””โ”€โ”€ notifications_controller.rb
โ”‚   โ”œโ”€โ”€ models/                  # ActiveRecord models
โ”‚   โ”‚   โ”œโ”€โ”€ user.rb
โ”‚   โ”‚   โ”œโ”€โ”€ beer.rb
โ”‚   โ”‚   โ”œโ”€โ”€ rating.rb
โ”‚   โ”‚   โ”œโ”€โ”€ recommendation.rb
โ”‚   โ”‚   โ”œโ”€โ”€ chat_message.rb
โ”‚   โ”‚   โ””โ”€โ”€ forum_post.rb
โ”‚   โ”œโ”€โ”€ services/                # Business logic
โ”‚   โ”‚   โ”œโ”€โ”€ ai/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ recommendation_service.rb
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ chat_service.rb
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ flavor_analyzer.rb
โ”‚   โ”‚   โ””โ”€โ”€ gamification/
โ”‚   โ”‚       โ””โ”€โ”€ points_service.rb
โ”‚   โ””โ”€โ”€ serializers/             # JSON serializers
โ”‚       โ”œโ”€โ”€ beer_serializer.rb
โ”‚       โ”œโ”€โ”€ rating_serializer.rb
โ”‚       โ””โ”€โ”€ ...
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ database.yml             # Database configuration
โ”‚   โ”œโ”€โ”€ routes.rb                # API routes
โ”‚   โ”œโ”€โ”€ initializers/
โ”‚   โ”‚   โ”œโ”€โ”€ cors.rb             # CORS configuration
โ”‚   โ”‚   โ””โ”€โ”€ redis.rb            # Redis configuration
โ”‚   โ””โ”€โ”€ environments/
โ”œโ”€โ”€ db/
โ”‚   โ”œโ”€โ”€ migrate/                # Database migrations
โ”‚   โ”œโ”€โ”€ seeds.rb               # Seed data
โ”‚   โ””โ”€โ”€ schema.rb              # Database schema
โ”œโ”€โ”€ spec/                       # RSpec tests
โ”‚   โ”œโ”€โ”€ models/
โ”‚   โ”œโ”€โ”€ controllers/
โ”‚   โ””โ”€โ”€ services/
โ”œโ”€โ”€ Gemfile                     # Ruby dependencies
โ””โ”€โ”€ .env                       # Environment variables

๐Ÿ”Œ API Endpoints

Base URL

http://localhost:3001/api/v1

Authentication

Currently disabled for demo purposes. To enable JWT authentication, uncomment the authentication code in controllers.

Endpoints Overview

Dashboard

GET /dashboard

Returns user statistics, recent activities, and achievement progress.

Response:

{
  "data": {
    "stats": {
      "total_ratings": 7,
      "total_recommendations": 15,
      "total_chat_queries": 2,
      "points": 595
    },
    "recent_activities": [...],
    "achievements": [...]
  }
}

Beers

GET /beers                    # List all beers
GET /beers/:id                # Get beer details
GET /beers/search             # Search beers

Query Parameters:

  • style: Filter by beer style (e.g., IPA, Stout)
  • country: Filter by country
  • brewery: Filter by brewery name

Response:

{
  "data": {
    "beers": [
      {
        "id": 1,
        "name": "Pasteur Street Jasmine IPA",
        "style": "IPA",
        "abv": 6.5,
        "brewery": "Pasteur Street Brewing",
        "country": "Vietnam",
        "description": "...",
        "flavor_notes": ["floral", "hoppy", "jasmine"],
        "average_rating": 4.5
      }
    ]
  }
}

Ratings

GET /ratings                  # List user's ratings
POST /ratings                 # Create a rating
GET /ratings/:id              # Get rating details
PUT /ratings/:id              # Update rating
DELETE /ratings/:id           # Delete rating

Create Rating:

POST /ratings
{
  "beer_id": 1,
  "rating": {
    "rating": 5,
    "notes": "Excellent IPA with jasmine notes!"
  }
}

Awards 5 points to the user.

Recommendations

GET /recommendations          # Get user's recommendations
POST /recommendations         # Generate new recommendations

Generate Recommendations:

POST /recommendations
{}

Generates 5 new personalized recommendations based on user's taste profile. Awards 25 points.

Response:

{
  "data": {
    "recommendations": [
      {
        "id": 1,
        "beer": {...},
        "match_score": 95,
        "reason": "Based on your love for hoppy beers",
        "created_at": "2025-01-15T10:00:00Z"
      }
    ]
  }
}

Chat (BrewChat AI)

GET /chat_messages            # Get chat history
POST /chat_messages           # Send a message

Send Message:

POST /chat_messages
{
  "message": "What's the best Vietnamese IPA?"
}

Awards 10 points per query.

Response:

{
  "data": {
    "message": {
      "id": 1,
      "content": "What's the best Vietnamese IPA?",
      "response": "Based on your taste profile, I recommend...",
      "created_at": "2025-01-15T10:00:00Z"
    }
  }
}

Forum

GET /forum_posts              # List forum posts
GET /forum_posts/:id          # Get post with replies
POST /forum_posts             # Create a post
PUT /forum_posts/:id          # Update post
DELETE /forum_posts/:id       # Delete post
POST /forum_posts/:id/like    # Like a post
POST /forum_posts/:id/reply   # Reply to post

Query Parameters:

  • category: Filter by category
  • search: Search in post content

Create Post:

POST /forum_posts
{
  "forum_post": {
    "title": "Best Vietnamese IPAs?",
    "content": "Looking for recommendations...",
    "category": "vietnamese_craft_beers"
  }
}

Awards 10 points per post.

Notifications

GET /notifications            # Get user notifications
GET /notifications/preferences # Get notification settings
PUT /notifications/preferences # Update preferences
POST /notifications/:id/read  # Mark as read

๐Ÿ—„๏ธ Database Schema

Key Models

Users

  • Authentication credentials
  • Taste preferences
  • Points and achievements
  • Activity tracking

Beers

  • Name, style, ABV, brewery
  • Country, description
  • Flavor notes
  • Average rating

Ratings

  • User reference
  • Beer reference
  • Rating (1-5 stars)
  • Notes
  • Timestamps

Recommendations

  • User reference
  • Beer reference
  • Match score (0-100)
  • Reason for recommendation
  • Status (viewed/dismissed)

ChatMessages

  • User reference
  • Message content
  • AI response
  • Encrypted storage

ForumPosts

  • User reference
  • Title, content, category
  • Like count
  • Parent post (for replies)

Sample Schema

create_table "beers" do |t|
  t.string "name"
  t.string "style"
  t.decimal "abv"
  t.string "brewery"
  t.string "country"
  t.text "description"
  t.string "flavor_notes", array: true, default: []
  t.timestamps
end

create_table "ratings" do |t|
  t.references "user", foreign_key: true
  t.references "beer", foreign_key: true
  t.integer "rating"
  t.text "notes"
  t.timestamps
end

create_table "recommendations" do |t|
  t.references "user", foreign_key: true
  t.references "beer", foreign_key: true
  t.integer "match_score"
  t.text "reason"
  t.string "status", default: "pending"
  t.timestamps
end

๐Ÿค– AI Implementation

Current: Mock Implementation

The app currently uses smart pattern matching and mock AI responses:

# Mock recommendation logic
def generate_mock_recommendations
  beers = Beer.where.not(id: user.rated_beer_ids)
    .order("RANDOM()")
    .limit(5)

  beers.map do |beer|
    Recommendation.create!(
      user: user,
      beer: beer,
      match_score: rand(75..100),
      reason: generate_reason(beer)
    )
  end
end

Production: OpenAI Integration

To enable real AI features:

  1. Add API Key to .env:

    OPENAI_API_KEY=sk-your-key-here
    
  2. Uncomment AI Code in controllers:

# app/controllers/api/v1/recommendations_controller.rb
def create
  recommendations = AI::RecommendationService.new(current_user).generate
  # Instead of mock data
end

# app/controllers/api/v1/chat_messages_controller.rb
def create
  response = AI::ChatService.new(current_user).respond(params[:message])
  # Instead of pattern matching
end
  1. AI Services (already implemented):
  2. AI::RecommendationService - GPT-4 powered recommendations
  3. AI::ChatService - Conversational AI with beer expertise
  4. AI::FlavorAnalyzer - Taste profile analysis

๐ŸŽฎ Gamification System

Points Calculation

module Gamification
  class PointsService
    POINTS = {
      rating: 5,
      chat_query: 10,
      recommendation: 25,
      forum_post: 10,
      forum_reply: 5
    }
  end
end

Achievement Badges

Automatically awarded based on user activity:

  • Beer Novice: First rating
  • Beer Explorer: 5 ratings
  • Beer Connoisseur: 20 ratings
  • IPA Enthusiast: 10 IPA ratings
  • Community Contributor: 5 forum posts
  • Chat Master: 20 chat queries

๐Ÿงช Testing

# Run all tests
bundle exec rspec

# Run specific test file
bundle exec rspec spec/models/beer_spec.rb

# Run with coverage
COVERAGE=true bundle exec rspec

Test Structure

spec/
โ”œโ”€โ”€ models/              # Model unit tests
โ”œโ”€โ”€ controllers/         # API endpoint tests
โ”œโ”€โ”€ services/           # Service object tests
โ””โ”€โ”€ factories/          # Test data factories

๐Ÿš€ Deployment

Railway (Recommended)

  1. Install Railway CLI:

    npm install -g @railway/cli
    
  2. Login and Initialize:

    railway login
    railway init
    
  3. Add Services:

    railway add postgresql
    railway add redis
    
  4. Deploy:

    railway up
    
  5. Set Environment Variables in Railway dashboard:

    RAILS_ENV=production
    SECRET_KEY_BASE=$(rails secret)
    FRONTEND_URL=https://your-frontend.vercel.app
    OPENAI_API_KEY=your_key_here
    
  6. Run Migrations:

    railway run rails db:migrate db:seed
    

Heroku

# Create app
heroku create brewquest-api

# Add addons
heroku addons:create heroku-postgresql:mini
heroku addons:create heroku-redis:mini

# Deploy
git push heroku main

# Run migrations
heroku run rails db:migrate db:seed

# Set environment variables
heroku config:set SECRET_KEY_BASE=$(rails secret)
heroku config:set FRONTEND_URL=https://your-frontend.vercel.app

Docker

# Build image
docker build -t brewquest-api .

# Run container
docker run -p 3001:3001 \
  -e DATABASE_URL=postgresql://... \
  -e REDIS_URL=redis://... \
  brewquest-api

๐ŸŒ Environment Variables

Variable Description Required
DATABASE_URL PostgreSQL connection string Yes
REDIS_URL Redis connection string Yes
SECRET_KEY_BASE Rails secret key Yes
RAILS_ENV Environment (development/production) Yes
FRONTEND_URL Frontend URL for CORS Yes
OPENAI_API_KEY OpenAI API key No (for production AI)
AWS_ACCESS_KEY_ID AWS credentials No (for file uploads)
AWS_SECRET_ACCESS_KEY AWS credentials No (for file uploads)
AWS_REGION AWS region No (for file uploads)
AWS_BUCKET S3 bucket name No (for file uploads)

๐Ÿ“Š Performance Optimization

Caching Strategy

# Cache beer list for 1 hour
Rails.cache.fetch("beers/list", expires_in: 1.hour) do
  Beer.all.to_a
end

# Cache user recommendations
Rails.cache.fetch("recommendations/user_#{user.id}", expires_in: 5.minutes) do
  user.recommendations.includes(:beer).to_a
end

Database Indexing

add_index :ratings, [:user_id, :beer_id]
add_index :recommendations, [:user_id, :created_at]
add_index :beers, :style
add_index :forum_posts, :category

Background Jobs

# Process AI recommendations asynchronously
RecommendationGeneratorJob.perform_later(user_id)

# Send notification emails
NotificationMailerJob.perform_later(user_id, notification_type)

๐Ÿ”’ Security

  • CORS: Configured to allow only frontend domain
  • JWT Tokens: Secure authentication (disabled in demo)
  • Input Validation: Strong parameters and model validations
  • SQL Injection: Using ActiveRecord parameterized queries
  • Rate Limiting: Rack::Attack for API throttling
  • Encryption: Database encryption for sensitive data

๐Ÿ“š Additional Resources

๐Ÿค Contributing

  1. Follow Rails best practices
  2. Write tests for new features
  3. Use service objects for complex business logic
  4. Keep controllers thin
  5. Document API changes
  6. Run tests before committing

๐Ÿ“ License

This project is part of BrewQuest AI platform.


Powering the future of beer discovery with AI! ๐Ÿบ๐Ÿค–

Built With

Share this project:

Updates