TrustedHostMiddleware was blocking localhost healthchecks from Traefik, causing 400 Bad Request errors. When behind a reverse proxy like Traefik/Coolify, host validation is handled by the proxy itself.
📚 Ebook Coupon Management System
A comprehensive enterprise-grade FastAPI application for managing ebook coupon codes with an admin dashboard interface and translation file management system.
📑 Table of Contents
- Overview
- Features
- Technology Stack
- Project Structure
- Prerequisites
- Installation & Setup
- Environment Configuration
- Running the Application
- API Endpoints
- Admin Dashboard
- Database Schema
- Testing
- Deployment
🎯 Overview
The Ebook Coupon Management System is a production-ready web application designed to manage ebook coupon codes efficiently. It provides a secure admin interface for generating, managing, and tracking coupon usage, along with translation file management capabilities.
Key Highlights:
- ✅ Automatic database initialization on first run
- ✅ Auto-creates admin user from environment variables
- ✅ RESTful API with comprehensive documentation
- ✅ Real-time coupon generation and validation
- ✅ Excel file support for bulk operations
- ✅ Translation file management system
- ✅ Comprehensive test suite included
- ✅ Production-ready logging and error handling
🚀 Features
🔐 Authentication & Authorization
- Secure Admin Login: Session-based authentication with HTTP-only cookies
- Auto Admin Creation: First-time setup automatically creates admin user
- Password Hashing: Bcrypt password encryption
- Logout Functionality: Clean session termination
🎫 Coupon Management
Generate Coupons
- Single Generation: Create one coupon code at a time
- Bulk Generation: Generate multiple coupons in one operation
- Unique Codes: 10-character alphanumeric codes (uppercase)
- Automatic Storage: Codes saved to database with metadata
Manage Coupons
- List All Coupons: Paginated listing with usage statistics
- Search Functionality: Case-insensitive search by coupon code
- Usage Tracking: One time coupon code usage and timestamps
- Delete Coupons: Remove unwanted or expired codes
- Add Manual Codes: Add specific coupon codes manually
Bulk Operations
- Excel Upload: Upload multiple coupons from Excel files (.xlsx, .xls)
- Duplicate Detection: Automatically skips existing codes
- Validation: Ensures data integrity during bulk upload
Coupon Validation
- Code Verification: Check if coupon exists and is valid
- Usage Validation: Prevent reuse of single-use coupons
- Mark as Used: Track when and how coupons are redeemed
🌐 Translation File Management
- Upload Translation Files: Admin can upload Excel translation files
- Download Translations: Retrieve uploaded translation files
- Delete Translations: Remove existing translation files
- Status Check: Verify if translation file exists
- Metadata Storage: Preserves original filename information
- File Validation: Ensures only valid Excel files are accepted
🖥️ Admin Dashboard
- Modern UI: Clean, responsive interface built with vanilla JavaScript
- Real-time Updates: Live data refresh without page reload
- File Upload: Drag-and-drop support for Excel files
- Pagination: Efficient browsing of large coupon lists
- Search Interface: Quick search functionality
- Statistics Display: View total coupons and usage
📊 System Features
- Health Monitoring:
/healthendpoint for system checks - Database Status: Real-time database connection monitoring
- Automatic Migrations: Tables created automatically on startup
- Logging System: Structured JSON logging with rotation
- Error Handling: Comprehensive exception handling
- Request Tracking: Unique request IDs for tracing
🛠️ Technology Stack
Backend
| Technology | Purpose | Version |
|---|---|---|
| FastAPI | Web framework | Latest |
| Uvicorn | ASGI server | Latest |
| SQLAlchemy | ORM | 2.x |
| PostgreSQL | Database | 12+ |
| Pydantic | Data validation | 2.x |
| Passlib | Password hashing | Latest |
| Bcrypt | Encryption | 4.0.1 |
| Python-Jose | JWT handling | Latest |
Frontend
| Technology | Purpose |
|---|---|
| HTML5 | Structure |
| CSS3 | Styling |
| Vanilla JavaScript | Interactivity |
| Fetch API | HTTP requests |
Development & Testing
| Tool | Purpose |
|---|---|
| Pytest | Testing framework |
| HTTPx | Async HTTP client |
| Python-dotenv | Environment management |
📁 Project Structure
ebook_extension-feature-admin-dashboard/
│
├── admin-backend/ # Backend API application
│ ├── models/ # Database models
│ │ ├── user.py # Admin user model
│ │ └── coupon.py # Coupon model
│ │
│ ├── routes/ # API routes
│ │ └── auth.py # All API endpoints
│ │
│ ├── utils/ # Utility modules
│ │ ├── auth.py # Authentication utilities
│ │ ├── coupon_utils.py # Coupon generation
│ │ ├── exceptions.py # Custom exceptions
│ │ ├── logger.py # Logging configuration
│ │ ├── template_loader.py # Template utilities
│ │ └── timezone_utils.py # Timezone handling
│ │
│ ├── tests/ # Test suite
│ │ ├── conftest.py # Test configuration
│ │ ├── test_auth_routes.py # Auth endpoint tests
│ │ ├── test_coupon_routes.py # Coupon endpoint tests
│ │ ├── test_main.py # Main app tests
│ │ ├── test_models.py # Model tests
│ │ ├── test_schemas.py # Schema tests
│ │ ├── test_translation_routes.py # Translation tests
│ │ └── test_utils.py # Utility tests
│ │
│ ├── logs/ # Application logs
│ │ ├── app.log # General logs
│ │ └── error.log # Error logs
│ │
│ ├── translationfile/ # Translation storage
│ │ └── translation.xlsx # Uploaded translation file
│ │
│ ├── main.py # FastAPI application
│ ├── init_db.py # Database initialization
│ ├── schemas.py # Pydantic schemas
│ ├── manage_test_db.py # Test database manager
│ └── pytest.ini # Pytest configuration
│
├── admin-frontend/ # Frontend files
│ ├── admin_login.html # Login page
│ ├── admin_login.js # Login logic
│ ├── admin_dashboard.html # Dashboard UI
│ └── admin_dashboard.js # Dashboard logic
│
├── .env.example # Environment template
├── .gitignore # Git ignore rules
├── requirements.txt # Python dependencies
├── README.md
└── start.sh # Startup script
📋 Prerequisites
Before installing, ensure you have the following:
- Python: Version 3.10 or higher
- PostgreSQL: Version 12 or higher
- pip: Python package manager
- Virtual Environment:
venvorvirtualenv - Git: For cloning the repository
System Requirements
- OS: Linux, macOS, or Windows
- RAM: Minimum 2GB
- Disk Space: Minimum 500MB
💻 Installation & Setup
Step 1: Clone the Repository
git clone <repository-url>
cd ebook_extension-feature-admin-dashboard
Step 2: Create Virtual Environment
# Create virtual environment
python3 -m venv .venv
# Activate virtual environment
# On Linux/Mac:
source .venv/bin/activate
# On Windows:
.venv\Scripts\activate
Step 3: Install Dependencies
pip install --upgrade pip
pip install -r requirements.txt
Step 4: Set Up PostgreSQL Database
Create Database
# Option 1: Using psql
sudo -u postgres psql -c "CREATE DATABASE ebook_db;"
# Option 2: Using createdb
sudo -u postgres createdb ebook_db
# Option 3: Connect to PostgreSQL and create manually
sudo -u postgres psql
postgres=# CREATE DATABASE ebook_db;
postgres=# \q
Verify Database Creation
sudo -u postgres psql -c "\l" | grep ebook_db
Step 5: Configure Environment Variables
# Copy example environment file
cp .env.example .env
# Edit with your settings
nano .env # or your preferred editor
Required Configuration:
- Update
DATABASE_URLif using different credentials - Change
ADMIN_PASSWORDfrom default - Generate strong
SECRET_KEYfor production
Step 6: Initialize Database (Automatic)
The application automatically:
- Creates all required tables on first run
- Creates admin user from
.envcredentials - Validates database connection
No manual database setup required!
⚙️ Environment Configuration
Environment Variables Explained
Create a .env file in the project root with these variables:
Database Configuration
# PostgreSQL connection string
DATABASE_URL=postgresql://username:password@host:port/database
# Test database (for running tests)
TEST_DATABASE_URL=postgresql://username:password@host:port/test_database
Security Configuration
# Secret key for JWT and session encryption
# Generate with: python -c "import secrets; print(secrets.token_urlsafe(32))"
SECRET_KEY=your-super-secret-key-change-this-in-production
# Debug mode (set to false in production)
DEBUG=true
# Environment: development, staging, production
ENVIRONMENT=development
Admin Credentials
# Auto-created admin user on first run
# IMPORTANT: Change these before production deployment!
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin@123
Application Configuration
# Application details
APP_NAME=Ebook Coupon Management System
APP_VERSION=1.0.0
# CORS allowed origins (comma-separated)
CORS_ORIGINS=http://localhost:3000,http://localhost:8000,http://127.0.0.1:8000
# Trusted hosts
TRUSTED_HOSTS=*
Logging Configuration
# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_LEVEL=INFO
# Log file paths (relative to admin-backend)
LOG_FILE=logs/app.log
ERROR_LOG_FILE=logs/error.log
File Upload Configuration
# Maximum file size in bytes (10MB default)
MAX_FILE_SIZE=10485760
# Allowed file types
ALLOWED_FILE_TYPES=.xlsx,.xls
Server Configuration
# Server binding
HOST=0.0.0.0
PORT=8000
Security Best Practices
🔒 For Production:
- Generate strong
SECRET_KEY:python -c "import secrets; print(secrets.token_urlsafe(32))" - Change
ADMIN_PASSWORDto a strong password (12+ characters) - Set
DEBUG=false - Set
ENVIRONMENT=production - Update
CORS_ORIGINSto specific domains
🚀 Running the Application
Method 1: Using Startup Script (Recommended)
./start.sh
This script automatically:
- Checks for
.envfile (creates from example if missing) - Activates virtual environment
- Installs/updates dependencies
- Starts the application with auto-reload
Method 2: Manual Start
# Navigate to backend directory
cd admin-backend
# Activate virtual environment
source ../.venv/bin/activate
# Start the server
uvicorn main:app --reload --host 0.0.0.0 --port 8000
Verify Application is Running
# Check health endpoint
curl http://localhost:8000/health
# Expected response:
# {
# "status": "healthy",
# "timestamp": 1762246309.91,
# "version": "1.0.0",
# "environment": "development",
# "database_status": "connected"
# }
Access Points
| Service | URL | Description |
|---|---|---|
| API | http://localhost:8000 | Main API endpoint |
| Admin Login | http://localhost:8000/login | Admin login page |
| Admin Dashboard | http://localhost:8000/ | Main dashboard (requires login) |
| API Docs | http://localhost:8000/docs | Swagger UI documentation |
| ReDoc | http://localhost:8000/redoc | Alternative API docs |
| Health Check | http://localhost:8000/health | System health status |
Default Login Credentials
Username: admin
Password: admin@123
📡 API Endpoints
Authentication Endpoints
Admin Login
POST /admin/login
Content-Type: application/json
{
"username": "admin",
"password": "admin@123"
}
Response: 200 OK
{
"status": "success"
}
Admin Logout
POST /admin/logout
Response: 200 OK
{
"status": "success"
}
Coupon Management Endpoints
Generate Single Coupon
POST /generate
Content-Type: application/x-www-form-urlencoded
mode=single
Response: 200 OK
{
"code": "A1B2C3D4E5"
}
Generate Bulk Coupons
POST /generate
Content-Type: application/x-www-form-urlencoded
mode=bulk&count=100
Response: 200 OK
{
"codes": ["CODE1", "CODE2", ...]
}
List All Coupons
GET /list?page=1&limit=20
Response: 200 OK
{
"codes": [
{
"code": "A1B2C3D4E5",
"used_at": "2025-11-04 10:30:00 CEST",
"usage_count": 1
}
],
"total": 100,
"page": 1,
"limit": 20,
"total_pages": 5
}
Search Coupons
GET /search-codes?query=A1B2
Response: 200 OK
[
{
"code": "A1B2C3D4E5",
"used": 1,
"usage_count": 1,
"used_at": "2025-11-04 10:30:00 CEST"
}
]
Check Specific Coupon
GET /check-code/A1B2C3D4E5
Response: 200 OK
{
"code": "A1B2C3D4E5",
"used": 1
}
Verify and Use Coupon
POST /verify
Content-Type: application/json
{
"code": "A1B2C3D4E5"
}
Response: 200 OK
{
"message": "Coupon verified",
"used_at": "2025-11-04 10:30:00 CEST"
}
Add Manual Coupon
POST /add-code
Content-Type: application/json
{
"code": "CUSTOM123",
"usage": 0
}
Response: 200 OK
{
"message": "Code added successfully"
}
Delete Coupon
DELETE /delete-code/A1B2C3D4E5
Response: 200 OK
{
"message": "Code deleted successfully"
}
Upload Coupons from Excel
POST /upload-codes
Content-Type: application/json
{
"codes": [
{"code": "CODE1", "usage": 0},
{"code": "CODE2", "usage": 1}
]
}
Response: 200 OK
{
"uploaded": 2,
"skipped": 0,
"total": 2
}
Translation File Endpoints
Upload Translation File
POST /upload-translations
Content-Type: multipart/form-data
file: <translation.xlsx>
Response: 200 OK
{
"message": "Translation file uploaded successfully",
"filename": "translation.xlsx"
}
Download Translation File
GET /download-translation
Response: 200 OK
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="translation.xlsx"
Delete Translation File
DELETE /delete-translation
Response: 200 OK
{
"message": "Translation file deleted successfully"
}
Check Translation Status
GET /translations/status
Response: 200 OK
{
"file_exists": true,
"file_name": "translation.xlsx"
}
Get Latest Translation (Legacy)
GET /translations/latest
Response: 200 OK
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
System Endpoints
Health Check
GET /health
Response: 200 OK
{
"status": "healthy",
"timestamp": 1762246309.91,
"version": "1.0.0",
"environment": "development",
"database_status": "connected"
}
Root Endpoint
GET /
Response: 302 Found
Location: /login (if not logged in)
🖥️ Admin Dashboard
Features
-
Login Page (
/login)- Secure authentication form
- Session-based login
- Error handling
-
Dashboard (
/)- Coupon generation (single/bulk)
- Coupon listing with pagination
- Search functionality
- File upload for bulk operations
- Translation file management
- Statistics display
Usage
- Login: Navigate to
http://localhost:8000/login - Enter Credentials: Use admin username and password from
.env - Dashboard Access: Automatically redirected to dashboard on success
- Generate Coupons: Use the generation form
- Upload Files: Drag and drop or browse for Excel files
- Manage Translations: Upload, download, or delete translation files
🗄️ Database Schema
Table: admin_users
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | INTEGER | PRIMARY KEY | Auto-increment ID |
| username | STRING | UNIQUE, NOT NULL | Admin username |
| password_hash | STRING | NOT NULL | Bcrypt hashed password |
| created_at | DATETIME | DEFAULT NOW | Account creation timestamp |
Table: coupon_codes
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | INTEGER | PRIMARY KEY | Auto-increment ID |
| code | STRING | UNIQUE | Coupon code |
| usage_count | INTEGER | DEFAULT 0 | Number of times used |
| created_at | DATETIME | DEFAULT NOW | Creation timestamp |
| used_at | DATETIME | NULLABLE | Last usage timestamp |
Timezone: All timestamps use Europe/Bratislava timezone for creation, Asia/Kolkata for usage.
🧪 Testing
Run All Tests
cd admin-backend
source ../.venv/bin/activate
pytest
Run Specific Test Files
# Test auth routes
pytest tests/test_auth_routes.py
# Test coupon routes
pytest tests/test_coupon_routes.py
# Test models
pytest tests/test_models.py
Run with Coverage
pytest --cov=. --cov-report=html
Test Database
Tests use a separate test database configured in TEST_DATABASE_URL.
🚢 Production Deployment
Pre-Deployment Checklist
- Set
DEBUG=false - Set
ENVIRONMENT=production - Change
ADMIN_PASSWORDto strong password - Generate secure
SECRET_KEY - Update
CORS_ORIGINSwith production domains - Configure PostgreSQL with SSL
- Set up Nginx reverse proxy
- Configure SSL/TLS certificates
- Enable firewall rules
- Set up automated backups
- Configure monitoring and logging
Production Environment Variables
# Database
DATABASE_URL=postgresql://dbuser:strong_password@localhost:5432/ebook_prod
# Security
SECRET_KEY=<generate-with: python -c "import secrets; print(secrets.token_urlsafe(32))">
DEBUG=false
ENVIRONMENT=production
# Admin (change after first login!)
ADMIN_USERNAME=admin
ADMIN_PASSWORD=<strong-password-here>
# CORS
CORS_ORIGINS=https://yourdomain.com,https://www.yourdomain.com
TRUSTED_HOSTS=yourdomain.com,www.yourdomain.com
# Application
APP_NAME=Ebook Coupon Management System
APP_VERSION=1.0.0
LOG_LEVEL=WARNING
# Server
HOST=0.0.0.0
PORT=8000
Deployment with Systemd
-
Install Gunicorn
pip install gunicorn -
Create Systemd Service File
sudo nano /etc/systemd/system/ebook-api.service[Unit] Description=Ebook Coupon Management System API After=network.target postgresql.service [Service] Type=notify User=www-data Group=www-data WorkingDirectory=/var/www/ebook_extension-feature-admin-dashboard/admin-backend Environment="PATH=/var/www/ebook_extension-feature-admin-dashboard/.venv/bin" EnvironmentFile=/var/www/ebook_extension-feature-admin-dashboard/.env ExecStart=/var/www/ebook_extension-feature-admin-dashboard/.venv/bin/gunicorn \ -w 4 \ -k uvicorn.workers.UvicornWorker \ --bind 0.0.0.0:8000 \ main:app Restart=always [Install] WantedBy=multi-user.target -
Enable and Start Service
sudo systemctl daemon-reload sudo systemctl enable ebook-api sudo systemctl start ebook-api sudo systemctl status ebook-api
Nginx Reverse Proxy
-
Install Nginx
sudo apt-get update sudo apt-get install nginx -
Create Nginx Configuration
sudo nano /etc/nginx/sites-available/ebook-apiupstream ebook_backend { server 127.0.0.1:8000; } server { listen 80; server_name yourdomain.com www.yourdomain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name yourdomain.com www.yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; add_header Strict-Transport-Security "max-age=31536000" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; client_max_body_size 10M; location / { proxy_pass http://ebook_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /static { alias /var/www/ebook_extension-feature-admin-dashboard/admin-frontend; expires 30d; } } -
Enable Site
sudo ln -s /etc/nginx/sites-available/ebook-api /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl restart nginx
Logs and Debugging
# Application logs
tail -f admin-backend/logs/app.log
# Error logs
tail -f admin-backend/logs/error.log
# Search for errors
grep -i error admin-backend/logs/app.log
# Enable debug mode
DEBUG=true uvicorn main:app
Quick Reference Commands
# Start application (development)
./start.sh
# Start application (production)
gunicorn -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 main:app
# Stop application
pkill -f "uvicorn main:app"
# Check if running
ps aux | grep uvicorn
# View health status
curl http://localhost:8000/health
# Database operations
sudo -u postgres psql -d ebook_db
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- FastAPI team for the excellent framework
- SQLAlchemy team for the powerful ORM
- All contributors and users
📞 Support
For support and questions:
- Review application logs:
admin-backend/logs/ - Check troubleshooting section above
- Open an issue on GitHub