Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

144 Commits
 
 
 
 
 
 

Repository files navigation

Easy Shop

A multi-vendor e-commerce platform where independent sellers list and manage their own products under a single storefront, customers browse and buy across all vendors in one cart, and administrators oversee the marketplace from a dedicated back office.

The application is split across two repositories:

Repository What it is
Easy-Shop (this one) Vue 3 single-page application covering the storefront, vendor panel and admin panel
Easyshop Spring Boot 2.6 REST API backed by MySQL, with Stripe Checkout for payments

The two are developed together and share an API contract, so they must be deployed as a pair — see Authentication Model. Paths shown below as backend/Backend/... refer to files in the API repository.


Table of Contents


Overview

Easy Shop models a marketplace with three user types, each with its own registration, sign-in and interface:

Role Entry point Purpose
Customer /signup, /signin Browse categories, search products, keep a wishlist and cart, pay via Stripe, track orders
Vendor /vsells, /vlogsin Seller dashboard — publish products, upload imagery, review orders placed against their own listings
Admin /adminlogin Back office — manage the category taxonomy, review users and vendors, confirm and update orders

The storefront is built on Bootstrap 5; the vendor and admin panels use CoreUI Vue, giving each back office a sidebar, breadcrumb and stat-widget layout.

Customer and vendor accounts must confirm their email address before they can sign in — registration sends a verification link, and signIn refuses accounts that are not yet enabled.

Features

Storefront (customer)

  • Category browsing and per-category product listings
  • Product search with a dedicated results page
  • Product detail pages with image galleries
  • Wishlist
  • Persistent cart with quantity updates and item removal
  • Stripe Checkout with success and failure return pages
  • Order placement, order history and order detail views
  • Profile editing and password change

Vendor panel

  • Dashboard with sales widgets
  • Product create / edit / list / delete, scoped to the vendor's own catalogue
  • Product image upload and management
  • Ordered-products view covering only that vendor's sales
  • Profile editing and password change

Admin panel

  • Dashboard with marketplace widgets
  • Category CRUD plus category image management
  • Customer and vendor directories
  • Order review, confirmation and status updates
  • Profile editing and password change

Architecture

Browser (Vue 3 SPA, :8080)
        │  JSON over HTTP; session token in the Authorization header
        ▼
Spring Boot REST API (:8084)  ──► MySQL (easyshop)
        │                     ──► SMTP (account verification mail)
        └──────────────────────► Stripe (Checkout sessions, payment verification)

The frontend never talks to MySQL or Stripe's secret API directly. Prices, order totals and account identity are all resolved server-side; see Authentication Model.

Tech Stack

Frontend

Concern Choice
Framework Vue 3 (Options API)
Build Vue CLI 5, Babel
Routing Vue Router 4 (history mode, with role-aware navigation guards)
State Vuex 4
UI Bootstrap 5 (storefront), CoreUI Vue 4 (dashboards)
HTTP Axios, via a shared client that attaches the bearer token
Payments Stripe.js (Checkout redirect)

Backend

Concern Choice
Framework Spring Boot 2.6.3 (Spring MVC)
Persistence Spring Data JPA / Hibernate, MySQL 8
Password hashing BCrypt (spring-security-crypto)
Payments stripe-java
Mail Spring Boot Mail (SMTP)
Build Maven (wrapper included)

Getting Started

Prerequisites

  • JDK 11+ and MySQL 8 (for the API)
  • Node.js 16+ and npm (for the web client)
  • A Stripe account — you need the test publishable and secret keys
  • An SMTP account for verification email (Gmail requires an App Password)

1. Database

CREATE DATABASE easyshop;
CREATE USER 'easyshop_app'@'localhost' IDENTIFIED BY 'a-strong-password';
GRANT ALL PRIVILEGES ON easyshop.* TO 'easyshop_app'@'localhost';

Use a dedicated account rather than root. Schema objects are generated by Hibernate on first run.

2. Backend

Clone the API repository alongside this one:

git clone https://github.com/Alphax978/Easyshop.git
cd Easyshop/Backend
cp .env.example .env          # then fill in every blank

Load the variables and start the API:

# bash
set -a && source .env && set +a
./mvnw spring-boot:run

# PowerShell
Get-Content .env | ForEach-Object { if ($_ -match '^([^#=]+)=(.*)$') { [Environment]::SetEnvironmentVariable($Matches[1].Trim(), $Matches[2].Trim()) } }
.\mvnw.cmd spring-boot:run

The API listens on http://localhost:8084. It will not start without DB_USERNAME, DB_PASSWORD, STRIPE_SECRET_KEY and the mail credentials — that is deliberate, so a deployment cannot silently fall back to placeholder secrets.

3. Create the first administrator

Administrator registration is not open to the public. Generate a bootstrap secret, set it as ADMIN_BOOTSTRAP_TOKEN, restart the API, then:

