Song Siwattanasombat

Loading portfolio

Back to projects

A custom full-stack stationery storefront created as the working demo before the owner moved the final store to Shopify.

  • React
  • Redux Toolkit
  • Node.js
  • Express
  • MongoDB
  • Stripe

Parin Studio began as a custom full-stack website built as a working demo for a nature-inspired stationery brand. As the developer and designer, I created the storefront, visual direction, product discovery, cart, checkout, customer accounts, order history, test-payment flow, and administration workflows. After the demo stage, the owner chose Shopify as the final commerce platform, and the customer-facing Shopify store was configured and designed to carry the same brand direction into launch. This case study focuses primarily on the custom web demo and its full-stack implementation, while the completed Shopify storefront is available through the Shopify Final Site link.

Project Scope

  • Responsive storefront
  • Customer accounts
  • Persistent cart
  • Guided checkout
  • Admin operations
  • Test payments

A small online stationery brand needs more than a product catalogue: customers need a dependable path from discovery to payment, while administrators need one protected place to operate the store.

  • The customer experience covers product discovery, search, pagination, product details, stock, reviews, a persistent cart, checkout, accounts, and order history.
  • The administration area manages products, users, orders, homepage content, store settings, and payment configuration.
  • Protected routes distinguish signed-in customers from administrators through authentication and role checks.
  • Payments and catalogue data are demonstrations; Stripe and PayPal use test or sandbox integrations rather than live commerce credentials.

From Store Requirements to Deployment

  1. 1Define Customer and Administrator Journeys
  2. 2Model Users, Products, Reviews, Orders, and Settings
  3. 3Build Express Routes, Middleware, Controllers, and Models
  4. 4Create React Screens and Reusable Interface Components
  5. 5Centralise API State with Redux Toolkit and RTK Query
  6. 6Integrate Authentication, Email, and Test Payments
  7. 7Deploy the Frontend and API as Separate Vercel Projects

The project was built as two coordinated applications: a React storefront and administration interface, plus a layered Express API connected to MongoDB and external services.

Storefront to Verified Order

Browse or search the product catalogue
View product details and stock
Add items to the persistent cart
Signed in?

No

Sign in or create an account

Yes

Continue to shipping
Enter shipping details
Select an enabled payment method
API rebuilds items, prices, tax, shipping, and total
Save the unpaid order in MongoDB
Payment provider

Stripe test checkout

Verify session, currency, amount, and order ID

PayPal sandbox

Verify completed order and captured amount
Transaction deducts stock and marks order paid
Confirmation email and order history

The checkout experience guides a customer from the catalogue to an order record, but the backend remains responsible for prices, stock checks, payment verification, and the final paid state.

The client stack was selected to support a multi-screen commerce interface with predictable navigation, shared state, and reusable API behaviour.

  • React 19 was chosen for component-based storefront and administration screens, while React Router 7 keeps customer and protected routes within one client application.
  • Redux Toolkit was selected over hand-written global state to organise authentication and cart state with less boilerplate.
  • RTK Query centralises REST requests, loading states, caching, mutations, and tag-based invalidation instead of duplicating request logic across screens.
  • React Bootstrap provides responsive, accessible interface primitives while custom styles establish the nature-inspired Parin Studio visual identity.

The server and infrastructure stack were chosen to keep the application JavaScript-first while supporting persistent data, protected workflows, and third-party commerce services.

  • Node.js and Express 5 provide a compact REST API and middleware pipeline that shares the same language as the React client.
  • MongoDB Atlas and Mongoose fit the document-shaped product, review, user, order, and settings data while adding schemas and relationship references.
  • JWT HTTP-only cookies and bcrypt keep session tokens outside client-side JavaScript and store password hashes rather than plain-text credentials.
  • Stripe, PayPal, Google OAuth, Nodemailer, and Vercel were integrated rather than rebuilding payments, identity, email delivery, and cloud deployment from scratch.

Full-Stack Application Architecture

Customer or Administrator
React FrontendVercel · React Router
Redux Toolkit + RTK QueryCart, auth, REST requests, cache invalidation
↓ HTTPS + credentials
Express REST APISeparate Vercel deployment

Application Layers

Auth + Role MiddlewareJWT cookie · administrator check
ControllersBusiness and payment logic
MongoDB AtlasMongoose models

External Services

Stripe + PayPalTest payment verification
Google OAuthExternal identity
SMTP EmailOrder and delivery notices

The API accepts credentialed requests only from the configured frontend origin and returns an HTTP-only JWT cookie for authenticated sessions.

The frontend and API are deployed independently. React and RTK Query call an Express REST API, which applies authentication and role middleware before controllers access MongoDB or external services.

The browser is not treated as the source of truth for an order. The API reconstructs order lines from database products, recalculates totals, checks ownership, and verifies the payment provider before changing payment and stock state.

  • Order creation ignores client-supplied prices and rebuilds each line from current product records.
  • Quantity and stock checks reject invalid, unavailable, or insufficient inventory before an order is accepted.
  • Stripe verification checks the order ID, paid status, AUD currency, and exact amount; PayPal verification follows the same server-side principle.
  • MongoDB transactions combine stock deduction with the paid-state update, and a stockDeducted flag protects against repeated deductions.
  • Order ownership prevents customers from reading or paying another user's order, while administration routes add an isAdmin role check.
  • CORS is limited to the configured frontend origin and authenticated requests include the HTTP-only JWT cookie.

Core Commerce Data Model

UserAccount · role · authentication

↓ places

OrderPayment + delivery state

↓ writes

ReviewRating + comment

↓ admin creates

ProductPrice + stock

Order contains

Order ItemsProduct reference · quantity · price snapshot

Each item references a Product

Product receives

ReviewsUser reference · rating · comment

Ratings remain connected to users

Site SettingsHomepage content · contact details · payment configuration

The data model connects customers, products, reviews, orders, order items, and store settings while preserving the product and pricing snapshot required for historical orders.

The portfolio demo is deployed as separate Vercel frontend and API projects with MongoDB Atlas and environment-based configuration. It demonstrates the complete workflow without claiming production commerce readiness.

  • The frontend receives the API address through configuration, while the API permits credentials only from its configured client origin.
  • Repository-hosted images avoid relying on Vercel's non-persistent serverless filesystem.
  • Payments are sandbox or test integrations, and PayPal is currently disabled in the deployed payment configuration.
  • The repository does not include a documented automated test suite; future work should add controller, payment, and end-to-end checkout tests.
  • Production hardening should add payment webhooks, stronger request validation, observability, image storage, accessibility audits, and recovery paths for interrupted checkout.
  • Email delivery is best-effort after order updates, so a durable queue would make notifications more reliable at production scale.