Back to home

ALDEN ROYSTON — luxury watch platform

  • React 19
  • Vue 3
  • Spring Boot 3
  • MySQL
  • Redis
  • MinIO
  • i18next

aldenroyston.com

The website of a Dubai luxury watch brand, built to show the collection and bring in customers, in English and Arabic. I delivered all three phases alone: the design documents, the Spring Boot API, the Vue admin console, the React front end and the deployment. Live at aldenroyston.com.

The aldenroyston.com home page: a watch on a dark background, with the language menu in the header.
The home page of the live site.

The brief

The client asked for a site Google could find by the brand name, product pages with photos, video, specifications and prices, links to social media, the marketplaces and WhatsApp, and a way to list and unlist products. I was also to take care of the server and the domain. It had to open fast in the Middle East, and use video only where it would not slow a page down.

Before writing any code I wrote the architecture document (1,172 lines), the API design (1,836 lines) and the backend reference. The client preferred Java, Spring and MySQL, so that is what the backend uses.

System

The backend is Spring Boot 3 on Java 17, with MyBatis-Plus, Spring Security and JWT (24-hour tokens plus a refresh token), MySQL, Redis and MinIO. The front end is React 19 with TypeScript, Tailwind, i18next and Framer Motion; the admin console is Vue 3 with Element Plus. Public endpoints live under /api/v1 and admin ones under /api/v1/admin.

Fourteen tables: products with specifications, images, video, care instructions and tags; categories; home-page sections; contact links; files; users and roles. Redis caches product data, and if a transaction rolls back, a compensation step writes the old cache entry back.

Customer ReactAdmin VueOne APISpring BootMySQL + RedisMinIO Customer ReactAdmin VueOne API Spring BootMySQL + Redis MinIO

Two languages, both directions

Where the translations live

Every translatable field has a column per language: name, name_en and name_ar, and specifications keep both the label and the value in each. The first design had the backend choose a language from the request headers. In phase two we changed it: the API returns every language at once, and the front end picks one, falling back when a translation is empty. Switching language needs no new request, and the cache never has to be split by language.

Right to left

Switching to Arabic sets the page direction to right-to-left and its language to Arabic, and the browser mirrors the whole layout from the same components. Only the footer needed its own direction class. Interface text lives in i18next, 117 lines of it in each language.

What changed across three phases

Live chat, built and then removed

Phase one included live customer chat over Spring STOMP. Messages the server logged as sent never arrived. After five rounds of narrowing it down, the cause turned out to be that user-specific destinations need a Principal bound to the WebSocket session; a handshake handler that gives each connection its own identity fixed it. Six days later, phase two dropped live chat in favour of WhatsApp and social links, and I removed it from the database up, two tables included.

A home page the client runs

Phase two split the home page into four configurable sections stored as JSON, and phase three let the admin pick exactly which products each one shows. Care instructions and a fixed table of nine specifications (model, water resistance, case, movement, strap, diameter, thickness, strap width, weight) became bilingual.

Phase three, early

Tags with their own colours replaced the fixed "Featured" badge, contact links got full management, and production moved to versioned images. It was planned to finish on March 3 and was delivered on February 16.

Deployment and result

Three Docker services (API, front end, admin) with Compose overrides per environment. In phase three I set up Gitea Actions, then moved to building versioned x86 images locally and pushing them to a private registry: fixed tags, never "latest".

In its first 28 days the site had 1,200+ organic search clicks and 4,300+ impressions (Search Console).

Looking back: the architecture document recommended server rendering for search, and I shipped a single-page app with a fixed title and description. That met the brief, being found by the brand name. Ranking individual products would need prerendered pages and a sitemap.

Timeline

  1. 2025.06.05Phase one: repository, database design, documents
  2. 2025.06.18Live chat delivery bug traced and fixed
  3. 2025.06.24Phase two: live chat removed; bilingual care and specifications
  4. 2025.06.27Home page split into four configurable sections
  5. 2026.02.09Phase three begins
  6. 2026.02.16Tags, product picking, contact management; delivered early
  7. 2026.02.27Production moves to versioned images