Skip to content

Repository files navigation

ShopHive — E-commerce Backend

A Django REST Framework backend for a single-vendor e-commerce platform. It exposes a JSON API consumed by a separate frontend (single-vendor-ecommerce-front-end) and covers the typical online-store domain: catalog, cart, coupons, wishlists, addresses, orders, Stripe checkout, role-based admin access, and rich-text legal pages.

The Django project package is named shophive and is run from manage.py.


Features

Verified from the source in this repository:

  • JWT-based authentication with djangorestframework-simplejwt (1440-minute access tokens, 1-day refresh tokens) — see shophive/settings.py:234-259.
  • Custom user model keyed by email, with phone number (via django-phonenumber-field), profile image, and role — users/models.py.
  • OTP-based flows for password reset, email change, and phone-number change, delivered via SMTP — users/views.py.
  • Role-Based Access Control using Module → Permission → Role models — roles/models.py.
  • Product catalog with categories (self-referential tree), variants (size + hex color via django-colorfield), per-variant images, size guides, and reviews — products/models.py.
  • Rich-text content for product descriptions and legal pages via django-tinymceproducts/models.py, legal_policies/models.py.
  • Cart with auto-calculated subtotal, 10% tax, flat shipping (150), coupon discounts (percentage / fixed with max cap) — cart/models.py.
  • Coupons with category scoping, validity windows, min purchase, and max discount caps — coupons/models.py.
  • Wishlists and multi-address support (with a single-default-address invariant) — wishlists/models.py, address/models.py.
  • Orders with auto-generated ORD-<timestamp>-<random> numbers, multiple statuses, Cash-on-Delivery and Stripe checkout sessions — orders/models.py, orders/views.py.
  • Stripe Checkout integration including session creation, PaymentIntents, a payment-success endpoint, and a webhook handler for checkout.session.completedorders/views.py.
  • Banners module for marketing assets with audience (customer / merchant) and status toggles — banners/models.py.
  • Search, filter, ordering, pagination baked into the product API (DjangoFilterBackend + SearchFilter + OrderingFilter).
  • Custom DRF pagination with page_size query param up to 100 — common/pagination.py.
  • Custom exception handler that normalizes DRF/JWT/Validation errors into { "message": ... }shophive/exceptions.py.
  • Custom 404/500 JSON handlersshophive/views.py.
  • UUID primary keys and created_at/updated_at timestamps on every model via a shared BaseModelcommon/model.py.
  • File logging to logs/django_debug.log (directory auto-created on startup).

Tech Stack

Layer Tooling
Language Python 3 (3.10+ recommended)
Framework Django 5.0.6
API Django REST Framework 3.15, SimpleJWT 5.3
Auth helpers dj-rest-auth, django-allauth (installed, not wired into INSTALLED_APPS)
Database SQLite (default in settings.py); PostgreSQL and MySQL drivers are also installed
Payments Stripe (stripe==10.6.0)
Rich text django-tinymce
Filtering django-filter
Phone numbers django-phonenumber-field
Color picker django-colorfield
Images Pillow
Caching helper django-cacheops + redis (installed; not configured in settings)
Static files whitenoise
CORS django-cors-headers (currently CORS_ALLOW_ALL_ORIGINS = True)
Server (prod) gunicorn
Env loading django-environ

Full pinned list in requirements.txt.


Architecture Overview

Project layout

The Django project (shophive) wires together a set of feature apps, each with its own models.py, serializers.py, views.py, urls.py, and admin.py. All apps mount under the /api/ prefix via shophive/urls.py.

Request flow

