Glossy Store
A full-stack storefront where every admin and superadmin login requires OTP — 28 Sequelize models, role-separated dashboards, and support chat with private attachment handling.
- 28
- Sequelize models
- 30
- Frontend pages
- 22
- Migrations
- 100%
- Staff logins with OTP
- Role
- Author
- Year
- 2026
- Status
- Private
- Type
- E-commerce platform
01Overview
Glossy Store is a React and Vite storefront over an Express and Sequelize backend on MySQL: catalogue, categories, cart, checkout, wishlist and orders, with separate admin and superadmin dashboards behind role-based access.
Twenty-eight Sequelize models, thirteen controllers, thirty frontend pages, twenty-two migrations. The database bootstraps itself on backend startup, so a fresh clone runs without a manual migration step.
The decision that shapes the security posture is small and unusual: OTP is mandatory on every admin and superadmin login attempt, not just on unrecognised devices.
02The problem
Storefront admin accounts are the real target. A customer account buys something; an admin account edits prices, reads every order, and exports a customer list. Most e-commerce builds protect both with the same password form.
Optional two-factor solves this only for the people who opt in, which is never the account that gets compromised. Risk-based prompts help, but they fail exactly when an attacker logs in from a plausible device.
Support is the other soft edge. A support thread carries order details and often an attachment, and serving those from a public uploads directory means a guessable URL is a data leak.
03Architecture
- 01
Mandatory OTP for privileged roles
Every admin and superadmin login goes through a dedicated /otp page with resend support. Customers get a normal login; anyone who can change a price does not.
- 02
Two admin tiers
Admin and superadmin are separate roles with separate dashboards rather than one dashboard with hidden buttons. Authorisation is enforced on the route, not on the render.
- 03
Commerce core
Products, categories, cart, checkout, wishlist and orders across 28 models — enough relational structure that the migrations and associations earn their keep.
- 04
Support chat with private attachments
Attachments in support threads are access-checked rather than served statically, so a file's URL is not its authorisation.
- 05
Self-bootstrapping database
The backend provisions its own schema on startup. For a project handed between machines, a clone that runs is worth more than a clone that documents how to make it run.
04Key decisions
OTP always, for staff
Mandatory second factor adds friction to a login that happens a few times a day for a handful of people, and removes the single-credential compromise that would expose every customer record. The friction is real and the trade is obvious.
Sequelize with real migrations
Twenty-two migrations against 28 models — a schema history that can move forward on a live database, rather than a sync that is only safe on an empty one.
Roles as routes, not as UI
Superadmin capability is separated at the API. Hiding a button is a presentation choice; refusing the request is an access control.
05Stack
- React
- Vite
- TypeScript
- Node.js
- Express
- Sequelize
- MySQL