👔

Online Shirt Store on Nuxt 4 with an Owner Admin Panel

a shirt shop in Cheboksary: the owner manages products, prices and orders alone

An online store for school and everyday shirts in Cheboksary on Nuxt 4 and FastAPI: a catalogue with colours and stock by size, a cart, wholesale prices, an admin panel and order alerts in Telegram.

In productionNDA
2 sections
kids' and teens' shirts, each with its own size table
webp
phone photos are rotated, shrunk and converted by the server
15 minutes
sign-in lockout after 5 wrong passwords in a row
Online store of school shirts on Nuxt by DevUnit Lab: the home page on a phone
Online store of school shirts on Nuxt by DevUnit Lab: the home page on a phone

The task

A shop selling school and everyday shirts in Cheboksary sold «by phone and chat» and delivered around the city and the districts of Chuvashia. The client needed a full online store that the owner runs alone: adds products and photos, changes prices and sees orders without contacting a developer or understanding the technical side.

The conditions:

  • the site is found in search for queries like «buy school shirts Cheboksary»;
  • the buyer chooses a size and colour instead of guessing in a chat;
  • wholesale purchases are calculated automatically;
  • the owner learns about a new order at once, in a messenger.

The solution

A Nuxt 4 storefront and a FastAPI API with MySQL 8, plus an admin panel for the owner. The admin panel is a closed section of the site where the owner edits products, prices, photos and texts and views orders.

What was implemented:

  • A catalogue with «kids'» and «teens'» sections, and a product card with colour options, a size chart and several photos.
  • Size tables for kids and teens, and a shirt measuring diagram with labels and an explanation.
  • A cart: add, change quantity, remove, total. The contents are stored in the browser and survive a page reload.
  • Checkout for several products at once, with prices calculated by the server.
  • Wholesale: the quantity and discount are set in the panel, and a product is marked as taking part in its own card.
  • The admin panel: products, prices, photos, «hit» and «new» labels, removal from the storefront, and an order list with status changes.
  • A «Site content» section: contacts and legal details, the schedule of market trading, the story of the shop, wholesale terms, three selling points on the home page, FAQ and page texts.
  • Light and dark themes with a switch, and a custom 404 page.
  • A bot for access requests to order notifications: a new person writes to the bot and the owner approves the request with a button in the chat.

How it works

Nuxt server-side rendering for «buy school shirts» searches

Server-side rendering (SSR) means a page is assembled on the server and delivered as ready HTML, not as an empty shell that JavaScript fills in. So a search robot sees the products at once. For search we did the following: every page has its own title and description, Product markup with price, availability and photos, ClothingStore markup with the pickup point coordinates, a canonical URL, a robots.txt that closes the admin panel, and a sitemap built on the fly from visible pages and products.

Stock by size and colour in the product card

A product has a list of colours, and each colour has its own list of sizes with stock. On the product page the buyer picks a colour by a swatch and a size among those in stock. The choice goes into the cart, the order, the admin panel and the Telegram notification. A size with no stock is not shown on the storefront.

Phone photos: rotation by the camera tag and webp

The owner uploads an ordinary phone snapshot. A phone records the frame's orientation in a camera tag instead of rotating the pixels, and without reading the tag a photo lies on its side. The server reads the tag, rotates the frame, shrinks it and converts it to webp, a modern image format that weighs noticeably less than JPEG.

The server calculates prices, not the browser

The cart contents are stored in the browser, and a buyer can edit the browser's data however they like. So at checkout the server recalculates prices and the total from the database. It also applies the wholesale price.

Order alerts in Telegram and an access-request bot

An order is duplicated into the owner's Telegram chat. Access to notifications for other people is granted by a bot: a person writes to the bot, the request goes to the owner, and the owner approves or rejects it with a button in the chat. Approved people are added to the recipients with no changes to server settings. VKontakte alerts are written but not switched on: the community token is missing.

