F&A Móveis
A furniture catalogue where every measurement is real, and every sale ends in WhatsApp
In plain English
A furniture shop's whole online catalogue, with real prices and real centimetre measurements on every piece — no cart, just a WhatsApp message pre-filled with the exact product, sent straight to Fátima, the owner.
My role
Solo full stack developer
Timeline
Ongoing
Team
Solo
Status
Live
Design
Product tour



Section 01
The problem
Fátima has run a neighbourhood furniture business in Rio de Janeiro for years with no website — just a Facebook page that had gone dormant since February 2022. She resells factory furniture, delivers it, and assembles it, and every sale already happened over WhatsApp. This was a paid client project on a tight budget where the demo had to come before the money.
Section 02
How I approached it
The site is deliberately backend-less: a typed TypeScript catalogue in content/, no CMS, no database, no monthly bill. Every measurement is stored as a number in centimetres and formatted at the edge — never hand-typed as a display string — and every wa.me link is built by one function reading her real phone number from a single content module. Nothing outside lib/catalog/source.*.ts is allowed to import a Shopify type, which keeps a later Shopify upsell a one-module swap instead of a rewrite. Where a price wasn't confirmed, the page says so — 'Consulte o preço' — instead of shipping a plausible number.
Outcome
Live at fa-moveis.vercel.app with 13 real products — the 27-item illustrative catalogue used to win the pitch was retired once real supplier stock replaced it. 10 of the 13 now carry a confirmed price; the other 3 show an honest 'Consulte o preço'. A production build measured Lighthouse 93 performance and 100 accessibility on /produtos, CLS 0, every product image under 32 KB against a 180 KB budget.
Section 03
Going deeper
A demo that had to come before the money
This was a paid client project on a tight budget, and a working site — built on her real brand, shown to her on her own phone — was what won the job in the first place. Real stock replaced the original illustrative catalogue only once it existed.
Nothing outside the seam touches Shopify
Every component is written against a domain Produto type. A later move to Shopify, or any other backend, only has to change the files behind lib/catalog/source.*.ts — nothing else in the app needs to know the difference.
Honest pricing, not estimated pricing
10 of 13 products carry a confirmed price, sourced from her own D'Doro line (3 pieces, priced via WhatsApp) and a second Novo Horizonte supplier (10 pieces, priced from a real supplier sheet, using the same freight-and-tax markup as an earlier sibling project). The remaining 3 say 'Consulte o preço' rather than a plausible guess.
Section 04
The build process
Scaffold on her real brand
Name, mark, the rose accent (#A87C7C), and a Didone serif were already hers, evidenced in her own Facebook video — the job was bringing an existing identity onto the web with better craft, never redesigning it from zero.
A typed catalogue, no CMS
content/produtos.ts, categorias.ts, ambientes.ts, and loja.ts became the single source of truth for every page and component.
Real stock, real prices
The 27-product illustrative catalogue was removed once real supplier stock replaced it — 3 D'Doro pieces from her own catalogue QR codes, 10 Novo Horizonte pieces priced from a supplier sheet.
The real-device checklist
A pass against the live deployment, not localhost, caught two defects invisible from a dev server: every WhatsApp message was shipping a literal localhost URL, and /produtos had no Open Graph card.
Section 05
How the pieces fit together
Each layer has one job. Read it top to bottom — that's roughly the path a request takes through the system.
Next.js App Router
Server-rendered catalogue, product, and home routes — zero client components in the shipped build.
content/*.ts
Typed product, category, and store data — the only source any page or component is allowed to read.
lib/whatsapp.ts
The one wa.me builder used by every product CTA, reading the phone number from content/loja.ts.
Vercel
Fully static, no database, no auth — a production build fails on purpose if SITE_URL would resolve to localhost.
Section 06
What it does
Real measurements, formatted at the edge
Every dimension is stored as a number in centimetres and rendered as 'L × A × P' — never typed as a display string.
Honest pricing
10 of 13 products show a confirmed price; the other 3 say 'Consulte o preço' instead of a guess.
One WhatsApp builder
Every product page resolves through the same pre-filled wa.me link — no second place composes that URL.
No cart, no checkout
The whole product terminates in a conversation with the owner, matching how she already sells.
Section 07
The hard parts
A localhost URL that shipped to production
An unset SITE_URL fell back silently to localhost, so the deployed site's own WhatsApp messages carried a dead link — caught by a real-device pass against the live URL, not the dev server, and fixed by failing the build outright on that exact misconfiguration.
Sourcing prices for stock that wasn't hers to guess
Novo Horizonte's 10 pieces needed real supplier-sheet numbers and the same freight-plus-tax markup logic already used on a sibling project — 3 items still show 'Consulte o preço' because that number wasn't confirmed yet.
Retiring the demo catalogue without losing the pitch
The original 27-item illustrative catalogue existed to win the job before real stock was ready; removing it once 13 real products existed meant the site never quietly kept selling furniture that wasn't actually in stock.
Section 08
What I took away
- A working demo built on the client's real brand — even before real stock exists — is what actually wins a tight-budget pitch, more than a polished mockup.
- Failing a production build outright on a known misconfiguration (SITE_URL resolving to localhost) catches a class of bug a real-device checklist would otherwise keep re-discovering.
- An honest 'Consulte o preço' is a better default than a plausible price, especially on a site the owner shows to her own customers.
Catalogue
13 real products, 10 priced
Conversion
wa.me, no cart, no checkout
Data
Typed TS, no CMS, no database
Measured
Lighthouse 93 perf, 100 a11y
Let's build something worth shipping
Available for freelance projects, full-time roles, and technical consulting. Tell me what you're building and I'll tell you honestly whether I'm the right person for it.
Based in Rio de Janeiro, Brazil · Working with teams in any timezone · Fluent in English and Portuguese