Deploying BookBounty
BookBounty is a dynamic, role-based web platform designed to foster a vibrant literary community. Built with PHP, JavaScript, HTML, CSS, and MySQL, BookBounty enables authors to upload and manage their books, users to read and interact with content, and administrators to oversee the entire platform. Whether you’re creating a digital library for educational institutions, building a self-publishing platform, or establishing a community reading hub, BookBounty provides the infrastructure and flexibility needed to create an engaging book-sharing ecosystem.
Why BookBounty?
BookBounty stands out as the premier choice for literary platforms with exceptional features:
- Role-Based Access Control: Separate dashboards and permissions for authors, users, and administrators
- Book Upload & Management: Authors can easily upload, edit, delete, and organize their books
- Seamless Reading Experience: Users can browse, search, and read books online with a responsive interface
- Admin Controls: Comprehensive administrative dashboard for managing users, books, and platform content
- User Authentication: Secure login and registration system for all user types
- Modular Backend: Built with PHP and MySQL for robust authentication and data persistence
- Interactive Frontend: Responsive design with JavaScript for smooth user interactions
- Real-Time Updates: Asynchronous operations for seamless content management
- Book Metadata Management: Store and display book details including title, author, description, cover images
- User Reviews & Ratings: Enable community engagement through book reviews and ratings
- Search Functionality: Full-text search for discovering books by title, author, or genre
- Responsive Design: Mobile-friendly interface accessible on all devices
- Database Persistence: Reliable SQL database for storing user and book data
- Scalable Architecture: Easily extensible for additional features and functionality
- Open Source: Customizable codebase under BSD-3-Clause license
- Community-Driven: Active development and community contributions
BookBounty is ideal for educational institutions building digital libraries, self-publishing platforms for independent authors, community libraries and reading groups, academic organizations managing course materials, content creators building book communities, and organizations promoting literacy and reading. With persistent storage on Klutch.sh, your literary platform has reliable data persistence and accessibility.
Prerequisites
Before deploying BookBounty, ensure you have:
- A Klutch.sh account
- A GitHub repository with your BookBounty deployment configuration
- Basic familiarity with Docker and Git
- Sufficient storage for book files and user data (typically 10-100GB depending on library size)
- Database knowledge for initial setup and maintenance
- Understanding of PHP and web server basics
- A custom domain for your platform (recommended for production)
Important Considerations
Deploying BookBounty
Create a New Project
Log in to your Klutch.sh dashboard and create a new project for your BookBounty platform.
Prepare Your Repository
Create a GitHub repository with the following structure for your BookBounty deployment:
bookbounty-deploy/├─ Dockerfile├─ .env.example├─ docker-entrypoint.sh├─ bookbounty.sql├─ .gitignore└─ README.mdHere’s a Dockerfile for BookBounty:
FROM php:8.2-apache# Install system dependenciesRUN apt-get update && apt-get install -y \git \curl \wget \mysql-client \libpng-dev \libjpeg62-turbo-dev \libfreetype6-dev \libxml2-dev \libzip-dev \zip \unzip \vim \nano \&& rm -rf /var/lib/apt/lists/*# Install PHP extensionsRUN docker-php-ext-configure gd --with-freetype --with-jpeg && \docker-php-ext-install -j$(nproc) \gd \mysqli \pdo \pdo_mysql \mbstring \xml \zip \curl# Enable Apache rewrite moduleRUN a2enmod rewrite# Set working directoryWORKDIR /var/www/html# Clone BookBounty repositoryRUN git clone https://github.com/kraonix/BookBounty.git . && \git checkout main || git checkout master# Create necessary directoriesRUN mkdir -p /var/www/html/uploads \/var/www/html/books \/var/www/data \/var/www/logs && \chmod -R 755 /var/www/html && \chown -R www-data:www-data /var/www/html# Copy Apache configurationCOPY apache-config.conf /etc/apache2/sites-available/000-default.confRUN a2ensite 000-default# Copy database schemaCOPY bookbounty.sql /tmp/bookbounty.sql# Copy entrypoint scriptCOPY docker-entrypoint.sh /RUN chmod +x /docker-entrypoint.sh# Expose portEXPOSE 80# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \CMD curl -f http://localhost/ || exit 1# Run entrypointENTRYPOINT ["/docker-entrypoint.sh"]CMD ["apache2-foreground"]Create an
apache-config.conffile:<VirtualHost *:80>ServerAdmin admin@localhostDocumentRoot /var/www/htmlErrorLog /var/www/logs/error.logCustomLog /var/www/logs/access.log combined<Directory /var/www/html>Options Indexes FollowSymLinksAllowOverride AllRequire all granted</Directory><IfModule mod_rewrite.c>RewriteEngine OnRewriteBase /RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ index.php?url=$1 [QSA,L]</IfModule></VirtualHost>Create a
docker-entrypoint.shfile:#!/bin/bashset -e# Create necessary directoriesmkdir -p /var/www/html/uploads \/var/www/html/books \/var/www/data \/var/www/logs# Set proper permissionschmod -R 755 /var/www/htmlchown -R www-data:www-data /var/www/htmlchown -R www-data:www-data /var/www/datachown -R www-data:www-data /var/www/logs# Wait for database to be readyecho "Waiting for database connection..."until mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} -e ";" 2>/dev/null; doecho "Database is unavailable - sleeping..."sleep 2doneecho "Database is up!"# Initialize database if neededif ! mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} -e "use ${DB_NAME};" 2>/dev/null; thenecho "Creating database..."mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} -e "CREATE DATABASE ${DB_NAME};"echo "Importing database schema..."mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} ${DB_NAME} < /tmp/bookbounty.sqlfiecho "BookBounty is starting..."exec apache2-foregroundCreate a
.env.examplefile:Terminal window # BookBounty ConfigurationAPP_NAME=BookBountyAPP_DESCRIPTION=A vibrant literary community platformAPP_URL=https://bookbounty.yourdomain.com# Database ConfigurationDB_HOST=database.internalDB_NAME=bookbountyDB_USER=bookbountyDB_PASSWORD=secure_database_password# Admin UserADMIN_USERNAME=adminADMIN_PASSWORD=secure_admin_passwordADMIN_EMAIL=admin@yourdomain.com# File Upload ConfigurationMAX_UPLOAD_SIZE=50MALLOWED_FILE_TYPES=pdf,epub,mobiUPLOAD_PATH=/var/www/html/uploadsBOOKS_PATH=/var/www/html/books# Application SettingsBOOKS_PER_PAGE=12ENABLE_USER_REGISTRATION=trueREQUIRE_EMAIL_VERIFICATION=falseENABLE_REVIEWS=trueENABLE_RATINGS=true# Email ConfigurationSMTP_SERVER=smtp.gmail.comSMTP_PORT=587SMTP_USERNAME=noreply@yourdomain.comSMTP_PASSWORD=app_passwordSMTP_FROM_NAME=BookBounty Platform# LoggingLOG_LEVEL=infoLOG_PATH=/var/www/logs# SecuritySESSION_TIMEOUT=3600ENABLE_TWO_FACTOR_AUTH=falseCreate a
.gitignorefile:.envuploads/books/logs/*.lognode_modules/.DS_Storevendor/Commit and push to your GitHub repository:
Terminal window git initgit add .git commit -m "Initial BookBounty deployment"git remote add origin https://github.com/yourusername/bookbounty-deploy.gitgit push -u origin mainCreate a New App
In the Klutch.sh dashboard:
- Click “Create New App”
- Select your GitHub repository containing the Dockerfile
- Choose the branch (typically
mainormaster) - Klutch.sh will automatically detect the Dockerfile in the root directory
Configure Environment Variables
Set up these essential environment variables in your Klutch.sh dashboard:
Variable Description Example APP_NAMEPlatform name BookBountyAPP_DESCRIPTIONPlatform description Literary community platformAPP_URLYour platform domain https://bookbounty.yourdomain.comDB_HOSTDatabase host database.internalDB_NAMEDatabase name bookbountyDB_USERDatabase user bookbountyDB_PASSWORDDatabase password secure_passwordADMIN_USERNAMEAdmin username adminADMIN_PASSWORDAdmin password secure_passwordADMIN_EMAILAdmin email admin@yourdomain.comMAX_UPLOAD_SIZEMax file size 50MALLOWED_FILE_TYPESUpload types pdf,epub,mobiBOOKS_PER_PAGEPagination 12ENABLE_USER_REGISTRATIONAllow signups trueENABLE_REVIEWSEnable reviews trueENABLE_RATINGSEnable ratings trueSMTP_SERVEREmail server smtp.gmail.comSMTP_PORTEmail port 587LOG_LEVELLogging verbosity infoConfigure Persistent Storage
BookBounty requires persistent storage for book files and application data. Add persistent volumes:
Mount Path Description Recommended Size /var/www/html/uploadsUser avatars and content 50GB /var/www/html/booksBook files (PDFs, EPUBs) 500GB-2TB /var/www/dataApplication data 50GB /var/www/logsLog files 20GB In the Klutch.sh dashboard:
- Navigate to your app settings
- Go to the “Volumes” section
- Click “Add Volume” for each mount path
- Set mount paths and sizes as specified above
- Ensure books volume is sized adequately for your library
Set Network Configuration
Configure your app’s network settings:
- Select traffic type: HTTP
- Recommended internal port: 80 (standard web port for Apache)
- Klutch.sh will handle HTTPS termination via reverse proxy
- The application will be accessible at your configured domain
Configure Custom Domain
BookBounty works best with a custom domain for professional platform presence:
- Navigate to your app’s “Domains” section in Klutch.sh
- Click “Add Custom Domain”
- Enter your domain (e.g.,
bookbounty.yourdomain.comorlibrary.yourdomain.com) - Configure DNS with a CNAME record pointing to your Klutch.sh app
- Update
APP_URLenvironment variable to match your domain - Klutch.sh will automatically provision SSL certificates
- Access your platform at
https://bookbounty.yourdomain.com
Deploy Your App
- Review all settings and environment variables carefully
- Verify all persistent volumes are properly configured with adequate sizes
- Ensure database credentials are secure and match your configuration
- Click “Deploy”
- Klutch.sh will build the Docker image and start your BookBounty instance
- Wait for the deployment to complete (typically 10-15 minutes)
- Access your BookBounty platform at your configured domain
- Log in with admin credentials to begin setting up your platform
Initial Setup and Configuration
After deployment completes, access your BookBounty instance to configure your platform.
Accessing BookBounty
Navigate to your domain: https://bookbounty.yourdomain.com
Log in to the admin panel using admin credentials you configured.
Admin Dashboard Access
Access administrative features:
- Navigate to
https://bookbounty.yourdomain.com/adminor click “Admin” link - Enter admin username and password
- You’re now in the admin dashboard
- Configure platform settings and user management
- Access analytics and platform statistics
Creating User Roles
Set up different user types with appropriate permissions:
-
Admin Role:
- Full platform control
- User and book management
- Content moderation
- Analytics and statistics
- Platform configuration
-
Author Role:
- Upload and manage personal books
- Edit book metadata
- View book statistics
- Receive review feedback
- Manage publication status
-
User/Reader Role:
- Browse and read books
- Leave reviews and ratings
- Create reading lists
- Follow favorite authors
- Access personal library
Managing User Accounts
Administer user accounts effectively:
- Navigate to “Users” in admin dashboard
- View all registered users
- Create new user accounts manually
- Edit user information and roles
- Reset user passwords
- Deactivate or delete accounts
- Monitor user activity logs
Adding Books to the Platform
Upload and manage books:
-
As Admin:
- Click “Add Book” in admin panel
- Enter book metadata (title, author, description, genre)
- Upload book file (PDF, EPUB, MOBI)
- Upload cover image
- Set pricing (if applicable)
- Publish book
-
As Author:
- Access “My Books” section
- Click “Upload New Book”
- Fill in book details
- Upload book file
- Submit for admin approval (if required)
- Manage book settings
Managing Book Content
Configure book management settings:
- Go to “Settings” → “Book Management”
- Configure:
- Allowed file formats
- Maximum file size
- File storage location
- Book approval workflow
- Cover image specifications
- Set content policies
- Configure metadata fields
- Enable/disable specific features
Configuring Content Moderation
Set up moderation for reviews and user-generated content:
- Navigate to “Moderation” in admin panel
- Configure:
- Review moderation requirements
- Automatic content filtering
- Flagging and reporting system
- Content removal policies
- Set moderation queue
- Approve pending reviews
- Remove inappropriate content
Setting Up Email Notifications
Configure email system for user communications:
- Go to “Settings” → “Email Configuration”
- Set up SMTP server:
- SMTP server address
- SMTP port
- Authentication credentials
- Configure email templates:
- Welcome emails
- Password reset emails
- Review notifications
- New book notifications
- Test email delivery
- Configure notification preferences
Customizing Platform Appearance
Personalize your BookBounty instance:
- Access “Settings” → “Appearance”
- Configure:
- Platform name and logo
- Color scheme and theme
- Homepage content
- Footer information
- Upload custom branding assets
- Set page layout options
- Preview changes before publishing
Setting User Registration Settings
Control how new users join your platform:
- Navigate to “Settings” → “Registration”
- Configure:
- Enable/disable user registration
- Email verification requirements
- Terms and conditions
- User approval workflow
- Set registration fields
- Configure welcome messages
- Set role assignment for new users
Environment Variable Examples
Basic Configuration
APP_NAME=BookBountyAPP_URL=https://bookbounty.yourdomain.comDB_HOST=database.internalDB_NAME=bookbountyDB_USER=bookbountyDB_PASSWORD=securepasswordADMIN_USERNAME=adminADMIN_EMAIL=admin@yourdomain.comComplete Production Configuration
# Application SettingsAPP_NAME=BookBounty Literary PlatformAPP_DESCRIPTION=A dynamic community for discovering and sharing booksAPP_URL=https://bookbounty.yourdomain.comAPP_LOGO_URL=https://yourdomain.com/logo.png
# Database ConfigurationDB_HOST=database.internalDB_PORT=3306DB_NAME=bookbountyDB_USER=bookbountyDB_PASSWORD=very_secure_database_password_32_charsDB_CHARSET=utf8mb4DB_COLLATION=utf8mb4_unicode_ci
# Admin UserADMIN_USERNAME=adminADMIN_PASSWORD=very_secure_admin_password_32_charsADMIN_EMAIL=admin@yourdomain.comADMIN_DISPLAY_NAME=Administrator
# File Upload ConfigurationMAX_UPLOAD_SIZE=50MALLOWED_FILE_TYPES=pdf,epub,mobi,doc,docxUPLOAD_PATH=/var/www/html/uploadsBOOKS_PATH=/var/www/html/booksCOVER_IMAGE_PATH=/var/www/html/covers
# Application FeaturesBOOKS_PER_PAGE=12ENABLE_USER_REGISTRATION=trueENABLE_AUTHOR_REGISTRATION=trueREQUIRE_EMAIL_VERIFICATION=trueREQUIRE_APPROVAL_FOR_AUTHORS=trueENABLE_REVIEWS=trueENABLE_RATINGS=trueENABLE_COMMENTS=trueENABLE_SOCIAL_SHARING=true
# Email ConfigurationSMTP_SERVER=smtp.gmail.comSMTP_PORT=587SMTP_USERNAME=noreply@yourdomain.comSMTP_PASSWORD=app_specific_passwordSMTP_FROM_NAME=BookBounty PlatformSMTP_FROM_EMAIL=noreply@yourdomain.comSMTP_USE_TLS=true
# Search ConfigurationENABLE_FULL_TEXT_SEARCH=trueSEARCH_INDEX_PATH=/var/www/data/searchMAX_SEARCH_RESULTS=50
# Analytics ConfigurationENABLE_ANALYTICS=trueANALYTICS_TRACKING_ID=your_tracking_idCOLLECT_USER_STATISTICS=true
# Security ConfigurationSESSION_TIMEOUT=3600ENABLE_TWO_FACTOR_AUTH=falseENABLE_CAPTCHA=trueCOOKIE_SECURE=trueCOOKIE_HTTPONLY=truePASSWORD_MIN_LENGTH=8REQUIRE_STRONG_PASSWORDS=true
# LoggingLOG_LEVEL=infoLOG_PATH=/var/www/logsLOG_ROTATION_ENABLED=trueLOG_RETENTION_DAYS=30
# PerformanceENABLE_CACHING=trueCACHE_TTL=3600DATABASE_POOL_SIZE=20Sample Code and Getting Started
PHP - Book Management Integration
<?php// BookBounty Book Management Integration
class BookManager { private $db; private $uploadPath; private $allowedTypes;
public function __construct($database, $uploadPath, $allowedTypes = ['pdf', 'epub', 'mobi']) { $this->db = $database; $this->uploadPath = $uploadPath; $this->allowedTypes = $allowedTypes; }
/** * Upload a new book */ public function uploadBook($title, $author, $description, $file, $coverId = null) { // Validate file $fileExt = pathinfo($file['name'], PATHINFO_EXTENSION);
if (!in_array(strtolower($fileExt), $this->allowedTypes)) { throw new Exception('File type not allowed'); }
if ($file['size'] > 50 * 1024 * 1024) { // 50MB limit throw new Exception('File size exceeds maximum'); }
// Generate unique filename $uniqueName = uniqid('book_') . '.' . $fileExt; $uploadPath = $this->uploadPath . '/' . $uniqueName;
// Move uploaded file if (!move_uploaded_file($file['tmp_name'], $uploadPath)) { throw new Exception('Failed to upload file'); }
// Insert into database $query = "INSERT INTO books (title, author, description, file_path, cover_id, upload_date) VALUES (?, ?, ?, ?, ?, NOW())";
$stmt = $this->db->prepare($query); $stmt->bind_param('ssssi', $title, $author, $description, $uploadPath, $coverId);
if ($stmt->execute()) { return $this->db->insert_id; } else { unlink($uploadPath); throw new Exception('Database error: ' . $this->db->error); } }
/** * Get all books with pagination */ public function getBooks($page = 1, $perPage = 12) { $offset = ($page - 1) * $perPage;
$query = "SELECT id, title, author, description, cover_id, upload_date, rating_count, avg_rating FROM books WHERE published = true ORDER BY upload_date DESC LIMIT ? OFFSET ?";
$stmt = $this->db->prepare($query); $stmt->bind_param('ii', $perPage, $offset); $stmt->execute();
return $stmt->get_result()->fetch_all(MYSQLI_ASSOC); }
/** * Search books */ public function searchBooks($query, $page = 1, $perPage = 12) { $offset = ($page - 1) * $perPage; $searchTerm = '%' . $query . '%';
$sql = "SELECT id, title, author, description, cover_id, rating_count, avg_rating FROM books WHERE published = true AND (title LIKE ? OR author LIKE ? OR description LIKE ?) ORDER BY rating_count DESC LIMIT ? OFFSET ?";
$stmt = $this->db->prepare($sql); $stmt->bind_param('sssii', $searchTerm, $searchTerm, $searchTerm, $perPage, $offset); $stmt->execute();
return $stmt->get_result()->fetch_all(MYSQLI_ASSOC); }
/** * Get book details */ public function getBook($bookId) { $query = "SELECT b.*, u.username as author_username, COUNT(DISTINCT r.id) as review_count, AVG(r.rating) as avg_rating FROM books b LEFT JOIN users u ON b.author_id = u.id LEFT JOIN reviews r ON b.id = r.book_id WHERE b.id = ? GROUP BY b.id";
$stmt = $this->db->prepare($query); $stmt->bind_param('i', $bookId); $stmt->execute();
return $stmt->get_result()->fetch_assoc(); }
/** * Add review to book */ public function addReview($bookId, $userId, $rating, $reviewText) { if ($rating < 1 || $rating > 5) { throw new Exception('Rating must be between 1 and 5'); }
$query = "INSERT INTO reviews (book_id, user_id, rating, review_text, created_at) VALUES (?, ?, ?, ?, NOW())";
$stmt = $this->db->prepare($query); $stmt->bind_param('iis', $bookId, $userId, $rating, $reviewText);
if ($stmt->execute()) { // Update book rating $this->updateBookRating($bookId); return true; }
return false; }
/** * Update book rating */ private function updateBookRating($bookId) { $query = "UPDATE books SET rating_count = (SELECT COUNT(*) FROM reviews WHERE book_id = ?), avg_rating = (SELECT AVG(rating) FROM reviews WHERE book_id = ?) WHERE id = ?";
$stmt = $this->db->prepare($query); $stmt->bind_param('iii', $bookId, $bookId, $bookId);
return $stmt->execute(); }
/** * Get books by genre */ public function getBooksByGenre($genre, $page = 1, $perPage = 12) { $offset = ($page - 1) * $perPage;
$query = "SELECT b.id, b.title, b.author, b.description, b.cover_id, b.avg_rating FROM books b WHERE b.published = true AND b.genre = ? ORDER BY b.upload_date DESC LIMIT ? OFFSET ?";
$stmt = $this->db->prepare($query); $stmt->bind_param('sii', $genre, $perPage, $offset); $stmt->execute();
return $stmt->get_result()->fetch_all(MYSQLI_ASSOC); }}
// Usage example$bookManager = new BookManager($mysqli, '/var/www/html/books');
// Upload a booktry { $bookId = $bookManager->uploadBook( 'My Great Novel', 'John Doe', 'An amazing fiction story', $_FILES['book_file'] ); echo "Book uploaded successfully with ID: " . $bookId;} catch (Exception $e) { echo "Error: " . $e->getMessage();}
// Search books$results = $bookManager->searchBooks('fiction', 1, 12);JavaScript - Frontend Book Browser
// BookBounty Book Browser Interface
class BookBrowser { constructor(containerId, apiUrl) { this.container = document.getElementById(containerId); this.apiUrl = apiUrl; this.currentPage = 1; this.booksPerPage = 12; this.currentFilter = 'all'; this.init(); }
async init() { this.setupUI(); this.setupEventListeners(); this.loadBooks(); }
setupUI() { this.container.innerHTML = ` <div class="book-browser"> <div class="search-bar"> <input type="text" id="searchInput" placeholder="Search books by title, author, or genre..." /> <button id="searchBtn" class="btn-primary">Search</button> </div>
<div class="filters"> <select id="genreFilter" class="filter-select"> <option value="">All Genres</option> <option value="fiction">Fiction</option> <option value="non-fiction">Non-Fiction</option> <option value="mystery">Mystery</option> <option value="romance">Romance</option> <option value="science-fiction">Science Fiction</option> </select> <select id="sortFilter" class="filter-select"> <option value="latest">Latest</option> <option value="rating">Highest Rated</option> <option value="popular">Most Popular</option> <option value="title">Title (A-Z)</option> </select> </div>
<div id="bookGrid" class="book-grid"></div>
<div class="pagination"> <button id="prevBtn" class="btn-nav">← Previous</button> <span id="pageInfo" class="page-info">Page 1</span> <button id="nextBtn" class="btn-nav">Next →</button> </div> </div> `;
this.bookGrid = document.getElementById('bookGrid'); this.pageInfo = document.getElementById('pageInfo'); }
setupEventListeners() { document.getElementById('searchBtn').addEventListener('click', () => { this.search(); });
document.getElementById('searchInput').addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.search(); } });
document.getElementById('genreFilter').addEventListener('change', (e) => { this.currentFilter = e.target.value; this.currentPage = 1; this.loadBooks(); });
document.getElementById('sortFilter').addEventListener('change', (e) => { this.loadBooks(e.target.value); });
document.getElementById('prevBtn').addEventListener('click', () => { if (this.currentPage > 1) { this.currentPage--; this.loadBooks(); } });
document.getElementById('nextBtn').addEventListener('click', () => { this.currentPage++; this.loadBooks(); }); }
async loadBooks(sort = 'latest') { try { const params = new URLSearchParams({ page: this.currentPage, perPage: this.booksPerPage, sort: sort, genre: this.currentFilter });
const response = await fetch(this.apiUrl + '/api/books?' + params); const data = await response.json();
this.displayBooks(data.books); this.updatePagination(data.totalPages); } catch (error) { console.error('Failed to load books:', error); this.bookGrid.innerHTML = '<p class="error">Failed to load books</p>'; } }
async search() { const searchTerm = document.getElementById('searchInput').value; if (!searchTerm) { this.currentPage = 1; this.loadBooks(); return; }
try { const response = await fetch( this.apiUrl + '/api/books/search?q=' + encodeURIComponent(searchTerm) + '&page=' + this.currentPage ); const data = await response.json();
this.displayBooks(data.books); this.updatePagination(data.totalPages); } catch (error) { console.error('Search failed:', error); } }
displayBooks(books) { if (!books || books.length === 0) { this.bookGrid.innerHTML = '<p class="no-results">No books found</p>'; return; }
this.bookGrid.innerHTML = books.map(book => ` <div class="book-card"> <div class="book-cover"> <img src="${book.coverUrl}" alt="${book.title}" /> <div class="book-overlay"> <button class="btn-read" data-book-id="${book.id}">Read Now</button> </div> </div> <div class="book-info"> <h3 class="book-title">${this.escapeHtml(book.title)}</h3> <p class="book-author">by ${this.escapeHtml(book.author)}</p> <div class="book-rating"> ${this.renderStars(book.avgRating)} <span class="rating-count">(${book.reviewCount} reviews)</span> </div> <p class="book-description">${this.escapeHtml(book.description.substring(0, 100))}...</p> <div class="book-meta"> <span class="genre-tag">${book.genre}</span> </div> </div> </div> `).join('');
// Add click listeners to read buttons document.querySelectorAll('.btn-read').forEach(btn => { btn.addEventListener('click', (e) => { const bookId = e.target.getAttribute('data-book-id'); window.location.href = `/book/${bookId}/read`; }); }); }
renderStars(rating) { const stars = []; const fullStars = Math.floor(rating); const hasHalfStar = rating % 1 >= 0.5;
for (let i = 0; i < 5; i++) { if (i < fullStars) { stars.push('★'); } else if (i === fullStars && hasHalfStar) { stars.push('⭐'); } else { stars.push('☆'); } }
return stars.join(''); }
updatePagination(totalPages) { this.pageInfo.textContent = `Page ${this.currentPage} of ${totalPages}`; document.getElementById('prevBtn').disabled = this.currentPage === 1; document.getElementById('nextBtn').disabled = this.currentPage === totalPages; }
escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, m => map[m]); }}
// Initialize browserdocument.addEventListener('DOMContentLoaded', () => { new BookBrowser('bookContainer', 'https://bookbounty.yourdomain.com');});Bash - Backup and Maintenance Script
#!/bin/bash
# BookBounty Backup and Maintenance ScriptBACKUP_DIR="/backups/bookbounty"TIMESTAMP=$(date +%Y%m%d_%H%M%S)RETENTION_DAYS=30
# Create backup directorymkdir -p $BACKUP_DIR
echo "Starting BookBounty backup..."
# Backup databaseecho "Backing up MySQL database..."mysqldump -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} ${DB_NAME} > $BACKUP_DIR/bookbounty_db_$TIMESTAMP.sql
# Compress database backupgzip $BACKUP_DIR/bookbounty_db_$TIMESTAMP.sql
# Backup book filesecho "Backing up book files..."tar -czf $BACKUP_DIR/bookbounty_books_$TIMESTAMP.tar.gz \ /var/www/html/books
# Backup user uploadsecho "Backing up user uploads..."tar -czf $BACKUP_DIR/bookbounty_uploads_$TIMESTAMP.tar.gz \ /var/www/html/uploads
# Backup configurationecho "Backing up configuration..."tar -czf $BACKUP_DIR/bookbounty_config_$TIMESTAMP.tar.gz \ /var/www/html/config \ /var/www/html/settings.php
# Cleanup old backupsecho "Cleaning up old backups..."find $BACKUP_DIR -name "bookbounty_*" -mtime +$RETENTION_DAYS -delete
# Verify backup integrityecho "Verifying backup integrity..."for file in $BACKUP_DIR/bookbounty_*_$TIMESTAMP.*; do if gzip -t "$file" 2>/dev/null; then echo "✓ Verified: $(basename $file)" else echo "✗ Failed: $(basename $file)" fidone
# Calculate backup sizeTOTAL_SIZE=$(du -sh $BACKUP_DIR | awk '{print $1}')
echo ""echo "Backup completed: $TIMESTAMP"echo "Total backup size: $TOTAL_SIZE"echo "Backup location: $BACKUP_DIR"
# List recent backupsecho ""echo "Recent backups:"ls -lh $BACKUP_DIR | tail -15
# Maintenance tasksecho ""echo "Running database optimization..."mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} ${DB_NAME} -e "OPTIMIZE TABLE books, users, reviews, ratings;"
# Optional: Upload to cloud storage# aws s3 sync $BACKUP_DIR s3://your-bucket/bookbounty-backups/ --delete
# Optional: Send backup notification# curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \# -d "{\"text\":\"BookBounty backup completed successfully\"}"cURL - API Integration Examples
# BookBounty API Examples
# Get all bookscurl -X GET https://bookbounty.yourdomain.com/api/books \ -H "Content-Type: application/json"
# Get book with paginationcurl -X GET "https://bookbounty.yourdomain.com/api/books?page=1&perPage=12" \ -H "Content-Type: application/json"
# Search bookscurl -X GET "https://bookbounty.yourdomain.com/api/books/search?q=fiction&page=1" \ -H "Content-Type: application/json"
# Get book detailscurl -X GET https://bookbounty.yourdomain.com/api/books/123 \ -H "Content-Type: application/json"
# Get books by genrecurl -X GET "https://bookbounty.yourdomain.com/api/books/genre/fiction?page=1" \ -H "Content-Type: application/json"
# Get book reviewscurl -X GET https://bookbounty.yourdomain.com/api/books/123/reviews \ -H "Content-Type: application/json"
# Add review (requires authentication)curl -X POST https://bookbounty.yourdomain.com/api/books/123/reviews \ -H "Content-Type: application/json" \ -H "Authorization: Bearer SESSION_TOKEN" \ -d '{ "rating": 4, "reviewText": "An excellent book that I highly recommend!" }'
# Get user profilecurl -X GET https://bookbounty.yourdomain.com/api/users/123 \ -H "Content-Type: application/json"
# Get user books (for authors)curl -X GET "https://bookbounty.yourdomain.com/api/users/123/books" \ -H "Content-Type: application/json"
# Get featured bookscurl -X GET https://bookbounty.yourdomain.com/api/books/featured \ -H "Content-Type: application/json"
# Get top-rated bookscurl -X GET "https://bookbounty.yourdomain.com/api/books/top-rated?limit=10" \ -H "Content-Type: application/json"
# Create user account (registration)curl -X POST https://bookbounty.yourdomain.com/api/auth/register \ -H "Content-Type: application/json" \ -d '{ "username": "newuser", "email": "newuser@example.com", "password": "securepassword123" }'
# Login usercurl -X POST https://bookbounty.yourdomain.com/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "username": "username", "password": "password" }'Platform Management
Managing Authors and Content Contributors
Support your author community:
-
Author Registration:
- Enable author registration in settings
- Set up author approval workflow
- Provide author guidelines
- Create onboarding documentation
-
Author Tools:
- Dashboard for book management
- Sales analytics if applicable
- Royalty tracking
- Reader communication tools
-
Content Moderation:
- Review book submissions
- Check for copyright compliance
- Verify metadata accuracy
- Manage content removal requests
Moderating User Reviews
Maintain community standards:
- Set review moderation policies
- Flag and review reported reviews
- Remove inappropriate content
- Maintain rating accuracy
- Address author disputes professionally
Monitoring Platform Analytics
Track platform performance:
- Monitor user growth
- Track book upload trends
- Analyze search patterns
- Monitor reading behavior
- Review user engagement metrics
Troubleshooting
Common Issues and Solutions
Issue: Cannot access the platform
Solutions:
- Verify Klutch.sh app is running
- Check domain DNS resolution
- Clear browser cache
- Verify SSL certificate is valid
- Check network connectivity
Issue: Books not uploading
Troubleshooting:
- Verify disk space availability
- Check file permissions on upload directory
- Verify file size limits
- Ensure file format is supported
- Check browser console for errors
Issue: Database connection errors
Solutions:
- Verify database credentials
- Check database host accessibility
- Ensure database is running
- Verify user permissions
- Check error logs
Issue: Slow platform performance
Solutions:
- Check server resource usage
- Optimize database queries
- Enable caching
- Reduce image file sizes
- Monitor concurrent user connections
Issue: Email notifications not sending
Troubleshooting:
- Verify SMTP configuration
- Check SMTP credentials
- Verify firewall rules
- Review mail logs
- Test SMTP connection
Updating BookBounty
To update BookBounty to a newer version:
- Backup your database and files
- Update your Dockerfile to pull latest code
- Commit and push to GitHub
- Klutch.sh will automatically rebuild
- Test all functionality after upgrade
- Verify database integrity
- Monitor logs for any issues
Use Cases
Educational Institution Library
- Manage course materials
- Host student-created content
- Organize by departments or courses
- Control access by user roles
Self-Publishing Platform
- Enable independent authors to publish
- Monetize through sales
- Track author earnings
- Build author community
Community Library
- Shared reading lists
- Community recommendations
- Event coordination
- Book club management
Corporate Knowledge Base
- Store company documentation
- Share procedures and guidelines
- Training materials
- Policy documents
Literary Magazine
- Publish short stories and poetry
- Manage submissions
- Build subscriber base
- Archive past issues
Additional Resources
- BookBounty GitHub Repository - Source code and community contributions
- BookBounty React Frontend - Modern React-based frontend alternative
- Klutch.sh Getting Started Guide
- Klutch.sh Volumes Documentation
- Klutch.sh Custom Domains Guide
Conclusion
Deploying BookBounty on Klutch.sh provides you with a powerful, full-stack platform for fostering a vibrant literary community. With role-based access control, comprehensive book management, seamless reading experience, powerful admin controls, and responsive design, BookBounty enables you to build a platform that connects authors with readers. Klutch.sh’s managed infrastructure ensures your platform is always available, secure, and performant, allowing you to focus on building a thriving literary community.
Start building your digital literary platform today by deploying BookBounty on Klutch.sh and experience the power of a dedicated book-sharing ecosystem.