Admin panel protection

Passwords are stored as hashes and sign-in creates a session. The 15-minute lockout after 5 wrong passwords applies to a username regardless of the address the guessing comes from, because the general per-IP request limit on nginx does not stop guessing from many addresses. The panel is available on a separate subdomain with its own session cookie that does not overlap with the storefront. All write routes in the API check sign-in.

Deployment as one container stack

The store runs in four Docker containers: database, cache, API and storefront. The database schema is applied by Alembic migrations automatically when the API starts. The general entry nginx on the studio's web server publishes the site, with certificates issued by Let's Encrypt.

Results

  • The owner adds products and changes prices, stock and texts alone, without a developer.
  • The buyer picks a colour and size, and the order reaches the owner in Telegram with the chosen items.
  • The wholesale price switches on automatically, and prices do not depend on what sits in the browser.
  • Pages are served as ready HTML, each with its own title and description, and products carry structured markup.
  • Uploading a photo from a phone needs no processing on the owner's side.
  • The repository has no speed measurements and no automated tests, so we give no scores.

Technologies and why

  • Nuxt 4, Vue 3, Tailwind CSS 4 — the storefront and the admin panel with server-side rendering and light and dark themes.
  • FastAPI and SQLAlchemy 2 (async) — the REST API for the catalogue, orders and site settings.
  • Alembic — database schema migrations, six revisions at the time of the document, applied at startup.
  • MySQL 8 — products, variants, stock, orders, site settings.
  • Redis 7 — cache and sessions.
  • Docker Compose — database, cache, API and storefront as one stack; Python 3.13 and Node 24 inside the images.
  • nginx and Let's Encrypt — publishing the storefront and the panel through the shared entry container of the web server.
  • A Telegram bot — order notifications and requests for access to them.

Status

Version 1.17.1 of 26 September 2026, the store runs on the production server. Search indexing is closed while it is being finished. Before promotion the block must be removed, Yandex Metrica connected and the site verified in the webmaster tools, which needs verification codes from the client. Payment is on receipt only, and online payment is not connected: a QR-code payment or an online payment service is under discussion. The numbers in the size chart need to be checked with the owner. The repository has no automated tests and no description of backups. Other client details are not disclosed.

Questions about this project

How do you move from selling by phone and chat to an online store?
You need a store the owner runs alone. Here, in the admin panel, the owner adds products and photos, changes prices, marks items as «hit» or «new», removes a product from the storefront and sees orders with a one-click call to the buyer. No developer is needed.
How do you upload a product photo from a phone so it does not lie on its side?
An ordinary phone snapshot is uploaded. The server rotates the frame by the camera tag, shrinks it and converts it to webp, so pages stay light.
How do you track stock by size and colour?
In the product card you add a list of colours, and each colour has its own sizes with stock on hand. A size with no stock disappears from the storefront, and so does a colour with no sizes. The buyer picks a colour and size on the product page, and the choice goes into the cart, the order and the notification to the owner.
How do wholesale prices work in the online store?
The admin panel sets the quantity at which wholesale starts and the discount size, and each product is marked as taking part in wholesale. The cart shows how many pieces are missing for the wholesale price. The total is calculated by the server from the database, not by the browser.
How does an online store get found for «buy school shirts in Cheboksary»?
The storefront is rendered on the server, so search robots receive ready HTML with the products. Every page has its own title and description, the product page carries Product markup with price and availability, and the sitemap builds itself. Indexing is currently closed while the store is being finished, and is switched on before promotion.
How is the store's admin panel protected?
Writing to the API is possible only after sign-in. After 5 wrong passwords in a row for one username, sign-in is blocked for 15 minutes through either of the two panel addresses. The panel opens on a separate subdomain with its own session cookie, and the response time on sign-in does not reveal whether a username exists.

Need something similar?

Tell us about the task — we'll show how we solved it and estimate the scope.