Back to Projects
E-commerce2025

Bakery E-commerce & Management System

A bakery needed one system to handle online ordering, custom cakes, delivery/pickup, payments, and staff operations instead of juggling disconnected tools. I built a full-stack e-commerce and management platform: a customer storefront plus a multi-role admin dashboard for admin, order staff, baker, and accountant roles, with an end-to-end order workflow and automated bank-transfer payment verification. Built with Next.js 16, React 19, TypeScript, Tailwind CSS 4, Node.js, Express 5, PostgreSQL, Supabase, JWT, VietQR, and SePay.

Bakery E-commerce & Management System
Next.js 16React 19TypeScriptTailwind CSS 4Node.jsExpress 5PostgreSQLSupabaseJWTbcryptVietQRSePayNodemailer
Full-stack project — repo not published

The Problem

The business was running ordering, custom cake requests, delivery coordination, and payment confirmation across separate manual channels, making it hard to track order status or verify payments without back-and-forth.

Challenges

  • Modeling a five-stage order workflow (pending → confirmed → baking → delivering → delivered) that stays consistent across the storefront, admin dashboard, and notification emails
  • Automatically matching incoming bank-transfer webhooks (VietQR/SePay) to the correct order without manual reconciliation
  • Supporting four distinct staff roles (admin, order staff, baker, accountant) with different permissions on the same data, without duplicating dashboard code per role

Key Decisions & Trade-offs

Supabase (PostgreSQL) with Row Level Security plus backend middleware authorization

RLS gave a database-level safety net for a relational order/customer/payment model, while still enforcing the real business rules explicitly in backend middleware rather than relying on RLS alone.

Webhook-based payment verification (VietQR + SePay) instead of manual confirmation

Matching transaction metadata to order references automatically removed the slowest, most error-prone step in the original manual process — someone checking a bank app and updating order status by hand.

Results

  • Bank-transfer payments are verified automatically against order references instead of manual reconciliation
  • Four staff roles operate from one shared dashboard with role-appropriate permissions instead of separate tools
  • Customers get a clear order status pipeline from placement through delivery

Lessons Learned

  • Designing the order-status state machine before writing storefront/admin UI paid off — every downstream screen just reflects one shared source of truth
  • RLS is a strong safety net but not a substitute for explicit authorization checks in backend middleware — treating it as the only guard would have been a mistake