curl -X POST http://localhost:8084/backend/Admin/signup \
  -H "Content-Type: application/json" \
  -H "X-Admin-Bootstrap-Token: <your ADMIN_BOOTSTRAP_TOKEN>" \
  -d '{"firstName":"Ada","lastName":"Lovelace","email":"admin@example.com","password":"choose-a-long-one"}'

The bootstrap token only works while no administrator exists. After the first account, further admins must be created by an existing admin sending their own Authorization: Bearer <token>. Clear ADMIN_BOOTSTRAP_TOKEN from the environment once you are done.

4. Frontend

cd frontend
cp .env.example .env.local    # set VUE_APP_API_URL and your Stripe publishable key
npm install
npm run serve

The dev server runs on http://localhost:8080 with hot reload. npm run build emits a production bundle to frontend/dist/; serve it from any static host that rewrites unknown paths to index.html so history-mode routing works.

Configuration

Nothing secret lives in the repository. Both halves read configuration from the environment, and both ship a committed .env.example documenting every key.

Backendbackend/Backend/.env.example

Variable Purpose
DB_URL, DB_USERNAME, DB_PASSWORD MySQL connection
SERVER_PORT API port (default 8084)
APP_BASE_URL Public URL of the frontend; Stripe return URLs are built from it
APP_ALLOWED_ORIGINS Comma-separated CORS allowlist
ADMIN_BOOTSTRAP_TOKEN One-time secret permitting creation of the first admin
STRIPE_SECRET_KEY Stripe secret key — backend only, never shipped to the browser
MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD SMTP for verification mail
JPA_SHOW_SQL SQL logging; leave false outside local debugging

Frontendfrontend/.env.example

Variable Purpose
VUE_APP_API_URL Base URL of the backend API
VUE_APP_STRIPE_PUBLISHABLE_KEY Stripe publishable key (pk_…), which is designed to be public

Anything prefixed VUE_APP_ is compiled into the JavaScript bundle and is readable by anyone who loads the page. Only the publishable Stripe key belongs there; the secret key (sk_…) goes in the backend environment alone.

Authentication Model

Sign-in returns an opaque session token, which the browser stores and sends on every subsequent request:

Authorization: Bearer <token>

Three rules hold throughout the API:

  1. Identity is derived from the token, never from the request. Endpoints that act on "your" account — profile update, password change, order history, vendor sales — take no account id at all. The server looks up the token's owner. Supplying somebody else's id is not a way in, because there is nowhere to supply one.
  2. Authentication and authorisation are separate checks. Holding a valid token proves who you are; each endpoint separately confirms the record you are reaching for is yours. Orders verify the buyer, products verify the seller.
  3. Money is calculated server-side. Checkout accepts only a product id and a quantity. Unit prices are read from the database and the Stripe session is confirmed as paid before an order is recorded, so neither the price nor the fact of payment can be asserted by the client.

Passwords are hashed with BCrypt at cost factor 12. Accounts predating this change still hold an MD5 digest; those are accepted at sign-in and transparently re-hashed to BCrypt on the next successful login, so no one is locked out and the old digests drain away on their own.

The frontend also carries role-aware router guards, but treat them as a usability feature — they keep panels from rendering for signed-out visitors. Guards in a browser can always be bypassed, so the server authorises every request independently.

Security Notes

This codebase went through a security review; the fixes are described above. Points worth carrying forward:

  • Rotate any credential that was ever committed or shared. Configuration now comes from the environment, but a secret that previously sat in a file should be considered burned. Rotate the database password, Stripe keys and SMTP app password.
  • .gitignore covers target/, .env, and the upload directories. Maven copies application.properties into target/classes, so an unignored build directory will leak whatever the file holds.
  • Uploads are restricted to jpg/jpeg/png/gif/webp, stored under a generated UUID filename, and resolved through a containment check so a crafted name cannot escape the storage directory. Upload endpoints require an admin (catalogue imagery) or vendor (product imagery) session.
  • CORS is an allowlist, driven by APP_ALLOWED_ORIGINS. Avoid reintroducing @CrossOrigin on individual controllers — a per-controller annotation overrides the central policy.
  • Error responses omit stack traces and exception messages (server.error.include-stacktrace=never), so internals are not disclosed to clients.

Sensible next steps, not yet implemented:

  • Move order fulfilment to a Stripe webhook. The API verifies payment status before recording an order and rejects a reused session id, but a webhook is the durable path — it survives a customer closing the tab before the redirect completes.
  • Give session tokens an expiry and rotation policy. They are currently long-lived and issued once per account.
  • Add rate limiting on sign-in and registration.
  • Consider httpOnly cookies instead of localStorage, which would put tokens out of reach of injected scripts.

Project Structure

Easyshop/            # API repository
└── Backend/
│   ├── .env.example                  # documented configuration keys
│   ├── pom.xml
│   └── src/main/
│       ├── java/com/EasyShop/ecommerce/
│       │   ├── controller/           # REST endpoints
│       │   ├── service/              # business logic, Stripe, mail, storage
│       │   ├── security/             # AuthGuard (identity), PasswordService (BCrypt)
│       │   ├── repository/           # Spring Data repositories
│       │   ├── model/                # JPA entities
│       │   ├── dto/                  # request/response shapes
│       │   ├── exceptions/           # typed errors + HTTP status mapping
│       │   └── config/               # CORS, storage locations
│       └── resources/
│           └── application.properties  # reads entirely from the environment

