Snurlax Cosmetics API
The e-commerce backend behind a cosmetics brand, built with a second developer. An Express and MongoDB API covering accounts, products, categories, cart, favourites and orders, with JWT auth and bcrypt hashing, an admin role and phone verification, image uploads through Multer, transactional email over Nodemailer and push notifications through Firebase. Packaged with Docker Compose for deployment.
- My Role
- Backend Developer
- Timeline
- Aug 2023 – Oct 2023
- Status
- Shipped

This is the server side of a cosmetics brand's online store, built at Snurlax Digital: a REST API that carries a shopper from browsing the catalogue to a placed order, consumed by a Flutter mobile app a colleague built in parallel. It was my first professional role, at Snurlax Digital, working as the backend half of a two-developer team — which meant every endpoint doubled as a contract the mobile client depended on.
The API is organised around the store's domain objects — users, products, categories, carts, favourites and orders — each persisted as MongoDB documents behind Express routes. Cross-cutting concerns live in middleware: JWT verification on protected routes, an admin check on catalogue management, Multer parsing on image-upload endpoints. Outbound messaging goes through Nodemailer for transactional email and Firebase for push, and Docker Compose runs the API and database as one reproducible stack.
The problem to solve
A commerce backend has to get the unglamorous parts right: accounts that cannot be hijacked, an order path that reflects what is actually in the cart, and an admin surface shoppers can never reach. Here all of it — identity, catalogue, purchasing, media upload and outbound messaging — had to fit in a single service, built in a first professional role while a colleague developed the Flutter client against the same API in parallel; the endpoints had to stay stable and predictable enough to serve as the contract between two people working at the same time.
How it was built
The service is one Express application with a route module per resource and MongoDB collections underneath. Sign-up stores bcrypt-hashed credentials; login exchanges them for a JWT that middleware validates on protected routes. An admin role gates catalogue management, and phone verification ties each account to a reachable number. Product images arrive as multipart uploads through Multer, transactional email leaves over Nodemailer, and Firebase carries push notifications to the mobile app.
Docker Compose declares the API and its database as a single stack, so the backend the Flutter developer coded against locally is the same one that was deployed — brought up with one command rather than a hand-configured server.
What it does
JWT Auth with bcrypt
Passwords are stored as bcrypt hashes and sessions ride on JWTs; middleware checks the token on every protected route.
Phone Verification
Accounts confirm a phone number as a second identity check beyond email and password.
Categorised Product Catalogue
Product and category endpoints back the browsing experience; writes are reserved for the admin role.
Cart, Favourites, Orders
The whole purchase path is server-side: shoppers maintain a cart and a favourites list, and the cart becomes an order.
Multer Image Uploads
Image endpoints accept multipart uploads through Multer, giving the catalogue its product photography.
Email and Push
Nodemailer sends transactional email and Firebase delivers push notifications to the Flutter client.
Built with
Backend
Express keeps a resource-shaped REST API thin: each domain — products, cart, orders — is a router, and JWT checks, the admin gate and Multer parsing compose as middleware in front of the handlers.
The workload is almost entirely I/O — database reads, image uploads, email and push dispatch — which Node's non-blocking event loop serves from a single JavaScript runtime.
Data
Catalogue entities and per-user documents like carts and favourites map directly onto MongoDB documents, and the API returns them as the same JSON shapes the Flutter client consumes.
Firebase Cloud Messaging handles device-level push delivery to the Flutter app on both platforms, so the backend only triggers notifications instead of maintaining connections to phones.
Infrastructure
Docker Compose declares the API and MongoDB as one stack, so both developers and the deployment target run an identical environment from a single command.