Case study: full stack build, site and dashboard
Salmon Guru, Dubai: a bar website the team runs itself
Salmon Guru is the Dubai home of the cocktail bar from Madrid, in Business Bay. The site shows the cocktails, the food menu and what is on this month, and every one of those is added and edited by the team from a dashboard behind it. I built both halves alone.

- Client
- Salmon Guru, Business Bay, Dubai
- Built
- Website, menu and events dashboard
- My role
- Everything, front end to back end
- Stack
- React, Vite, PHP 8.4, MySQL
A bar changes every week
Cocktail lists change. Dishes come and go. There is a different event next month. A bar website that needs a developer for any of that is a bar website that goes stale, and a stale menu costs more than a slow page.
So the site was built around its dashboard. The team signs in, adds a cocktail with its photo, edits a price, publishes next month's events, and the site updates. No developer, no waiting, no PDF to re-export.
What it is built with
| Part | Built with |
|---|---|
| Public website | React 19, built with Vite. One page, navigated by scrolling rather than a router library. Plain CSS with custom properties, no framework. |
| Found by search | Per-page titles and descriptions, and JSON-LD restaurant data written by hand, so the bar, its menu and its events read correctly in search results. |
| Back end and dashboard | PHP 8.4 with no third-party packages at all: a small front controller, a router, controllers and repositories, and server-rendered dashboard screens. |
| Logins | PHP sessions with bcrypt password hashing and a per-session token on every form, compared in constant time. |
| Images | Uploads are re-encoded to WebP on the server, with the smaller sizes generated automatically for phones. |
| Rich text | Event descriptions are cleaned against an allowlist, so what the team writes cannot break or attack the page. |
| The bar’s latest posts pulled from the Instagram Graph API, retried on failure and cached in the database so the site never waits on Instagram. | |
| Reservations | WhatsApp links, because that is how guests in Dubai actually book. |
| Tests | A dependency-free test harness, 226 assertions. |
| Deployment | GitHub Actions builds the site, and a deploy script pulls the new version, runs database migrations and puts both halves in place. |
Three decisions worth explaining
- A back end with no third-party packages. The PHP side uses none: no framework, no library, nothing to update at three in the morning because someone else's dependency had a security problem. For a site this size that is less code to own, not more.
- Instagram is cached, not fetched live. The bar's feed comes from the Instagram Graph API, retried if it fails and stored in the database with an expiry. If Instagram is slow or down, the site still loads at full speed with the posts it already has.
- Reservations go to WhatsApp. Not a booking system, because guests in Dubai message. The honest answer was a WhatsApp link, not a platform nobody would use.
Built to be handed over
Photos are re-encoded to WebP automatically, so nobody has to think about file sizes. Event text is cleaned against an allowlist before it is shown, so a pasted formatting mess cannot break a page. The whole thing ships through a build pipeline that runs database migrations on the way, so a change is one command rather than a careful evening.