Skip to content

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

  1. Create a New Project

    Log in to your Klutch.sh dashboard and create a new project for your BookBounty platform.

  2. 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.md

    Here’s a Dockerfile for BookBounty:

    FROM php:8.2-apache
    # Install system dependencies
    RUN 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 extensions
    RUN 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 module
    RUN a2enmod rewrite
    # Set working directory
    WORKDIR /var/www/html
    # Clone BookBounty repository
    RUN git clone https://github.com/kraonix/BookBounty.git . && \
    git checkout main || git checkout master
    # Create necessary directories
    RUN 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 configuration
    COPY apache-config.conf /etc/apache2/sites-available/000-default.conf
    RUN a2ensite 000-default
    # Copy database schema
    COPY bookbounty.sql /tmp/bookbounty.sql
    # Copy entrypoint script
    COPY docker-entrypoint.sh /
    RUN chmod +x /docker-entrypoint.sh
    # Expose port
    EXPOSE 80
    # Health check
    HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost/ || exit 1
    # Run entrypoint
    ENTRYPOINT ["/docker-entrypoint.sh"]
    CMD ["apache2-foreground"]

    Create an apache-config.conf file:

    <VirtualHost *:80>
    ServerAdmin admin@localhost
    DocumentRoot /var/www/html
    ErrorLog /var/www/logs/error.log
    CustomLog /var/www/logs/access.log combined
    <Directory /var/www/html>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
    </Directory>
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
    </IfModule>
    </VirtualHost>

    Create a docker-entrypoint.sh file:

    #!/bin/bash
    set -e
    # Create necessary directories
    mkdir -p /var/www/html/uploads \
    /var/www/html/books \
    /var/www/data \
    /var/www/logs
    # Set proper permissions
    chmod -R 755 /var/www/html
    chown -R www-data:www-data /var/www/html
    chown -R www-data:www-data /var/www/data
    chown -R www-data:www-data /var/www/logs
    # Wait for database to be ready
    echo "Waiting for database connection..."
    until mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} -e ";" 2>/dev/null; do
    echo "Database is unavailable - sleeping..."
    sleep 2
    done
    echo "Database is up!"
    # Initialize database if needed
    if ! mysql -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} -e "use ${DB_NAME};" 2>/dev/null; then
    echo "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.sql
    fi
    echo "BookBounty is starting..."
    exec apache2-foreground

    Create a .env.example file:

    Terminal window
    # BookBounty Configuration
    APP_NAME=BookBounty
    APP_DESCRIPTION=A vibrant literary community platform
    APP_URL=https://bookbounty.yourdomain.com
    # Database Configuration
    DB_HOST=database.internal
    DB_NAME=bookbounty
    DB_USER=bookbounty
    DB_PASSWORD=secure_database_password
    # Admin User
    ADMIN_USERNAME=admin
    ADMIN_PASSWORD=secure_admin_password
    ADMIN_EMAIL=admin@yourdomain.com
    # File Upload Configuration
    MAX_UPLOAD_SIZE=50M
    ALLOWED_FILE_TYPES=pdf,epub,mobi
    UPLOAD_PATH=/var/www/html/uploads
    BOOKS_PATH=/var/www/html/books
    # Application Settings
    BOOKS_PER_PAGE=12
    ENABLE_USER_REGISTRATION=true
    REQUIRE_EMAIL_VERIFICATION=false
    ENABLE_REVIEWS=true
    ENABLE_RATINGS=true
    # Email Configuration
    SMTP_SERVER=smtp.gmail.com
    SMTP_PORT=587
    SMTP_USERNAME=noreply@yourdomain.com
    SMTP_PASSWORD=app_password
    SMTP_FROM_NAME=BookBounty Platform
    # Logging
    LOG_LEVEL=info
    LOG_PATH=/var/www/logs
    # Security
    SESSION_TIMEOUT=3600
    ENABLE_TWO_FACTOR_AUTH=false

    Create a .gitignore file:

    .env
    uploads/
    books/
    logs/
    *.log
    node_modules/
    .DS_Store
    vendor/

    Commit and push to your GitHub repository:

    Terminal window
    git init
    git add .
    git commit -m "Initial BookBounty deployment"
    git remote add origin https://github.com/yourusername/bookbounty-deploy.git
    git push -u origin main
  3. Create a New App

    In the Klutch.sh dashboard:

    • Click “Create New App”
    • Select your GitHub repository containing the Dockerfile
    • Choose the branch (typically main or master)
    • Klutch.sh will automatically detect the Dockerfile in the root directory
  4. Configure Environment Variables

    Set up these essential environment variables in your Klutch.sh dashboard:

    VariableDescriptionExample
    APP_NAMEPlatform nameBookBounty
    APP_DESCRIPTIONPlatform descriptionLiterary community platform
    APP_URLYour platform domainhttps://bookbounty.yourdomain.com
    DB_HOSTDatabase hostdatabase.internal
    DB_NAMEDatabase namebookbounty
    DB_USERDatabase userbookbounty
    DB_PASSWORDDatabase passwordsecure_password
    ADMIN_USERNAMEAdmin usernameadmin
    ADMIN_PASSWORDAdmin passwordsecure_password
    ADMIN_EMAILAdmin emailadmin@yourdomain.com
    MAX_UPLOAD_SIZEMax file size50M
    ALLOWED_FILE_TYPESUpload typespdf,epub,mobi
    BOOKS_PER_PAGEPagination12
    ENABLE_USER_REGISTRATIONAllow signupstrue
    ENABLE_REVIEWSEnable reviewstrue
    ENABLE_RATINGSEnable ratingstrue
    SMTP_SERVEREmail serversmtp.gmail.com
    SMTP_PORTEmail port587
    LOG_LEVELLogging verbosityinfo
  5. Configure Persistent Storage

    BookBounty requires persistent storage for book files and application data. Add persistent volumes:

    Mount PathDescriptionRecommended Size
    /var/www/html/uploadsUser avatars and content50GB
    /var/www/html/booksBook files (PDFs, EPUBs)500GB-2TB
    /var/www/dataApplication data50GB
    /var/www/logsLog files20GB

    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
  6. 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
  7. 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.com or library.yourdomain.com)
    • Configure DNS with a CNAME record pointing to your Klutch.sh app
    • Update APP_URL environment variable to match your domain
    • Klutch.sh will automatically provision SSL certificates
    • Access your platform at https://bookbounty.yourdomain.com
  8. 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:

  1. Navigate to https://bookbounty.yourdomain.com/admin or click “Admin” link
  2. Enter admin username and password
  3. You’re now in the admin dashboard
  4. Configure platform settings and user management
  5. Access analytics and platform statistics

