This project keeps the existing SSQUARE ELITE/ToyLand storefront design and adds the requested guest shopping flow, admin authentication, MySQL-backed product management, delivery rules and UPI checkout.
Customers do not create an account and do not log in.
Store → Add to Cart → Cart → Checkout → Customer Details
→ Delivery Calculation → Order Summary → UPI Payment → Order Confirmation
The server recalculates the subtotal, stock and delivery amount from the MySQL product catalogue, so the final amount is not trusted from the browser.
Only UPI is offered.
UPI ID: sriram170620@okaxis
The app builds a dynamic upi://pay request using the final order amount and also displays a QR code. The QR image is generated from that UPI URI by the QR image service used in the frontend.
The application intentionally does not mark an order as paid when the customer only opens the UPI payment page. The order becomes paid/placed only after the customer confirms payment. A real UPI payment-verification gateway/webhook would be required for automatic server-side verification.
Admin login: /admin-login.html
The dashboard can:
Product data is stored in MySQL and is therefore persistent across page refreshes and server restarts. New products automatically appear on the customer store because the store reads the product catalogue from /api/products.
For local development, set these in .env:
ADMIN_NAME=SSQUARE ELITE Admin
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=replace_with_a_strong_password
JWT_SECRET=replace_with_a_long_random_secret
When ADMIN_EMAIL and ADMIN_PASSWORD are set, startup creates or updates that account as an admin. Passwords are stored as bcrypt hashes in MySQL.
You can also create/update an admin from a machine that can reach the database:
node scripts/make-admin.js admin@example.com "StrongPassword123!" "Store Admin"
npm install
Create .env from .env.example and fill in the MySQL credentials.
Then run:
npm start
Development mode:
npm run dev
Open:
http://localhost:3000/
Admin:
http://localhost:3000/admin-login.html
GoDaddy’s managed MySQL environment supplies:
DB_HOST
DB_PORT
DB_NAME
DB_USER
DB_PASSWORD
Add these application secrets yourself:
CLIENT_URL=https://ssquareelite.online
JWT_SECRET=<long random secret>
ADMIN_JWT_EXPIRES_IN=8h
ADMIN_NAME=SSQUARE ELITE Admin
ADMIN_EMAIL=<your admin email>
ADMIN_PASSWORD=<strong admin password>
Restart the app after changing secrets.
The server automatically creates the MySQL tables and seeds starter products only when the products table is empty.
Sri-main/
├── server.js
├── app.js
├── package.json
├── package-lock.json
├── config/
│ └── db.js
├── middleware/
│ └── auth.js
├── models/
│ ├── User.js
│ ├── Product.js
│ └── Order.js
├── routes/
│ ├── admin-auth.js
│ ├── admin.js
│ ├── checkout.js
│ └── products.js
├── scripts/
│ ├── make-admin.js
│ ├── seed.js
│ └── seed-data.js
└── public/
├── index.html
├── admin-login.html
├── admin.html
├── success.html
├── js/app.js
├── css/style.css
└── img/uploads/
Customer help opens:
https://wa.me/918072894491?text=Hi%2C%20I%20have%20a%20question%20regarding%20my%20order%2Fproduct.
Number: 8072894491
admin_token.secure: true when NODE_ENV=production.If the admin login says it is not working, check these values in the hosting application’s Environment Variables (not only in .env.example):
ADMIN_USERNAME=admin
ADMIN_EMAIL=your-real-admin-email@example.com
ADMIN_PASSWORD=your-strong-password
JWT_SECRET=a-random-secret-at-least-32-characters-long
After changing any of these values, restart/redeploy the Node.js application. The server will create or update the configured admin account automatically.
You can check the application without exposing secrets:
https://your-domain.com/health
https://your-domain.com/api/admin/auth/status
/health should return ok: true. The admin status endpoint should show adminBootstrapConfigured: true and jwtConfigured: true.
The admin login accepts either the configured ADMIN_USERNAME or the configured ADMIN_EMAIL.
The eight category cards now filter products by category and scroll to the filtered product list. Existing starter products are migrated to the matching categories on startup.
UPI is still a manual payment method. A UPI QR/deep link does not provide a reliable server-side payment-success callback, so the success page has an I Have Paid — Confirm Order button. That action confirms the order, reduces stock, marks it paid, and triggers WhatsApp notifications.
Set these environment variables in GoDaddy:
WHATSAPP_GRAPH_VERSION=vXX.X
WHATSAPP_ACCESS_TOKEN=...
WHATSAPP_PHONE_NUMBER_ID=...
WHATSAPP_ADMIN_TO=919344714369
WHATSAPP_TEMPLATE_LANG=en_US
WHATSAPP_ADMIN_TEMPLATE=...
WHATSAPP_CUSTOMER_TEMPLATE=...
The system sends the paid order to 9344714369, including customer details, item names/quantities, total and publicly hosted product images when available. It also sends the customer a bill message to the mobile number entered at checkout and includes a bill URL.
Meta may require an approved WhatsApp message template for business-initiated messages outside the customer-service window. Configure the optional admin/customer template names above if free-form messages are rejected.
+ / − quantity controls and a You may also like product suggestion section.pending until the customer confirms payment after completing UPI payment.paid.WHATSAPP_ADMIN_TO (default 919344714369) and sends the customer a receipt/document link when the API allows it./api/checkout/invoice/<ORDER_ID>.pdf and the customer can also view the HTML bill.A plain UPI deep link/QR does not provide this Node.js app with automatic bank-side payment verification. The current flow therefore confirms the order only after the customer taps I Have Paid — Confirm Order. For automatic verification, replace this confirmation step with a payment gateway such as Razorpay/PhonePe/PayU and its server-side webhook.
For business-initiated WhatsApp messages, Meta may require approved message templates. Set WHATSAPP_ADMIN_TEMPLATE and WHATSAPP_CUSTOMER_TEMPLATE to approved template names when free-form messages are rejected. The customer receipt document also requires the public CLIENT_URL to be HTTPS and reachable by Meta.