Client (frontend at http://localhost:3000)
        │
        ▼
CORS middleware  ──►  Django middleware stack  ──►  DRF Router
                                                       │
                                                       ▼
                                       <App>ViewSet (Model/Generic)
                                                       │
                                                       ▼
                                     Serializer  ◄──►  Model (BaseModel: UUID + timestamps)
                                                       │
                                                       ▼
                                              SQLite / MySQL / Postgres
  • All viewsets extend DRF's ModelViewSet (or use generic views in legal_policies).
  • The product viewset additionally mixes in SuccessMessageMixin from common/mixins.py to wrap responses with a { "message": ..., "data": ... } envelope.
  • Exceptions funnel through shophive.exceptions.custom_exception_handler, which also catches expired/invalid JWTs and emits a single message field.

Authentication

  • JWT issued via POST /api/token/ (standard SimpleJWT) and via the custom POST /api/users/login/ action which accepts email_or_phone + password.
  • Permissions default to AllowAny; individual viewsets opt into IsAuthenticated. Sensitive user actions (change_password, update_email, update_phone, profile, …) require auth.
  • Tokens carry user_id as the user claim. Refresh through POST /api/token/refresh/.

Payments

  • Orders created with payment_method=stripe trigger a stripe.checkout.Session.create(...) and return a payment_url.
  • Stripe redirects success to STRIPE_SUCCESS_URL?order_number=...; the frontend then calls GET /api/orders/payment-success/ to mark the order/payment paid.
  • Stripe pushes checkout.session.completed events to POST /api/webhook/, verified with STRIPE_WEBHOOK_SECRET.

Background workers

None. Even though redis is in requirements.txt, there is no Celery, Channels, or async worker configuration in the repo. Emails are sent synchronously through Django's SMTP backend.

Database design highlights

  • Every model inherits common.model.BaseModelid: UUIDField (primary key), created_at, updated_at, ordering = ['-created_at'].
  • Category is self-referential (parent → subcategories) with cycle detection in clean().
  • Product → ProductVariant → (Size, ColorField, image) with derived in_stock.
  • Cart is OneToOne per user; CartItem is unique per (cart, product_variant).
  • Order numbers are generated as ORD-<unix_ts>-<6 random chars>.

Folder Structure

ecommerce-backend/
├── manage.py
├── requirements.txt
├── .env.sample
├── shophive/             # Django project (settings, root urls, wsgi/asgi)
│   ├── settings.py
│   ├── urls.py
│   ├── views.py                # custom 404 / 500 JSON handlers
│   ├── exceptions.py           # custom DRF exception handler
│   ├── wsgi.py
│   └── asgi.py
├── common/                     # shared base model, pagination, response mixin
│   ├── model.py
│   ├── pagination.py
│   └── mixins.py
├── utils/
│   └── utils.py                # ColorUtils.get_color_name_from_hex(...)
│
├── roles/                      # Module / Permission / Role
├── users/                      # custom User model + auth/OTP flows
├── banners/                    # marketing banners
├── categories/                 # nested product categories
├── products/                   # products, variants, size guides, images, reviews
│   └── filters/
│       └── filters.py
├── cart/                       # cart + cart items (totals/discount logic)
├── coupons/                    # promo codes
├── wishlists/                  # per-user wishlist
├── address/                    # multi-address with default flag
├── orders/                     # orders, order items, payments, shipping methods, Stripe
└── legal_policies/             # Privacy Policy + Terms (TinyMCE)

Each feature app follows the standard Django layout: models.py, serializers.py, views.py, urls.py, admin.py, apps.py, tests.py, and per-app migrations/.

Note: there are no templates/ or static/ directories committed — this project is API-only and pairs with a separate frontend repo.


Installation

1. Clone

git clone https://github.com/rifadul/ecommerce-backend.git
cd ecommerce-backend

2. Create and activate a virtualenv

python3 -m venv shophive_venv
source shophive_venv/bin/activate          # Linux / macOS
# shophive_venv\Scripts\activate           # Windows

3. Install dependencies

pip install -r requirements.txt

4. Configure environment

Copy the sample env file and fill in real values:

cp .env.sample .env

Then edit .env (see Environment Variables below). Note that .env.sample only lists the bare minimum — the running settings additionally require EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, STRIPE_SECRET_KEY, STRIPE_PUBLIC_KEY, and STRIPE_WEBHOOK_SECRET, or the project will fail at import time.

5. Database

The default database is SQLite (auto-created at db.sqlite3 in the project root). To use PostgreSQL or MySQL, edit the DATABASES block in shophive/settings.py — a commented-out MySQL block is provided as a reference. The .env.sample defines DB_NAME/DB_USER/etc., but settings.py does not currently read them; you would need to wire them in yourself (e.g. via dj-database-url or environ).

6. Apply migrations

python3 manage.py makemigrations
python3 manage.py migrate

7. Create an admin user

python3 manage.py createsuperuser

You will be prompted for email, phone_number, first_name, last_name, and a password (the user model overrides USERNAME_FIELD = 'email').


Environment Variables

Variables actually read by shophive/settings.py:

Variable Required Default Purpose
DJANGO_SECRET_KEY yes Django secret key; also the JWT signing key
DJANGO_DEBUG optional False Toggle debug mode
DJANGO_ALLOWED_HOSTS optional localhost,127.0.0.1,192.168.10.39 Comma-separated allowed hosts
EMAIL_HOST_USER yes SMTP username (Gmail SMTP is hard-coded)
EMAIL_HOST_PASSWORD yes SMTP password / app password
STRIPE_SECRET_KEY yes Stripe secret key
STRIPE_PUBLIC_KEY yes Stripe publishable key
STRIPE_WEBHOOK_SECRET yes Signing secret used to verify webhook events

Variables present in .env.sample but not currently consumed by settings.py (would need wiring before they take effect):

Variable Note
DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_PORT Listed in .env.sample; DATABASES is still hard-coded to SQLite
CLIENT_ID, CLIENT_SECRET Referenced in the old README; no code path reads them

Other hard-coded values worth knowing about:

  • EMAIL_HOST = smtp.gmail.com, EMAIL_PORT = 587, EMAIL_USE_TLS = True.
  • STRIPE_SUCCESS_URL = http://localhost:3000/order-success/ and STRIPE_CANCEL_URL = http://localhost:3000/order-cancel/.
  • CORS_ALLOW_ALL_ORIGINS = True (in addition to an explicit CORS_ALLOWED_ORIGINS = ["http://localhost:3000"]).
  • CSRF_COOKIE_SECURE and SESSION_COOKIE_SECURE are True — local HTTP testing will not set the session/CSRF cookies; use HTTPS or temporarily relax these for dev.

Running the Project

Development server

python3 manage.py runserver
# http://127.0.0.1:8000/

The browsable DRF API is available under /api/... and the Django admin under /admin/.

Production server (Gunicorn)

gunicorn is in requirements.txt. A typical invocation:

gunicorn shophive.wsgi:application --bind 0.0.0.0:8000 --workers 3

Static files are served by WhiteNoise (installed but not added to MIDDLEWARE). To enable it, insert 'whitenoise.middleware.WhiteNoiseMiddleware' right after SecurityMiddleware, then run:

python3 manage.py collectstatic --noinput

Docker / docker-compose

Not present in this repo. There is no Dockerfile, docker-compose.yml, nginx.conf, or CI workflow committed.

Background workers / Celery

Not configured.


API Documentation

All endpoints are mounted under /api/. Every resource is a DefaultRouter-registered viewset, so the standard list/retrieve/create/update/partial_update/destroy actions exist for each.

Authentication

  • POST /api/token/ — obtain JWT pair ({"username": ..., "password": ...} — SimpleJWT defaults to the user model's USERNAME_FIELD, which is email here).
  • POST /api/token/refresh/ — refresh access token.
  • POST /api/users/register/ — register a new user and receive an initial JWT pair.
  • POST /api/users/login/ — login with email_or_phone + password.

Send Authorization: Bearer <access_token> on protected endpoints.

Users (/api/users/)

Standard CRUD plus custom actions:

  • POST /api/users/register/
  • POST /api/users/login/
  • POST /api/users/change_password/
  • POST /api/users/forget_password/
  • POST /api/users/reset_password_with_otp/
  • GET /api/users/profile/
  • POST /api/users/update_email/
  • POST /api/users/update_phone/
  • POST /api/users/verify_otp/
  • POST /api/users/resend_otp/
  • POST /api/users/update_image/
  • DELETE /api/users/delete-multiple/?ids=<id1,id2,...>

Roles & permissions

  • /api/modules/, /api/permissions/, /api/roles/
  • POST /api/roles/delete-multiple/?ids=<id1,id2,...>

Catalog

  • /api/category/ — nested categories.
  • /api/products/ — products with search, ordering (price, name, sku) and django-filter-backed filters.
    • GET /api/products/colors/ — unique variant colors with their inferred names.
    • POST /api/products/add-review/ — add a review (authenticated).
    • DELETE /api/products/delete-multiple/?ids=<id1,id2,...>
  • /api/banners/

Shopping flow

  • /api/cart/, /api/cart-items/, GET /api/my-cart/
  • /api/coupons/
  • /api/wishlist/
  • /api/address/

Orders & payments

  • /api/orders/, /api/payments/, /api/shipping-methods/
  • GET /api/orders/my_orders/
  • GET /api/orders/order_details/?order_number=<n>
  • POST /api/orders/<id>/cancel_order/
  • POST /api/orders/<id>/create_payment_intent/
  • GET /api/orders/payment-success/?session_id=<stripe_session_id>
  • POST /api/webhook/ — Stripe webhook receiver

Legal

  • GET /api/privacy-policy/
  • GET /api/terms-and-conditions/

Pagination

All list endpoints use common.pagination.CustomPageNumberPagination:

GET /api/products/?page=2&page_size=20

page_size is capped at 100.

Example — create a product review

POST /api/products/add-review/
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "product_id": "<uuid>",
  "rating": 5,
  "comment": "Great quality!"
}

Example — create a Stripe-checkout order

POST /api/orders/
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "shipping_address": "<address_uuid>",
  "billing_address":  "<address_uuid>",
  "shipping_method":  "<shipping_method_uuid>",
  "payment_method":   "stripe"
}

