A full-stack event booking system with Flask backend, MySQL database, and vanilla JavaScript frontend. This system allows users to browse events, purchase tickets, and manage bookings. It includes optional hotel and travel booking features.
- Project Overview
- Project Structure
- Prerequisites
- Database Setup
- Backend Setup
- Frontend Setup
- Running the Application
- Default Users
- API Endpoints
- Features
- Payment Processing
- Troubleshooting
This is a demo/prototype event booking system with the following components:
- Backend: Flask REST API with MySQL database
- Frontend: Static HTML/CSS/JavaScript pages
- Database: MySQL with connection pooling
- Authentication: JWT-based authentication with password hashing
- Booking System: Transactional booking creation with inventory management
Note: This is a demo system. Card/payment details collected on the frontend are for UI purposes only. No actual payment processing occurs.
.
├── backend/ # Flask backend application
│ ├── app.py # Flask app factory and main entry point
│ ├── config.py # Configuration management
│ ├── requirements.txt # Python dependencies
│ │
│ ├── database/ # Database related files
│ │ ├── schema.sql # Database schema (tables, indexes, FKs)
│ │ ├── seed.sql # Seed data (events, hotels, users, etc.)
│ │ ├── pool.py # MySQL connection pool
│ │ └── generate_seed_passwords.py # Script to generate password hashes
│ │
│ ├── repositories/ # Data access layer (SQL queries)
│ │ ├── user_repository.py
│ │ ├── event_repository.py
│ │ ├── booking_repository.py
│ │ ├── hotel_repository.py
│ │ ├── travel_repository.py
│ │ └── ticket_type_repository.py
│ │
│ ├── services/ # Business logic layer
│ │ ├── auth_service.py
│ │ ├── event_service.py
│ │ ├── booking_service.py
│ │ ├── hotel_service.py
│ │ └── travel_service.py
│ │
│ ├── routes/ # API route handlers
│ │ ├── auth_routes.py # /api/v1/auth/*
│ │ ├── event_routes.py # /api/v1/events/*
│ │ ├── booking_routes.py # /api/v1/bookings/*
│ │ ├── hotel_routes.py # /api/v1/hotels/*
│ │ ├── travel_routes.py # /api/v1/travels/*
│ │ └── admin_routes.py # /api/v1/admin/*
│ │
│ ├── utils/ # Utility functions
│ │ ├── errors.py # Error handling and response formatting
│ │ ├── validators.py # Request validation (Marshmallow schemas)
│ │ ├── decorators.py # Custom decorators (admin_required, etc.)
│ │ └── serializers.py # Datetime/timedelta serialization
│ │
│ └── tests/ # Test suite
│ ├── conftest.py # Pytest configuration and fixtures
│ ├── test_auth.py
│ ├── test_events.py
│ ├── test_bookings.py
│ └── test_admin.py
│
├── frontend/ # Frontend application (static files)
│ ├── pages/ # HTML pages
│ │ ├── index.html # Homepage with event listings
│ │ ├── signin.html # Login page
│ │ ├── createaccount.html # Registration page
│ │ ├── tickets.html # Event details and ticket selection
│ │ ├── purchase.html # Booking checkout
│ │ ├── my-bookings.html # User bookings list
│ │ ├── hotels.html # Hotel listings
│ │ ├── travel.html # Travel options
│ │ ├── order-confirmed.html # Booking confirmation
│ │ └── js/ # JavaScript files
│ │ ├── apiClient.js # API client with fetch wrapper
│ │ └── authNav.js # Dynamic navigation based on auth status
│ │
│ ├── stylecss/ # CSS stylesheets
│ │ ├── index.css
│ │ ├── signin.css
│ │ ├── purchase.css
│ │ └── [other CSS files]
│ │
│ └── images/ # Image assets
│ ├── Blackpink.jpg
│ └── [other image files]
│
├── setup_database_now.ps1 # Automated database setup script (Windows)
├── setup_database.ps1 # Alternative database setup script
└── setup_db_manual.sql # Manual SQL setup script
Before setting up the project, ensure you have the following installed:
- Python 3.8+ with pip
- MySQL 5.7+ or MariaDB 10.3+ (server installed and running)
- MySQL root password (default:
12345as configured in setup scripts) - Git (optional, for version control)
-
Ensure MySQL service is running
- Open Services (
services.msc) and verify "MySQL80" is running - Or start it manually:
net start MySQL80
- Open Services (
-
Run the automated setup script
.\setup_database_now.ps1
This script will:
- Test MySQL connection
- Create the database
encore_db - Load the schema from
backend/database/schema.sql - Load seed data from
backend/database/seed.sql - Verify the setup
Note: The script uses password
12345by default. If your MySQL root password is different, edit the script or use manual setup.If you get an execution policy error:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
-
Open MySQL Workbench
- Launch MySQL Workbench
- Connect to your MySQL server (usually
localhost:3306) - Enter your root password
-
Create Database
- Click the "Create a new schema" button (lightning bolt icon) or press
Ctrl+U - Enter schema name:
encore_db - Set default collation:
utf8mb4_unicode_ci - Click Apply
- Click the "Create a new schema" button (lightning bolt icon) or press
-
Load Schema
- Click File → Open SQL Script
- Navigate to
backend/database/schema.sql - Select
encore_dbfrom the dropdown above the query area - Execute the script: Click the Execute button (lightning bolt icon) or press
Ctrl+Shift+Enter - Verify tables are created in the left sidebar
-
Generate Password Hashes
cd backend python database/generate_seed_passwords.pyYou'll see output like:
Password: password123 Hash: pbkdf2:sha256:600000$abc123xyz... (long string)Copy the hash (the long string starting with
pbkdf2:sha256:) -
Update Seed File
- Open
backend/database/seed.sqlin a text editor - Find the user insert statements (they contain password hashes)
- Replace the placeholder hash with the hash you generated in Step 4
- Replace it for all three users (admin, user1, user2) - they should all use the same hash
- Save the file
- Open
-
Load Seed Data
- In MySQL Workbench, click File → Open SQL Script
- Navigate to
backend/database/seed.sql - Make sure
encore_dbis selected in the dropdown - Execute the script (lightning bolt icon or
Ctrl+Shift+Enter)
-
Create Database
mysql -u root -p
Then in MySQL:
CREATE DATABASE encore_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; EXIT;
-
Generate Password Hashes
cd backend python database/generate_seed_passwords.pyCopy the generated hash.
-
Update Seed File
- Open
backend/database/seed.sql - Replace password hashes with the generated hash for all users
- Save the file
- Open
-
Load Schema and Seed Data
mysql -u root -p encore_db < backend/database/schema.sql mysql -u root -p encore_db < backend/database/seed.sql
The database uses the following default settings:
- Database Name:
encore_db - Host:
localhost - Port:
3306 - User:
root - Password:
12345(configured in setup scripts, change if different) - Character Set:
utf8mb4 - Collation:
utf8mb4_unicode_ci
Note: These settings can be changed in the .env file (see Backend Setup section).
Connect to MySQL and verify:
mysql -u root -p encore_db
-- Check tables exist
SHOW TABLES;
-- Check users are inserted
SELECT email, role FROM users;
-- Check events are inserted
SELECT title, artist FROM events LIMIT 5;You should see:
- 7 tables:
users,events,event_ticket_types,hotels,hotel_room_types,travel_options,bookings - 3 users: admin@encore.com, user1@encore.com, user2@encore.com
- 8 sample events
cd backendWindows:
python -m venv .venv
.venv\Scripts\activatemacOS/Linux:
python -m venv .venv
source .venv/bin/activateYou should see (.venv) prefix in your terminal prompt.
pip install -r requirements.txtThis installs:
- Flask (web framework)
- Flask-CORS (CORS handling)
- Flask-JWT-Extended (JWT authentication)
- PyMySQL (MySQL connector)
- python-dotenv (environment variables)
- marshmallow (request validation)
- werkzeug (password hashing)
- pytest (testing)
Create a .env file in the backend directory:
FLASK_ENV=development
SECRET_KEY=your-secret-key-change-in-production
JWT_SECRET_KEY=your-jwt-secret-key-change-in-production
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=12345
DB_NAME=encore_db
DB_PORT=3306Important:
- Replace
DB_PASSWORDwith your actual MySQL root password if different from12345 - Change
SECRET_KEYandJWT_SECRET_KEYin production to random secure strings
Ensure the database is set up (see Database Setup section above).
python app.pyThe server will start on http://127.0.0.1:5000
You should see output like:
* Running on http://127.0.0.1:5000
* Restarting with stat
* Debugger is active!
* Debugger PIN: xxx-xxx-xxx
Note: Keep this terminal window open. The backend must be running for the frontend to work.
The backend API is available at: http://127.0.0.1:5000/api/v1
The frontend is a static site that can be served using any HTTP server.
-
Open a new terminal window (keep the backend running in the other terminal)
-
Navigate to the frontend directory
cd frontend -
Start the HTTP server
python -m http.server 8000
-
Access the frontend
- Open your browser
- Navigate to:
http://localhost:8000/pages/index.html
If using VS Code:
- Install the "Live Server" extension
- Right-click on any HTML file in
frontend/pages/(e.g.,index.html) - Select "Open with Live Server"
The page will open in your browser with auto-reload enabled.
You can use any static file server to serve the frontend directory:
- Node.js:
npx http-server frontend -p 8000 - PHP:
php -S localhost:8000 -t frontend - Any web server: Configure to serve the
frontenddirectory
The frontend API base URL is configured in frontend/pages/js/apiClient.js:
const API_BASE_URL = 'http://127.0.0.1:5000/api/v1';Make sure the backend is running on port 5000 before using the frontend.
- Pages: All HTML pages are in
frontend/pages/ - CSS: Stylesheets are in
frontend/stylecss/(referenced as../stylecss/from pages) - Images: Images are in
frontend/images/(referenced as../images/from pages) - JavaScript: API client is in
frontend/pages/js/apiClient.js
-
Start MySQL Service (if not running)
net start MySQL80
-
Start Backend (Terminal 1)
cd backend .venv\Scripts\activate # Windows # source .venv/bin/activate # macOS/Linux python app.py
Backend runs on:
http://127.0.0.1:5000 -
Start Frontend (Terminal 2)
cd frontend python -m http.server 8000Frontend accessible at:
http://localhost:8000/pages/index.html -
Open Browser
- Navigate to:
http://localhost:8000/pages/index.html - You should see the homepage with event listings
- Navigate to:
-
Sign In
- Click "Sign in" in the navigation
- Use credentials:
user1@encore.com/password123
-
Browse Events
- Click on any event card on the homepage
-
View Tickets
- On the event page, select a ticket type
- Click "Purchase"
-
Complete Booking
- Enter dummy card details (e.g.,
1234 5678 9012 3456,12/34,123) - Click "Confirm Purchase"
- Note: No actual payment processing occurs (demo system)
- Enter dummy card details (e.g.,
-
View Bookings
- Navigate to "My Bookings" from the navigation
- Your booking should appear
The seed data includes three default users (all with password password123):
| Password | Role | Description | |
|---|---|---|---|
admin@encore.com |
password123 |
Admin | Can manage events, view all bookings |
user1@encore.com |
password123 |
User | Regular user account |
user2@encore.com |
password123 |
User | Regular user account |
Note: Make sure to generate proper password hashes using generate_seed_passwords.py and update seed.sql before running the seed script if you haven't already.
-
POST /api/v1/auth/register- Register a new user{ "email": "user@example.com", "password": "password123" } -
POST /api/v1/auth/login- Login user{ "email": "user@example.com", "password": "password123" }Returns:
{ "access_token": "...", "user": {...} } -
GET /api/v1/auth/me- Get current user info (requires auth)
-
GET /api/v1/events- List events- Query params:
query,city,date_from,date_to,page,page_size - Example:
/api/v1/events?city=London&page=1&page_size=20
- Query params:
-
GET /api/v1/events/{id}- Get single event with ticket types
-
POST /api/v1/bookings- Create booking (requires auth){ "event_id": 1, "ticket_type_id": 1, "quantity": 2 } -
GET /api/v1/bookings- List bookings (user's own, or all if admin)- Query params:
page,page_size
- Query params:
-
GET /api/v1/bookings/{id}- Get single booking -
POST /api/v1/bookings/{id}/cancel- Cancel booking
GET /api/v1/hotels- List hotels- Query params:
city,page,page_size
- Query params:
GET /api/v1/travels- List travel options- Query params:
from_city,to_city,date,type,page,page_size
- Query params:
POST /api/v1/admin/events- Create eventPUT /api/v1/admin/events/{id}- Update eventDELETE /api/v1/admin/events/{id}- Delete eventPOST /api/v1/admin/events/{id}/inventory- Adjust inventory
All protected endpoints require a JWT token in the Authorization header:
Authorization: Bearer <your-jwt-token>
- Layered Architecture: Routes → Services → Repositories → Database
- JWT Authentication: Secure token-based authentication
- Password Hashing: PBKDF2 password hashing using Werkzeug
- Role-Based Access Control: Admin and user roles
- Transactional Bookings: Row-level locking for concurrent booking safety
- Inventory Management: Automatic ticket count updates
- RESTful API: Clean API design with consistent error handling
- CORS Support: Configured for frontend communication
- Input Validation: Marshmallow schemas for request validation
- Error Handling: Consistent JSON error responses
- Dynamic Navigation: Updates based on authentication status
- Event Browsing: Search and filter events
- Ticket Selection: Choose ticket types and quantities
- Booking Management: View and cancel bookings
- Hotel & Travel Options: Optional add-ons for bookings
- Responsive Design: Works on desktop and mobile
- LocalStorage: Token and user info stored in browser
Important: This is a demo/prototype system. No actual payment processing occurs.
- Card details are collected on the frontend (
purchase.html) for UI purposes - Basic format validation is performed (length checks only)
- Booking is created directly in the database with status 'confirmed'
- No payment gateway is called (no Stripe, PayPal, etc.)
- No actual money is charged
- Card details are NOT sent to the backend
- No payment API calls
- No card validation (no Luhn algorithm)
- No transaction records
- Card details are NOT stored in the database
You can use any dummy card data for testing:
- Card Number:
1234 5678 9012 3456(or any 13-19 digit number) - Expiry:
12/34(or any MM/YY format) - CVV:
123(or any 3-4 digit number)
The system will accept these values and create the booking without processing any payment.
Problem: Cannot connect to MySQL server
Solutions:
- Verify MySQL service is running:
net start MySQL80
- Check
.envfile has correct database credentials - Verify database exists:
mysql -u root -p -e "SHOW DATABASES;" - Test connection:
mysql -u root -p encore_db
Problem: Import errors or missing modules
Solutions:
- Ensure virtual environment is activated:
(.venv)should appear in prompt - Reinstall dependencies:
pip install -r requirements.txt - Check Python version:
python --version(should be 3.8+)
Problem: Port 5000 already in use
Solutions:
- Change port in
app.py:app.run(port=5001) - Or kill the process using port 5000:
netstat -ano | findstr :5000 taskkill /PID <PID> /F
Problem: API calls fail with CORS errors or connection refused
Solutions:
- Ensure backend is running on
http://127.0.0.1:5000 - Check browser console for specific errors
- Verify API base URL in
frontend/pages/js/apiClient.jsis correct - Check backend logs for incoming requests
Problem: 401 Unauthorized errors
Solutions:
- Check if token is stored: Open browser DevTools → Application → Local Storage
- If token exists but still getting 401, try logging out and logging in again
- Check backend logs for JWT validation errors
Problem: Bookings created but not showing in "My Bookings" page
Solutions:
- Check browser console (F12) for API errors
- Verify you're logged in with the same user who created the booking
- Check backend logs for booking creation confirmation
- Refresh the page or click "Retry" if error message appears
Problem: Setup script fails
Solutions:
- Ensure MySQL service is running
- Check MySQL installation path in script (default:
C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe) - Verify root password in script matches your MySQL password
- Try manual setup using MySQL Workbench (see Database Setup section)
Problem: Password hash mismatch
Solutions:
- Regenerate password hash:
python backend/database/generate_seed_passwords.py - Update
seed.sqlwith the new hash for all users - Reload seed data:
mysql -u root -p encore_db < backend/database/seed.sql
Problem: Event images show broken image icons
Solutions:
- Check image paths in database:
SELECT image_url FROM events; - Verify images exist in
frontend/images/directory - Check browser console for 404 errors on image requests
- Ensure image URLs in
seed.sqlusefrontend/images/prefix
- Development Only: This is a demo system, not production-ready
- Change Secrets: Update
SECRET_KEYandJWT_SECRET_KEYin production - Password Security: Use strong, unique passwords in production
- HTTPS: Use HTTPS in production for secure communication
- CORS: Restrict CORS origins in production (currently allows all)
The database includes the following tables:
users- User accounts with email, password hash, and roleevents- Event information (title, artist, venue, date, etc.)event_ticket_types- Ticket types for each event (name, price, availability)hotels- Hotel informationhotel_room_types- Room types for each hoteltravel_options- Travel/transportation optionsbookings- User bookings linking events, tickets, hotels, and travel
Run tests with pytest:
cd backend
pytestOr run specific test files:
pytest tests/test_auth.py
pytest tests/test_bookings.py -vThis project is for educational purposes.
- Start MySQL service
- Set up database: Run
.\setup_database_now.ps1or use MySQL Workbench - Set up backend:
cd backend python -m venv .venv .venv\Scripts\activate pip install -r requirements.txt # Create .env file with database credentials python app.py
- Set up frontend (in a new terminal):
cd frontend python -m http.server 8000 - Open browser:
http://localhost:8000/pages/index.html - Login:
user1@encore.com/password123 - Start booking events!
For detailed information about any section, refer to the corresponding section above.