E-Commerce
End-to-end commerce platform spanning customer, staff, and admin workflows.
React · TypeScript · NestJS · MySQL · Capacitor · Docker
01Problem
A customer app and an admin app with staff views, both backed by one API that owns prices, stock and media.
Shopping, product and inventory management, staff operations and admin work had to run as one system, on phone and web.
02My role
Primary developer
03What I built
Customer app
React · Capacitor for mobile
Admin app
React · staff views
REST
Backend
NestJS · TypeORM
Database
MySQL
Media
S3
Packaged with Docker
Cloud
AWS Elastic Beanstalk
- A customer app packaged for mobile with Capacitor, and an admin app with staff views.
- Product management, inventory tracking and QR scanning.
- Staff permissions set per system and per order type, checked on the server.
- Item photos and videos uploaded from the camera or the gallery in the staff app.
- Order creation and order history for customers.
- Product images and videos stored on S3.
- Docker images deployed on AWS Elastic Beanstalk.
04Engineering decisions
Option A
The totals the client sends
Option BChosen
The server, from stock data
- Trade-off
- Trusting the client is less code. Computing server-side needs a lookup per item, but the request body can’t set its own price.
- Decision
- Totals come from server-side stock prices. Body prices are ignored, every field is validated, and orders are rate-limited per phone.
- Why
- It closes price tampering, and bad input gets a clear 400 instead of an opaque 500.
Option A
A public S3 bucket with CORS
Option BChosen
A backend proxy
- Trade-off
- Direct S3 links skip a hop. A proxy adds load to the API, but nothing has to be public.
- Decision
- Media is served through the backend, with a local-disk fallback for older files.
- Why
- No public bucket, no CORS rules, and pre-migration files keep working.
05What I learned
Correctness and security live behind the UI. Server-side pricing, sign-in timing and media handling showed me how small assumptions become production bugs.