A comprehensive food delivery platform built with Flask, featuring role-based access for customers and restaurant owners, intelligent menu recommendations, and comprehensive order management.
- Prerequisites
- Installation
- Database Setup
- Running the Application
- Testing
- Logging
- System Assumptions
- Python: 3.8 or higher
- Python 3.8+
- pip (Python package installer)
- Git (for version control)
git clone <repository-url>
cd Exit_Test# Create virtual environment
python -m venv venv
# Activate virtual environment
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activate# Install required packages
pip install -r requirements.txtCreate a .env file in the root directory:
# Copy example environment file
copy .env.example .envEdit .env file with your configuration:
SECRET_KEY=your-secret-key-here
FLASK_ENV=development
FLASK_DEBUG=TrueImportant: Replace your-secret-key-here with a secure random string.
# Run the run.py with "seed" argument for seeding script
python run.py seedThis will:
- Create all necessary database tables
- Load sample users, restaurants, menu items, and orders
- Set up relationships between entities
- Create log files directory
Check that the database file was created:
- Location:
justeat/databases/site.db - Size: Should be several MB after seeding
The seeded database includes:
- Customers: Alice, Diana
- Restaurant Owners: Bob, Charlie, Ethan
- Default Password:
password(hashed with bcrypt)
- Bob's Burgers (Owner: Bob)
- The Masala Mill (Owner: Charlie)
- Ethan's Eatery (Owner: Ethan)
- Various cuisines: Italian, Indian, American
- Different diet types: Vegetarian, Non-Vegetarian, Vegan
- Price range: $5-$25
- Special items and discounts
- Sample order history
- Customer reviews and ratings
- Feedback and responses
# Run the Flask development server
python run.pyThe application will start on http://localhost:5000
# Set production environment
set FLASK_ENV=production
# Linux/Mac: export FLASK_ENV=production
# Run with production settings
python run.py- Browse restaurants and menu items
- Add items to cart and checkout
- View order history
- Leave reviews and feedback
- Manage dietary preferences
- Get personalized recommendations
- Register and manage restaurants
- Add/edit/delete menu items
- View and manage orders
- Respond to customer feedback
- Track restaurant performance
# Run all tests with verbose output
pytest -v
# Run tests with coverage report
pytest --cov=justeat --cov-report=html# Test routes
pytest tests/test_routes.py -v
# Test services
pytest tests/test_services.py -v
# Test ui
pytest tests/test_ui.py -v
- Directory:
logs/
# Check if database file exists
ls justeat/databases/site.db
# Recreate database
rm justeat/databases/site.db
python seed_db.py# Ensure virtual environment is activated
venv\Scripts\activate.bat # Windows
source venv/bin/activate # Linux/Mac
# Reinstall dependencies
pip install -r requirements.txtThe JustEat application follows a modular Flask architecture with clear separation of concerns:
Exit_Test/ # Project root directory
├── justeat/ # Main application package
│ ├── __init__.py # Flask app factory and initialization
│ ├── config.py # Application configuration settings
│ ├── models.py # SQLAlchemy database models
│ ├── forms.py # WTForms form definitions
│ ├── databases/ # Database-related modules
│ │ ├── __init__.py
│ │ ├── cursor.py # Custom database cursor class
│ │ └── site.db # SQLite database file
│ ├── routes/ # Flask route blueprints
│ │ ├── __init__.py
│ │ ├── user.py # Authentication routes (login/logout)
│ │ ├── customer.py # Customer-specific routes
│ │ └── restaurant_owner.py # Restaurant owner routes
│ ├── services/ # Business logic layer
│ │ ├── __init__.py
│ │ ├── user.py # User management services
│ │ ├── customer.py # Customer business logic
│ │ └── restaurant_owner.py # Restaurant owner business logic
│ ├── templates/ # Jinja2 HTML templates
│ │ ├── layout.html # Base template with navigation
│ │ ├── user/ # Unauthenticated user templates
│ │ │ ├── home.html # Landing page
│ │ │ ├── login.html # Login form
│ │ │ └── profile.html # User profile
│ │ ├── customer/ # Customer-specific templates
│ │ │ ├── home.html # Customer dashboard
│ │ │ ├── display_restaurants.html # Restaurant listing
│ │ │ ├── display_restaurant.html # Individual restaurant view
│ │ │ ├── display_cart.html # Shopping cart
│ │ │ ├── display_orders.html # Order history
│ │ │ ├── display_order.html # Individual order details
│ │ │ ├── edit_preferences.html # User preferences
│ │ │ ├── add_review.html # Add review form
│ │ │ ├── display_reviews.html # Reviews listing
│ │ │ ├── add_feedback.html # Add feedback form
│ │ │ └── display_feedbacks.html # Feedback listing
│ │ └── restaurant_owner/ # Restaurant owner templates
│ │ ├── home.html # Owner dashboard
│ │ ├── register_restaurant.html # Restaurant registration
│ │ ├── display_restaurant.html # Restaurant management
│ │ ├── add_item.html # Add menu item
│ │ ├── display_item.html # Menu item details
│ │ ├── edit_item.html # Edit menu item
│ │ ├── display_orders.html # Order management
│ │ ├── display_order.html # Individual order details
│ │ ├── display_feedbacks.html # Customer feedback
│ │ └── reply_feedback.html # Reply to feedback
│ └── static/ # Static assets
│ ├── css/
│ │ └── style.css # Custom CSS styles
│ ├── js/
│ │ └── scripts.js # Custom JavaScript
│ └── seed_data.json # Sample data for database seeding
├── logs/ # Application log files
│ ├── justeat.log
├── venv/ # Python virtual environment
│ ├── Scripts/ # Windows activation scripts
│ ├── Lib/ # Python packages
│ └── pyvenv.cfg # Virtual environment config
├── run.py # Application entry point
├── seed_db.py # Database seeding script
└── README.md # This file
__init__.py: Flask application factory, extension initialization, and logging setupconfig.py: Configuration settings including database URI and secret keymodels.py: SQLAlchemy ORM models for all database entitiesforms.py: WTForms form classes for data validation and CSRF protection
cursor.py: Custom database abstraction layer with CRUD operationssite.db: SQLite database file containing all application data
user.py: Authentication routes (login, logout, profile management)customer.py: Customer-specific routes (browsing, ordering, reviews)restaurant_owner.py: Restaurant owner routes (management, orders, feedback)
user.py: User management, authentication, and session handlingcustomer.py: Customer business logic, recommendations, and cart managementrestaurant_owner.py: Restaurant management and order processing
layout.html: Base template with navigation, flash messages, and common elementsuser/: Templates for unauthenticated users (landing, login, profile)customer/: Customer-specific templates (dashboard, ordering, reviews)restaurant_owner/: Restaurant owner templates (management, orders, feedback)
css/style.css: Custom CSS for styling and responsive designjs/scripts.js: JavaScript for interactive features and form handlingseed_data.json: Sample data for database initialization
justeat.log: Comprehensive application logs (DEBUG, INFO, WARNING, ERROR, CRITICAL)
run.py: Main application entry point for development serverseed_db.py: Database initialization and sample data loading
The JustEat application uses SQLite database with a comprehensive schema designed for a food delivery platform. The database follows normalized design principles with proper relationships and constraints.
The detailed diagram is in ER_Diagram.html
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ User │ │ Restaurant │ │ MenuItem │
├─────────────┤ ├──────────────┤ ├─────────────┤
│ id (PK) │◄───┤ id (PK) │◄───┤ id (PK) │
│ role │ │ owner_id (FK)│ │ restaurant_id(FK)│
│ name │ │ name │ │ diet_id (FK)│
│ email │ │ location │ │ cuisine_id(FK)│
│ password │ └──────────────┘ │ name │
└─────────────┘ │ price │
│ │ description │
│ │ is_special │
│ │ discount │
│ │ order_count │
│ └─────────────┘
│ │
│ ┌─────────────┐
│ │ OrderItem │
│ ├─────────────┤
│ │ item_id (FK)│
│ │ order_id(FK)│
│ │ quantity │
│ └─────────────┘
│ │
│ ┌─────────────┐
│ │ Order │
│ ├─────────────┤
│ │ id (PK) │
│ │ restaurant_id(FK)│
│ │ customer_id(FK)│
│ │ total_cost │
│ │ datetime │
│ │ status │
│ └─────────────┘
│
│ ┌─────────────┐
│ │ Review │
│ ├─────────────┤
│ │ id (PK) │
│ │ customer_id(FK)│
│ │ restaurant_id(FK)│
│ │ cuisine_id(FK)│
│ │ rating │
│ │ review │
│ └─────────────┘
│
│ ┌─────────────┐
│ │ Feedback │
│ ├─────────────┤
│ │ id (PK) │
│ │ customer_id(FK)│
│ │ restaurant_id(FK)│
│ │ feedback │
│ │ reply │
│ └─────────────┘
│
│ ┌─────────────┐
│ │ Diet │
│ ├─────────────┤
│ │ id (PK) │
│ │ name │
│ └─────────────┘
│
│ ┌─────────────┐
│ │ Cuisine │
│ ├─────────────┤
│ │ id (PK) │
│ │ name │
│ └─────────────┘
Purpose: Stores user account information for both customers and restaurant owners.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique user identifier |
role |
INTEGER | NOT NULL | User role (0=Customer, 1=Restaurant Owner) |
name |
VARCHAR(20) | NOT NULL | User's display name |
email |
VARCHAR(50) | NOT NULL | User's email address (unique) |
password |
VARCHAR(60) | NOT NULL | Bcrypt hashed password |
Relationships:
- One-to-Many with
Restaurant(restaurant owners) - One-to-Many with
Order(customers) - Many-to-Many with
Diet(diet preferences) - Many-to-Many with
Cuisine(cuisine preferences) - Many-to-Many with
Restaurant(favorite restaurants)
Purpose: Stores restaurant information and links to owners.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique restaurant identifier |
owner_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to User table |
name |
VARCHAR(20) | NOT NULL | Restaurant name |
location |
INTEGER | NOT NULL | Location code/zip code |
Relationships:
- Many-to-One with
User(restaurant owner) - One-to-Many with
MenuItem(menu items) - One-to-Many with
Order(orders placed) - Many-to-Many with
User(favorite restaurants)
Purpose: Stores dietary preference categories.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique diet identifier |
name |
VARCHAR(20) | NOT NULL | Diet type name (e.g., Vegetarian, Vegan) |
Relationships:
- One-to-Many with
MenuItem(menu items with this diet) - Many-to-Many with
User(user diet preferences)
Purpose: Stores cuisine type categories.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique cuisine identifier |
name |
VARCHAR(20) | NOT NULL | Cuisine type name (e.g., Italian, Indian) |
Relationships:
- One-to-Many with
MenuItem(menu items of this cuisine) - Many-to-Many with
User(user cuisine preferences)
Purpose: Stores individual menu items with pricing and categorization.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique menu item identifier |
restaurant_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to Restaurant table |
diet_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to Diet table |
cuisine_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to Cuisine table |
name |
VARCHAR(20) | NOT NULL | Menu item name |
price |
INTEGER | NOT NULL | Price in cents |
description |
TEXT | NOT NULL, DEFAULT "No description" | Item description |
is_special |
BOOLEAN | NOT NULL, DEFAULT FALSE | Special item flag |
discount |
INTEGER | NOT NULL, DEFAULT 0 | Discount percentage (0-100) |
order_count |
INTEGER | NOT NULL, DEFAULT 0 | Number of times ordered |
Constraints:
discount >= 0 AND discount <= 100
Relationships:
- Many-to-One with
Restaurant(belongs to restaurant) - Many-to-One with
Diet(diet type) - Many-to-One with
Cuisine(cuisine type) - One-to-Many with
OrderItem(ordered items)
Purpose: Stores order information and status.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique order identifier |
restaurant_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to Restaurant table |
customer_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to User table |
total_cost |
INTEGER | NOT NULL | Total order cost in cents |
datetime |
DATETIME | NOT NULL, DEFAULT NOW() | Order timestamp |
status |
ENUM | NOT NULL | Order status (CART, ORDERED, READY, DELIVERED, CANCELLED, REJECTED) |
Order Status Values:
CART: Items in shopping cartORDERED: Order placed, awaiting confirmationREADY: Order ready for pickup/deliveryDELIVERED: Order completedCANCELLED: Order cancelled by customerREJECTED: Order rejected by restaurant
Relationships:
- Many-to-One with
Restaurant(order from restaurant) - Many-to-One with
User(customer who placed order) - One-to-Many with
OrderItem(items in order)
Purpose: Junction table for order-item relationships with quantities.
| Column | Type | Constraints | Description |
|---|---|---|---|
item_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to MenuItem table |
order_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to Order table |
quantity |
INTEGER | NOT NULL, DEFAULT 0 | Quantity of item in order |
Relationships:
- Many-to-One with
MenuItem(menu item) - Many-to-One with
Order(order containing item)
Purpose: Stores customer reviews for restaurants or cuisines.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique review identifier |
customer_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to User table |
restaurant_id |
INTEGER | NULL, FOREIGN KEY | Reference to Restaurant table |
cuisine_id |
INTEGER | NULL, FOREIGN KEY | Reference to Cuisine table |
rating |
INTEGER | NOT NULL | Rating (1-5 stars) |
review |
TEXT | NULL | Review text |
Constraints:
rating > 0 AND rating <= 5- Either
restaurant_idorcuisine_idmust be provided
Relationships:
- Many-to-One with
User(reviewer) - Many-to-One with
Restaurant(restaurant being reviewed) - Many-to-One with
Cuisine(cuisine being reviewed)
Purpose: Stores customer feedback and restaurant owner replies.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
INTEGER | PRIMARY KEY, AUTO_INCREMENT | Unique feedback identifier |
customer_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to User table |
restaurant_id |
INTEGER | NOT NULL, FOREIGN KEY | Reference to Restaurant table |
feedback |
TEXT | NOT NULL | Customer feedback text |
reply |
TEXT | NULL | Restaurant owner reply |
Relationships:
- Many-to-One with
User(feedback author) - Many-to-One with
Restaurant(restaurant receiving feedback)
Purpose: Many-to-many relationship between users and their favorite restaurants.
| Column | Type | Constraints | Description |
|---|---|---|---|
customer_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to User table |
restaurant_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to Restaurant table |
Purpose: Many-to-many relationship between users and their favorite cuisines.
| Column | Type | Constraints | Description |
|---|---|---|---|
customer_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to User table |
cuisine_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to Cuisine table |
Purpose: Many-to-many relationship between users and their dietary preferences.
| Column | Type | Constraints | Description |
|---|---|---|---|
customer_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to User table |
diet_id |
INTEGER | PRIMARY KEY, FOREIGN KEY | Reference to Diet table |
- All tables have auto-incrementing integer primary keys
- Composite primary keys for association tables
- All foreign key relationships have proper referential integrity
- Cascade delete for order items when orders are deleted
- Foreign key constraints enabled via SQLite PRAGMA
- MenuItem.discount: Must be between 0 and 100
- Review.rating: Must be between 1 and 5
- User email addresses are unique
- Composite unique constraints on association tables
# Create migration
flask db migrate -m "Description of changes"
# Apply migration
flask db upgradeThis document outlines all the assumptions made in the JustEat application design and implementation.
- User Roles: Only two user roles exist - Customer (role=0) and Restaurant Owner (role=1)
- Authentication: All users must be authenticated to access application features
- Password Security: Default passwords are 'password' or 'password2' for all seed users
- User Names: User names are limited to 20 characters maximum
- Email Validation: Email addresses are limited to 50 characters maximum
- Password Storage: Passwords are hashed using bcrypt with 60-character storage limit
- New Item Recommendations: There will always be items that the customer has not tried
- Recommendation Limit: Maximum 10 items are recommended to users
- Preference Scoring: Items are scored based on user's favorite restaurants, cuisines, and diets
- Random Fallback: If no preferences exist, 10 random items are selected
- Item Availability: All menu items are always available for recommendation
- Order Status: Orders have predefined statuses defined in
OrderStatusclass fromjusteat.models.py - Cart Initialization: Every customer gets a cart order automatically created upon login
- Order Items: Order items are linked to specific menu items and quantities
- Order Totals: Order totals are calculated based on item prices and quantities
- Order History: All orders are permanently stored and accessible
- Restaurant Ownership: Each restaurant has exactly one owner
- Menu Items: Restaurants can have multiple menu items
- Item Categories: Every menu item must have a diet type and cuisine type
- Price Storage: Prices are stored as integers (assuming cents or fixed decimal places)
- Discount Range: Discounts must be between 0-100%
- Special Items: Items can be marked as special (boolean flag)
- Database Type: SQLite database is used for all environments
- Foreign Keys: Foreign key constraints are enabled via PRAGMA
- Table Relationships: Many-to-many relationships use association tables
- Data Integrity: All required fields are non-nullable
- ID Generation: All primary keys are auto-incrementing integers
- String Lengths:
- User names: 20 characters max
- Email addresses: 50 characters max
- Menu item names: 20 characters max
- Restaurant names: 20 characters max
- Diet names: 20 characters max
- Cuisine names: 20 characters max
- Numeric Ranges:
- Discounts: 0-100%
- Prices: Positive integers
- Order counts: Non-negative integers
- User-Restaurant: One-to-many (one owner, many restaurants)
- User-Orders: One-to-many (one user, many orders)
- Restaurant-MenuItems: One-to-many (one restaurant, many items)
- Order-OrderItems: One-to-many (one order, many items)
- User Preferences: Many-to-many (users can have multiple favorites)