Creating User Roles

Set up different user types with appropriate permissions:

  1. Admin Role:

    • Full platform control
    • User and book management
    • Content moderation
    • Analytics and statistics
    • Platform configuration
  2. Author Role:

    • Upload and manage personal books
    • Edit book metadata
    • View book statistics
    • Receive review feedback
    • Manage publication status
  3. 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:

  1. Navigate to “Users” in admin dashboard
  2. View all registered users
  3. Create new user accounts manually
  4. Edit user information and roles
  5. Reset user passwords
  6. Deactivate or delete accounts
  7. Monitor user activity logs

Adding Books to the Platform

Upload and manage books:

  1. 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
  2. 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:

  1. Go to “Settings” → “Book Management”
  2. Configure:
    • Allowed file formats
    • Maximum file size
    • File storage location
    • Book approval workflow
    • Cover image specifications
  3. Set content policies
  4. Configure metadata fields
  5. Enable/disable specific features

Configuring Content Moderation

Set up moderation for reviews and user-generated content:

  1. Navigate to “Moderation” in admin panel
  2. Configure:
    • Review moderation requirements
    • Automatic content filtering
    • Flagging and reporting system
    • Content removal policies
  3. Set moderation queue
  4. Approve pending reviews
  5. Remove inappropriate content

Setting Up Email Notifications

