Demo / Hosted Version: http://142.93.162.11:8000
(Project is fully dockerized and running on this VPS)
Note: The demo runs on port 8000, so it may not open directly on Firefox or other browsers without specifying the port in the URL.
To access it, usehttp://142.93.162.11:8000.
A Django-based multi-tenant ordering platform where each company manages its own products and orders.
The system enforces data isolation, role-based permissions, soft deletion, CSV export, and includes full Dockerization using MySQL and Gunicorn.
- Introduction
- Features
- Tech Stack
- System Architecture
- Multi-Tenancy Model
- Data Models
- API Endpoints
- Access Control Rules
- Email Logging
- Admin Features
- Demo Data
- Project Structure
- Local Setup (non-Docker)
- Docker Setup & Deployment
- Running Migrations
- Useful Commands
- Notes
This project implements a multi-tenant ordering system in Django where each authenticated user belongs to one company.
Tenants (companies) are logically isolated, ensuring that products and orders of each company remain private to that company.
The API exposes CRUD operations for managing products and orders and supports CSV export and soft deletion.
A simple HTML interface is included at the index page.
- Multi-tenant data isolation (per company)
- Role-based permissions:
- Admin: full access
- Operator: limited order editing
- Viewer: read-only
- Product management with soft deletion
- Order creation with stock checks
- CSV export of orders
- Logging confirmation emails upon successful orders
- Full REST API with Swagger and Redoc documentation
- Django admin customization with export/bulk-actions
- Fully dockerized environment with MySQL & Gunicorn
- Simple HTML interface for product listing and creation
- Python 3.10+
- Django 5.x
- Django REST Framework
- MySQL 5.7
- Gunicorn
- drf-yasg (Swagger / Redoc)
- Docker & Docker Compose
The system consists of:
- A Django web application (REST API + Admin + HTML)
- A MySQL database
- Gunicorn application server
- Optional static serving via Django in development
This project uses shared-database, shared-schema multi-tenancy.
Tenant isolation is enforced through:
- Each user belonging to exactly one company
- All Product and Order objects having a company foreign key
- QuerySets automatically filtering data by the authenticated user’s company
No row belonging to another company is visible or accessible.
- name
- company (one-to-many)
- role:
admin|operator|viewer
u can try users username: admin1 or operator1 or viewer1 password: 1
- company
- name
- price
- stock
- created_by
- created_at (immutable)
- last_updated_at
- is_active (soft delete flag)
- company
- product
- quantity
- created_by
- created_at (immutable)
- status: pending | success | failed
- shipped_at (set automatically when status = success)
GET /api/products/ → List active products for the authenticated user's company
DELETE /api/products/ → Soft delete one or more products (admin only)
POST /api/orders/ → Create orders (one or more)
PATCH /api/orders/<id>/ → Update order (restricted for operator)
PUT /api/orders/<id>/ → Replace order
GET /api/orders/export/ → Export orders as CSV
/swagger/ → Swagger UI
/redoc/ → Redoc UI
/ → Simple HTML page with product form + table
- Data access is always limited to the user's company.
- Viewer users:
- Cannot place orders.
- Operator users:
- Can only modify orders created today.
- Admin users:
- Full access.
- Orders cannot include inactive products.
- Orders cannot be created when requested quantity exceeds stock.
When an order is marked as success, a simulated confirmation email is logged to:
order_confirmations.log
The log includes:
- Order ID
- Company
- User
- Timestamp
- Product details
Log rotation is handled automatically.
- Bulk action to mark selected products as inactive
- Action to export selected orders as CSV
The project includes demo data using Faker.
It generates:
- Companies
- Users (admin / operator / viewer)
- Products
- Orders
This allows testing API behavior easily.
A simplified structure:
project/
settings.py
urls.py
orders/
models.py
views.py
serializers.py
admin.py
urls.py
DTL/index.html
Dockerfile
docker-compose.yml
requirements.txt
README.md
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver
python manage.py seed_data
docker-compose up --build
or for new versions
docker compose up --build
docker compose up
The application will be available at:
http://0.0.0.0:8000
The MySQL server runs on:
localhost:3306
Django reads DB settings from variables defined in docker-compose.yml:
DB_NAME
DB_USER
DB_PASSWORD
DB_HOST
DB_PORT
docker exec -it django_app bash
python manage.py migrate
python manage.py createsuperuser
docker-compose down -v
docker-compose up --build
docker exec -it django_app bash
docker exec -it mysql_db mysql -u root -p
- All services bind to
0.0.0.0 - Data isolation is strictly enforced in all queries
- Stock validation prevents invalid orders
- Nginx can be added later for production deployment
- Swagger and Redoc are enabled for API documentation
End of README.