Easy-Shop/           # web client repository (this one)
└── frontend/
    ├── .env.example
    ├── public/index.html
    └── src/
        ├── api/
        │   ├── http.js               # shared Axios client; attaches bearer token
        │   └── session.js            # "who am I" against the /me endpoints
        ├── router/index.js           # routes + role-aware guards
        ├── components/               # shared storefront components
        ├── views/                    # storefront pages
        ├── Admin/                    # admin shell (CoreUI)
        └── aVendor/                  # vendor shell (CoreUI)

API Reference

All paths are relative to the API base URL. Auth shows what the endpoint requires.

Accounts

Method Path Auth Description
POST /backend/user/signup Register a customer; sends verification mail
POST /backend/user/signIn Sign in, returns a token
GET /backend/user/verify-email?token= Confirm an address
GET /backend/user/me Customer The caller's own record
POST /backend/user/update Customer Update own profile
POST /backend/user/updatepass Customer Change own password (current password required)
GET /backend/user/reflect Admin Customer directory
POST /backend/Vendor/signup · /signIn Vendor registration and sign-in
GET /backend/Vendor/me Vendor The caller's own record
POST /backend/Vendor/update · /updatepass Vendor Update own profile / password
GET /backend/Vendor/all · /vreflect Admin Vendor directory
POST /backend/Admin/signup Admin or bootstrap token Create an administrator
POST /backend/Admin/signIn Administrator sign-in
GET /backend/Admin/me Admin The caller's own record
POST /backend/Admin/update · /updatepass Admin Update own profile / password

Catalogue

Method Path Auth Description
GET /backend/category/show List categories (drives storefront nav)
POST /backend/category/create Admin Create a category
POST /backend/category/update/{id} Admin Update a category
DELETE /backend/category/delete/{name} Admin Delete a category
GET /backend/product/showun List all products
GET /backend/product/{id} Product detail
GET /backend/product/products/search/{query} Search
GET /backend/product/vendorshow Vendor The caller's own listings
POST /backend/product/add Vendor Create a listing
POST /backend/product/update/{id} Vendor (owner) Update own listing
DELETE /backend/product/delete/{id} Vendor (owner) Delete own listing

Cart, wishlist, orders

Method Path Auth Description
GET /backend/cart/ Customer Own cart
POST /backend/cart/add Customer Add an item
PUT /backend/cart/update Customer Change quantity
DELETE /backend/cart/delete/{itemId} Customer Remove an item
GET /backend/wishlist/ · /gets Customer Own wishlist
POST /backend/wishlist/add Customer Add to wishlist
DELETE /backend/wishlist/delete/{id} Customer Remove from wishlist
POST /backend/order/create-checkout-session Customer Stripe session; prices resolved server-side
POST /backend/order/add?sessionId= Customer Record an order once Stripe reports it paid
GET /backend/order/ Customer Own order history
GET /backend/order/{id} Customer (owner) Own order detail
GET /backend/order/all Admin Every order
GET /backend/order/allbyseller Vendor Own sales
POST /backend/order/statusupdate/{date} · /orderupdate/{date} Admin Update order status

Uploads

Method Path Auth Description
POST /backend/fileUpload/ Admin Upload catalogue imagery
GET /backend/fileUpload/ · /files/{name} List / fetch catalogue imagery
POST /backend/vendor/fileUpload/ Vendor Upload product imagery
GET /backend/vendor/fileUpload/ · /files/{name} List / fetch product imagery

Available Scripts

Frontend (from frontend/)

Command Description
npm run serve Development server with hot reload
npm run build Production bundle in dist/
npm run lint Lint and auto-fix

Backend (from backend/Backend/)

Command Description
./mvnw spring-boot:run Run the API
./mvnw clean package Build an executable JAR
./mvnw test Run tests

Known Limitations

  • No automated test suite. Neither half has meaningful test coverage; the security changes described above were verified by review and a frontend production build, not by tests.
  • Order fulfilment is redirect-driven. Payment is verified against Stripe and session ids cannot be replayed, but a webhook would be more robust — see Security Notes.
  • Session tokens do not expire. One long-lived token is issued per account.
  • ddl-auto is update. Convenient in development; production deployments should manage schema with migrations instead.
  • The bundled index.html loads jQuery 3.2.1 and Bootstrap 4 from CDNs, both of which have published advisories, while package.json bundles Bootstrap 5. Worth reconciling.
  • The frontend still ships a role value in localStorage to choose which /me endpoint to call. It is a routing hint only — the server never trusts it.

License

No license file is present. All rights are reserved by the author until one is added — open an issue if you would like to use this project.

About

Frontend for ecommerce website(Vue.js)

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages