Skip to content
Baraa Fraigeh
All work
Case studyLive in production

ValYou

NFC & QR customer engagement platform for physical businesses.

A multi-location SaaS that turns a tap or scan at the counter into a Google review, an optional customer contact and analytics the owner actually reads — delivered as a weekly email report.

Role

Founder & Product Engineer — product, backend, frontend, data and deployment

Timeline

Aug 2026 — Present

Type

SaaS · Customer engagement

Visit live site Private repo · walkthrough on request
valyou · dashboard / overview

Overview

All locations

Last 14 days

Taps (NFC)

142+12%

Scans (QR)

97+8%

Review clicks

118+15%

Contacts

36+5%

Interactions by source

NFC QR

Top locations

  • Downtown
  • Waterfront
  • Mall kiosk
Weekly report scheduled · Mon

Problem

Restaurants, cafés and shops live on Google reviews, but asking for one is awkward, and the moment leaves no data behind. Owners can't tell which location, table or touchpoint drives engagement — and they don't have time to live in a dashboard.

Solution

Physical NFC/QR cards point to dynamic, server-side redirects. Each tap opens a branded bilingual page that leads to the Google review flow and optionally collects contact details. Every interaction is recorded by card, location and source, and summarised into dashboards and a weekly email report.

Stack

Frontend
Next.jsReactTypeScriptTailwind CSSshadcn/uiReact Query
Backend
Node.jsExpressTypeScriptPrismaPostgreSQLRedisBullMQ
Infrastructure
Ubuntu VPSNginxPM2SSLGitHubBrevo SMTP

01 — Problem

Reviews matter. Asking for them doesn't scale.

Physical businesses — restaurants, cafés, retail, salons, clinics — depend on Google reviews for discovery. In practice, staff forget to ask, customers forget to follow through, and the interaction leaves no trace.

Owners also lack a basic view of engagement: which branch, which counter, which card is actually generating interactions. The tools that exist are built for marketers who spend their day in dashboards, not for a café owner with ten minutes a week.

Users
Business owners, staff, end customers, platform admins
Constraint
Zero friction for customers — no app, no forced sign-up
Constraint
Owners need answers without opening a dashboard

02 — Product

A tap at the counter, a weekly answer in the inbox.

Each business receives NFC/QR cards for its locations. A tap or scan opens a branded page in English or Arabic that leads to the Google review flow and lets the customer optionally share their name and phone number — with clear, privacy-focused messaging and no mandatory promotional sign-up.

Every interaction is recorded with its card, location and source. Owners see engagement per location and card in a dashboard, and receive a weekly email summarising what happened. Plans scale by the number of locations and cards a business can run.

Request flow · tap to review
  1. 01

    Tap or scan

    NFC chip or printed QR opens a stable ValYou URL.

  2. 02

    Resolve card

    Lookup card → location → business; check it is active.

  3. 03

    Record event

    Append interaction with source (NFC / QR) and timestamp.

  4. 04

    Redirect

    Branded page → Google review, optional contact form.

Every physical interaction passes through a server-side redirect that records it first.
ValYou NFC review card: tap a phone or scan the QR code to review the business on Google
Physical entry point — NFC chip and printed QR on one card

03 — Architecture

A small number of well-separated moving parts.

The frontend is a Next.js App Router application serving three audiences: public customer pages, the business-owner dashboard and the super-admin console. It talks to a single Express + TypeScript REST API.

Inside the API, routes stay thin: validation and authorization happen at the edge, business rules live in services, and Prisma handles persistence to PostgreSQL. Anything slow, scheduled or dependent on a third party — weekly reports, transactional email, Google data sync — is pushed to BullMQ queues on Redis and processed by separate worker processes.

System architecture
UBUNTU VPS · PM2EXTERNALenqueueCustomerNFC tap · QR scanOwner / AdminBrowserNginxTLS · reverse proxyNext.jsDashboards · pagesExpress APIAuth · RBACPostgreSQLPrisma ORMRedisBullMQ queuesWorkersReports · emailGoogle APIsLocations · reviewsBrevo SMTPEmail delivery
Request path (solid) and asynchronous work (dashed).

04 — Domain model

Business is the tenant, the billing boundary and the permission scope.

The most important early decision was getting the ownership graph right. A Business owns its Locations; Cards belong to a Location and carry a stable public code; every tap or scan is an immutable Event that references the card, the location and the source. The Subscription attaches to the Business, not to a location or a user.

Users relate to businesses through a role, so an owner, a staff member and a platform super-admin all resolve permissions through the same path — and every query is scoped by business.

Domain model
1:nn:11:11:n1:n1:n1:nUser◆ id email password_hash roleBusinessUser◆ user_id◆ business_id roleCustomerContact◆ business_id name? phone? consentBusiness◆ id name slug logo_urlSubscription◆ business_id plan status trial_ends_at period_endLocation◆ id◆ business_id name google_location?Card◆ id◆ location_id public_code activeInteractionEvent◆ card_id◆ location_id source: NFC|QR created_at
Simplified entity model. Field names are illustrative.

05 — Decisions

Engineering decisions

ADR-01

Gate features at the business level

Context
Plans differ by how many locations and cards a business can run. Attaching plans to users or locations would make limits ambiguous for multi-location owners.
Decision
The subscription belongs to the business. A single entitlement resolver turns the active plan (or trial) into limits; services check it before creating locations or cards, and the dashboard reads the same entitlements to render upgrade states.
Trade-off
One resolver must stay in sync with the plan catalogue — in exchange, limits are enforced in exactly one place.
ADR-02

Dynamic redirects, never hard-coded card URLs

Context
A printed card is permanent. Its destination, owner or status may not be.
Decision
Cards encode a stable ValYou URL. The redirect target is resolved server-side on every request, which also records the interaction and its source (NFC or QR) before forwarding.
Trade-off
The redirect sits on the critical path, so it does the minimum — lookup, record, redirect — and defers everything else.
ADR-03

Short-lived access tokens, rotating refresh tokens

Context
Dashboards stay open for long periods; sessions must be revocable.
Decision
Access tokens are short-lived. Refresh tokens are stored server-side, rotated on use and revoked on logout. On the client, a single in-flight refresh is shared by concurrent requests, so a burst of 401s triggers one refresh instead of a race.
Trade-off
More state than stateless JWTs, but sessions can actually be ended.
ADR-04

Idempotent provisioning

Context
Super-admins provision businesses, owners, locations and subscriptions. Double-clicks, retries and slow networks are normal.
Decision
Provisioning runs as a single transaction guarded by unique constraints and an idempotency check, so a repeated request returns the existing result instead of creating a second business or re-applying a trial or payment.
ADR-05

Analytics from raw events

Context
Counters updated in place drift, and dashboards and emails start disagreeing.
Decision
Interactions are stored as append-only events with card, location, source and timestamp. Dashboards and weekly reports aggregate from the same events over explicit date ranges, so both always tell the same story.
ADR-06

Integrations behind queues and caches

Context
Google APIs have quotas and latency; a dashboard shouldn't wait on them.
Decision
Location connection and disconnection are explicit lifecycle actions. Review data is synced by background jobs and served from the database, rather than fetched live on each page load.
Trade-off
Review data can be slightly behind real time — acceptable for this product, and far more predictable.

06 — Auth flow

Authentication that survives real usage.

Concurrency is the hard part of refresh tokens. When a dashboard fires several requests with an expired access token, naive clients send several refresh calls, and with rotation enabled all but one fail — logging the user out.

The client wraps the fetch layer so the first 401 starts a refresh and every other request waits on that same promise, then retries with the new token.

Sequence · token refresh
Dashboardconcurrent requestsFetch layersingle-flight refreshAPIauth middlewareToken storehashed refresh tokensGET /locations · GET /analyticsaccess token (expired)401 × 2POST /auth/refresh — onceverify · rotate · revoke oldnew refresh tokennew access + refreshretry both requests200 OK
Single-flight refresh with token rotation.

07 — Background jobs

Keep the request path fast; do the rest in workers.

The API enqueues; workers execute. Weekly reports, transactional emails and integration sync are BullMQ jobs on Redis, with retries and backoff for transient failures. Workers run as separate PM2 processes, so a slow SMTP response or third-party API never blocks a customer's tap.

Background jobs
REDIS · BULLMQAPIenqueue on requestSchedulerrepeatable · weeklyreportsqueueemailqueuesyncqueueWorkersretries · backoffPostgreSQLread events · writeBrevo SMTPsend reportGoogle APIssync locations
Scheduled and on-demand jobs flow through Redis-backed queues.
  • Weekly report: aggregate events per business → render email → send via Brevo SMTP
  • Transactional email: invitations, account and provisioning notifications
  • Integration sync: refresh connected Google location data outside of page loads

08 — Production

Deployed and operated, not just built.

ValYou runs on an Ubuntu VPS. Nginx terminates TLS and reverse-proxies to the Next.js app and the API; PM2 supervises the web, API and worker processes. Configuration is environment-based, and email is delivered through Brevo SMTP on the product domain.

Production topology
UBUNTU VPSPM2InternetHTTPS :443NginxTLS · proxy · redirectswebNext.js processapiExpress processworkerBullMQ consumersPostgreSQLprimary storeRedisqueues · cache
Production topology.
  • TLS certificates and HTTPS redirects at the proxy
  • Separate processes for API and workers so they scale and restart independently
  • Environment-specific configuration, secrets kept out of the repository
  • Error monitoring for production debugging

09 — Result

Live in production.

ValYou is live at valyou-lb.site with three tiers — Starter, Pro and Premium — that scale by locations and cards, and a provisioning flow for onboarding new businesses.

The architecture leaves room to grow: new plans are configuration, new reports are jobs, and new entry points are just another event source.

Status
Live in production
Plans
Starter · Pro · Premium
Languages
English · Arabic
Next
Access Business's Google Reviews and Add AI Analysis