Configure email system for user communications:

  1. Go to “Settings” → “Email Configuration”
  2. Set up SMTP server:
    • SMTP server address
    • SMTP port
    • Authentication credentials
  3. Configure email templates:
    • Welcome emails
    • Password reset emails
    • Review notifications
    • New book notifications
  4. Test email delivery
  5. Configure notification preferences

Customizing Platform Appearance

Personalize your BookBounty instance:

  1. Access “Settings” → “Appearance”
  2. Configure:
    • Platform name and logo
    • Color scheme and theme
    • Homepage content
    • Footer information
  3. Upload custom branding assets
  4. Set page layout options
  5. Preview changes before publishing

Setting User Registration Settings

Control how new users join your platform:

  1. Navigate to “Settings” → “Registration”
  2. Configure:
    • Enable/disable user registration
    • Email verification requirements
    • Terms and conditions
    • User approval workflow
  3. Set registration fields
  4. Configure welcome messages
  5. Set role assignment for new users

Environment Variable Examples

Basic Configuration

Terminal window
APP_NAME=BookBounty
APP_URL=https://bookbounty.yourdomain.com
DB_HOST=database.internal
DB_NAME=bookbounty
DB_USER=bookbounty
DB_PASSWORD=securepassword
ADMIN_USERNAME=admin
ADMIN_EMAIL=admin@yourdomain.com

Complete Production Configuration

Terminal window
# Application Settings
APP_NAME=BookBounty Literary Platform
APP_DESCRIPTION=A dynamic community for discovering and sharing books
APP_URL=https://bookbounty.yourdomain.com
APP_LOGO_URL=https://yourdomain.com/logo.png
# Database Configuration
DB_HOST=database.internal
DB_PORT=3306
DB_NAME=bookbounty
DB_USER=bookbounty
DB_PASSWORD=very_secure_database_password_32_chars
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
# Admin User
ADMIN_USERNAME=admin
ADMIN_PASSWORD=very_secure_admin_password_32_chars
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_DISPLAY_NAME=Administrator
# File Upload Configuration
MAX_UPLOAD_SIZE=50M
ALLOWED_FILE_TYPES=pdf,epub,mobi,doc,docx
UPLOAD_PATH=/var/www/html/uploads
BOOKS_PATH=/var/www/html/books
COVER_IMAGE_PATH=/var/www/html/covers
# Application Features
BOOKS_PER_PAGE=12
ENABLE_USER_REGISTRATION=true
ENABLE_AUTHOR_REGISTRATION=true
REQUIRE_EMAIL_VERIFICATION=true
REQUIRE_APPROVAL_FOR_AUTHORS=true
ENABLE_REVIEWS=true
ENABLE_RATINGS=true
ENABLE_COMMENTS=true
ENABLE_SOCIAL_SHARING=true
# Email Configuration
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=noreply@yourdomain.com
SMTP_PASSWORD=app_specific_password
SMTP_FROM_NAME=BookBounty Platform
SMTP_FROM_EMAIL=noreply@yourdomain.com
SMTP_USE_TLS=true
# Search Configuration
ENABLE_FULL_TEXT_SEARCH=true
SEARCH_INDEX_PATH=/var/www/data/search
MAX_SEARCH_RESULTS=50
# Analytics Configuration
ENABLE_ANALYTICS=true
ANALYTICS_TRACKING_ID=your_tracking_id
COLLECT_USER_STATISTICS=true
# Security Configuration
SESSION_TIMEOUT=3600
ENABLE_TWO_FACTOR_AUTH=false
ENABLE_CAPTCHA=true
COOKIE_SECURE=true
COOKIE_HTTPONLY=true
PASSWORD_MIN_LENGTH=8
REQUIRE_STRONG_PASSWORDS=true
# Logging
LOG_LEVEL=info
LOG_PATH=/var/www/logs
LOG_ROTATION_ENABLED=true
LOG_RETENTION_DAYS=30
# Performance
ENABLE_CACHING=true
CACHE_TTL=3600
DATABASE_POOL_SIZE=20