The response includes a payment_url to redirect the user to Stripe Checkout.

OpenAPI/Swagger: not installed. There is no drf-spectacular / drf-yasg configured in this repo.


Database & Migrations

Workflow:

python3 manage.py makemigrations          # generate migrations from model changes
python3 manage.py migrate                 # apply pending migrations
python3 manage.py showmigrations          # inspect status
python3 manage.py sqlmigrate <app> <n>    # preview SQL

Per-app migrations live in each app's migrations/ directory and are committed to the repo. All PKs are UUIDs (set on BaseModel), so cross-table relations use UUID FKs.


Static & Media Files

STATIC_URL  = '/static/'
STATIC_ROOT = <BASE_DIR>/staticfiles
MEDIA_URL   = '/media/'
MEDIA_ROOT  = <BASE_DIR>/media
  • In DEBUG mode, shophive/urls.py serves MEDIA_URL from MEDIA_ROOT.
  • Uploaded files end up under media/profile_images/, media/banners/, media/categories/, media/products/images/, and media/products/variants/.
  • Product/variant images are validated against an allow-list of formats (JPEG, JPG, PNG, GIF, BMP, TIFF, WEBP).
  • For production, run collectstatic and serve /static/ and /media/ through your web server (or wire up WhiteNoise — see above).

