Farhaan Beeharry
Software Engineer
© 2026 All rights reserved.
Lokal
Lokal gives a small business or an
independent entrepreneur a professional digital presence —
discoverable, contactable, and theirs. Customers search the
directory, browse a business profile with its products and
services, and get in touch directly by
WhatsApp, phone or e-mail.
The scope is deliberately tight: Lokal is a directory, not an e-commerce platform. There is no cart, no checkout, no order and no customer payment anywhere in the product. The only money that changes hands is the seller's one-time activation fee, transferred out of band and verified manually by an administrator — which keeps the product honest about what it does and removes an entire class of payment and fulfilment complexity.
The app has exactly four surfaces: a public website (landing, about, contact, FAQ, legal), a visitor experience for searching and viewing businesses, a seller portal with a 7-step onboarding wizard and a dashboard, and an admin CRM for metrics, moderation, activation verification and seller support.
It is built on React 19 + TypeScript with a clean, feature-sliced architecture — each feature owning its domain (types, Zod schemas, pure rules), application (TanStack Query hooks), infrastructure (the only layer allowed to talk to Supabase) and presentation layers. Business rules such as "when may a seller submit for activation" live in plain, React-free, unit-tested domain code.
Security sits in the database rather than the client: a business moves
A small decision with a large payoff: the seller's preview step and the public profile page are rendered by the same component. What a seller previews therefore cannot drift from what visitors actually get — a whole class of "it looked fine in preview" bug simply cannot occur.
For visitors
For sellers
For administrators
Accounts
Engineering
The scope is deliberately tight: Lokal is a directory, not an e-commerce platform. There is no cart, no checkout, no order and no customer payment anywhere in the product. The only money that changes hands is the seller's one-time activation fee, transferred out of band and verified manually by an administrator — which keeps the product honest about what it does and removes an entire class of payment and fulfilment complexity.
The app has exactly four surfaces: a public website (landing, about, contact, FAQ, legal), a visitor experience for searching and viewing businesses, a seller portal with a 7-step onboarding wizard and a dashboard, and an admin CRM for metrics, moderation, activation verification and seller support.
It is built on React 19 + TypeScript with a clean, feature-sliced architecture — each feature owning its domain (types, Zod schemas, pure rules), application (TanStack Query hooks), infrastructure (the only layer allowed to talk to Supabase) and presentation layers. Business rules such as "when may a seller submit for activation" live in plain, React-free, unit-tested domain code.
Security sits in the database rather than the client: a business moves
draft → pending_activation →
active, and a seller cannot publish
themselves — Row Level Security restricts them to the first
two states, and publication only happens inside an
admin-gated Postgres function.
A small decision with a large payoff: the seller's preview step and the public profile page are rendered by the same component. What a seller previews therefore cannot drift from what visitors actually get — a whole class of "it looked fine in preview" bug simply cannot occur.
For visitors
- Directory search with filters kept in the URL — linkable, bookmarkable, back-button safe
- Category and location filtering
- Business profiles with photos, description and social links
- Opening hours parsed from untrusted JSON, including past-midnight spans and day-range grouping
- Map location via Leaflet
- Product and service catalogue with fixed, "as from" and price-on-request pricing
- One-tap WhatsApp, call, e-mail and website links, with the digits-only normalisation
wa.merequires
For sellers
- 7-step onboarding wizard with a stepper and progress tracking
- Image upload with in-browser cropping
- A completion gate that spells out exactly what is still missing before activation
- Live preview rendered by the same component visitors see
- Dashboard to manage profile, contacts, socials and opening hours
- Product catalogue CRUD
- Activation request submission and status tracking
For administrators
- Platform metrics dashboard
- Business moderation and suspension
- Activation request verification and approval
- Seller support tooling
Accounts
- Sign-up, login, password recovery and reset
- Session handled push-based through Supabase's subscription rather than polling
- Route guards per surface — visitor, seller, admin
- A password policy defined once and derived by both the Zod schema and the on-screen checklist
- Login deliberately does not apply the strength rule, so existing accounts can still sign in
Engineering
- English / French throughout, including the legal documents — which are structured data, not hardcoded prose
- A test fails the build if the two languages drift in key coverage, if a French string is empty, or if legal section ids stop matching (which would produce dead anchors in one language only)
- Errors carry translation keys, not sentences, so no raw Postgres message ever reaches a user
- Server state in TanStack Query, client state in Zustand, search filters in the URL — one home per kind of state
- One source of truth per concept: routes, query keys and design tokens each defined in exactly one file
- 65 tests aimed at where a mistake would be silent: contact-link building, opening-hours parsing, the activation gate, price rendering, i18n parity
- Environment variables validated at startup so a bad value fails loudly instead of surfacing deep inside the Supabase client
- Accessibility built in: skip links, focus-visible rings, wired label / hint / error relationships,
role="alert"androle="status", aria-hidden skeletons with a single announcement, andprefers-reduced-motion
Found, then contacted
The visitor directory, a business profile and the seller onboarding wizard — recreated from Lokal's real screens and its orange brand palette.
Visitor directory & search
Boulangerie Bo Vallon
Bakery · Quatre Bornes Open
Bakery · Quatre Bornes Open
Opening hours
Mon – Fri06:00 – 18:00
Sat06:00 – 13:00
SunClosed
Products & services
Pain maison
Rs 25
Gâteau anniversaire
as from Rs 900
Catering
On request
WhatsApp
Call
Public business profile
Products & services
Pain maison
Price
Rs 25
Type
Fixed
Before activation
Profile & logo
Contact details
Opening hours
Continue
Seller onboarding wizard
React 19
TypeScript (strict)
Vite
Tailwind CSS
shadcn/ui + Radix
React Router
TanStack Query
Zustand
React Hook Form + Zod
i18next
Framer Motion
Leaflet
Supabase
Postgres RLS
Vitest
If you would like a walkthrough or a demo access account,
please contact me on
contact@farhaan.info