Sample 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 book
try {
$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 = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
};
return text.replace(/[&<>"']/g, m => map[m]);
}
}
// Initialize browser
document.addEventListener('DOMContentLoaded', () => {
new BookBrowser('bookContainer', 'https://bookbounty.yourdomain.com');
});

Bash - Backup and Maintenance Script

#!/bin/bash
# BookBounty Backup and Maintenance Script
BACKUP_DIR="/backups/bookbounty"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# Create backup directory
mkdir -p $BACKUP_DIR
echo "Starting BookBounty backup..."
# Backup database
echo "Backing up MySQL database..."
mysqldump -h ${DB_HOST} -u ${DB_USER} -p${DB_PASSWORD} ${DB_NAME} > $BACKUP_DIR/bookbounty_db_$TIMESTAMP.sql
# Compress database backup
gzip $BACKUP_DIR/bookbounty_db_$TIMESTAMP.sql
# Backup book files
echo "Backing up book files..."
tar -czf $BACKUP_DIR/bookbounty_books_$TIMESTAMP.tar.gz \
/var/www/html/books
# Backup user uploads
echo "Backing up user uploads..."
tar -czf $BACKUP_DIR/bookbounty_uploads_$TIMESTAMP.tar.gz \
/var/www/html/uploads
# Backup configuration
echo "Backing up configuration..."
tar -czf $BACKUP_DIR/bookbounty_config_$TIMESTAMP.tar.gz \
/var/www/html/config \
/var/www/html/settings.php
# Cleanup old backups
echo "Cleaning up old backups..."
find $BACKUP_DIR -name "bookbounty_*" -mtime +$RETENTION_DAYS -delete
# Verify backup integrity
echo "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)"
fi
done
# Calculate backup size
TOTAL_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 backups
echo ""
echo "Recent backups:"
ls -lh $BACKUP_DIR | tail -15
# Maintenance tasks
echo ""
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

Terminal window
# BookBounty API Examples
# Get all books
curl -X GET https://bookbounty.yourdomain.com/api/books \
-H "Content-Type: application/json"
# Get book with pagination
curl -X GET "https://bookbounty.yourdomain.com/api/books?page=1&perPage=12" \
-H "Content-Type: application/json"
# Search books
curl -X GET "https://bookbounty.yourdomain.com/api/books/search?q=fiction&page=1" \
-H "Content-Type: application/json"
# Get book details
curl -X GET https://bookbounty.yourdomain.com/api/books/123 \
-H "Content-Type: application/json"
# Get books by genre
curl -X GET "https://bookbounty.yourdomain.com/api/books/genre/fiction?page=1" \
-H "Content-Type: application/json"
# Get book reviews
curl -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 profile
curl -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 books
curl -X GET https://bookbounty.yourdomain.com/api/books/featured \
-H "Content-Type: application/json"
# Get top-rated books
curl -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 user
curl -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:

  1. Author Registration:

    • Enable author registration in settings
    • Set up author approval workflow
    • Provide author guidelines
    • Create onboarding documentation
  2. Author Tools:

    • Dashboard for book management
    • Sales analytics if applicable
    • Royalty tracking
    • Reader communication tools
  3. Content Moderation:

    • Review book submissions
    • Check for copyright compliance
    • Verify metadata accuracy
    • Manage content removal requests

Moderating User Reviews

Maintain community standards:

  1. Set review moderation policies
  2. Flag and review reported reviews
  3. Remove inappropriate content
  4. Maintain rating accuracy
  5. Address author disputes professionally

Monitoring Platform Analytics

Track platform performance:

  1. Monitor user growth
  2. Track book upload trends
  3. Analyze search patterns
  4. Monitor reading behavior
  5. 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:

  1. Backup your database and files
  2. Update your Dockerfile to pull latest code
  3. Commit and push to GitHub
  4. Klutch.sh will automatically rebuild
  5. Test all functionality after upgrade
  6. Verify database integrity
  7. 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

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.