Testing

Each app ships a stub tests.py. No tests are currently implemented in this repository, and there is no pytest.ini, pyproject.toml, tox.ini, or coverage configuration committed.

Run Django's built-in test runner anyway with:

python3 manage.py test

Deployment

There is no deployment config committed (no Dockerfile, compose file, Heroku Procfile, GitHub Actions workflow, or Nginx config). What the code suggests about how this is intended to run:

  • gunicorn is the production WSGI server.
  • django-heroku is in requirements.txt, hinting at past or planned Heroku deployment, but django_heroku.settings(locals()) is not called in settings.py.
  • whitenoise is installed for serving static assets in production (you must add its middleware — see the production section above).
  • Stripe webhook URL to register with Stripe: https://<your-domain>/api/webhook/.

A minimal deployment checklist:

  1. Set DJANGO_DEBUG=False and a strong DJANGO_SECRET_KEY.
  2. Populate DJANGO_ALLOWED_HOSTS with your domain(s).
  3. Switch DATABASES to PostgreSQL/MySQL.
  4. Tighten CORS_ALLOW_ALL_ORIGINS = False and use CORS_ALLOWED_ORIGINS.
  5. Add the WhiteNoise middleware, then collectstatic.
  6. Run with Gunicorn behind Nginx (or equivalent), terminate TLS at the edge.
  7. Configure Stripe webhook → /api/webhook/.

Troubleshooting

Symptom Likely cause / fix
ImproperlyConfigured: Set the DJANGO_SECRET_KEY environment variable .env is missing or DJANGO_SECRET_KEY is not set.
KeyError for EMAIL_HOST_USER / STRIPE_* at startup settings.py reads these unconditionally — fill them in .env, even with dummy values for local dev.
Login cookies missing locally CSRF_COOKIE_SECURE / SESSION_COOKIE_SECURE = True block cookies over plain HTTP. Use HTTPS or relax these for dev.
401 with "Your session has expired..." JWT expired or malformed — request a new pair via /api/token/ or /api/users/login/.
Stripe webhook returns 400 STRIPE_WEBHOOK_SECRET is wrong or the request body was modified by a proxy. Use the Stripe CLI (stripe listen --forward-to localhost:8000/api/webhook/) for local testing.
phonenumber_field validation error Phone numbers must be in E.164 format (e.g. +8801712345678).
Frontend blocked by CORS Check CORS_ALLOWED_ORIGINS; while CORS_ALLOW_ALL_ORIGINS = True is also set, leaving the explicit list out of sync can cause confusion.
MySQL/Postgres not used despite .env settings DATABASES is hard-coded to SQLite — edit shophive/settings.py to switch engines.

Contributing

  1. Fork the repo and create a feature branch: git checkout -b feat/<short-name>.
  2. Run python3 manage.py makemigrations whenever you change a model and commit the generated migration files.
  3. Keep new models inheriting from common.model.BaseModel for the UUID PK + timestamps.
  4. Follow existing patterns: one app per domain, viewsets registered with DefaultRouter, and URL include lines added to shophive/urls.py.
  5. Open a pull request describing the change and any new environment variables.

License

No license file is committed to this repository. Treat the code as All Rights Reserved until the owner adds an explicit license (e.g. MIT, Apache-2.0).


About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages