An honest local guide,
built with AI.
azoresbyrui.com is a local-first travel platform for the nine islands of the Azores. Brutally honest, opinionated, unsponsored. Built and operated by one resident, with AI as a collaborator on research, code, and content.
This document is the real, unpolished record of how that product was designed, built, and shipped.

A local travel platform.
Not a blog.
Not a directory.
An opinion engine.
Every place on the site has been personally visited, eaten at, or hiked by a single resident of São Miguel. No affiliate links. No sponsorship. No "top 10" lists generated from Tripadvisor scrapes.
The product carries opinion as a first-class object. Each entry surfaces a clear verdict (Top Pick, Worth It, Meh, Skip It) alongside a numeric score and a written explanation of why.
This project was also a real-world experiment: how far can a senior product designer take a full live product using AI as the primary building tool? The honest answer is in this case study.
Recommendations come from one resident. No editorial team chasing SEO.
Every place gets a verdict. 'Skip It' is a feature, not a bug.
Zero affiliate links. Zero paid placements. Zero sponsored reviews.
Built with Lovable, ChatGPT, Claude, and UX Pilot. All decisions human.
Most Azores travel guides are SEO farms with affiliate links wearing the costume of advice.SEO
The top-ranking pages are written to match keyword intent, not to be useful. They list 25 places. They've been to none.
Many 'best of' posts surface what pays them most: booking widgets, tours, hotels. All buried under editorial language.
The best tasca on the island has 12 Google reviews and no website. The mediocre tourist restaurant has 4,000 and a marketing team.
The phrase is used so often it now signals the opposite. Real gems aren't advertised; they're mentioned in a Reddit reply.
Half the 'top 10' places I tried were tourist traps. The food was fine but nothing special. Felt scammed by every guide I read.
Honestly? Skip the lists. The places locals actually go are the ones with 30 Google reviews, no English menu, and a queue of regulars at 1pm. Nobody writes about them because there's no affiliate link.
I asked an AI for restaurant recs and it gave me the same names as the first Google result. We're in a loop.
The trust gap in travel content is not a writing problem. It's an incentive problem.
Reading 700+ angry comments
before opening Figma.
I scraped every "what should I do in the Azores" thread from the last two years. Tagged each answer by category, sentiment, and whether the recommender actually lived here.
Locals over-index on a handful of unglamorous things. Tourists ask for those exact things and get sent to the photogenic, mid ones instead. By Google. By Tripadvisor. By AI assistants now too.
| Keyword | Vol | KD | A | B | C | |
|---|---|---|---|---|---|---|
| things to do são miguel | 18,100 | 72 | 1 | 2 | 4 | azoresbyrui |
| best restaurants azores | 9,900 | 64 | 3 | 1 | 7 | — |
| azores itinerary 7 days | 6,600 | 58 | 2 | 4 | 1 | — |
| hidden gems são miguel | 2,400 | 41 | 1 | 5 | 9 | — |
| where to eat ponta delgada | 1,900 | 38 | 4 | 2 | 6 | — |
| best viewpoint sete cidades | 1,300 | 32 | — | — | — | GAP |
| tasca são miguel local | 880 | 24 | — | — | — | GAP |
| free bathing area furnas | 590 | 19 | — | — | — | GAP |
Three competitors owned 90% of high-intent keywords with content none of them had personally verified.
The gap between ranking authority and lived authority became the entire positioning of the product.
The chips do the
emotional heavy lifting.
This is not a corporate token sheet. The Azores by Rui design system exists to do one job: communicate opinion clearly so a tourist skimming dozens of places knows, in 300ms, whether I'd send a friend there. Every chip below is rendered live from the production codebase.
Top tier. I'd recommend this without hesitation.
A solid choice. I'd recommend it.
Average. Nothing special about it.
Disappointing. I'd save your time.
Every score is explainable.
Each criterion can be tapped to read why the number is what it is, in plain words. Trust requires showing the seams.
Inter for body text. Set in #36443B for warmth, never pure black. Long-form descriptions, reviews, captions.
Four tools.
Four very different jobs.
Clustering 734 Reddit comments into themes. Drafting interview prompts. Translating Portuguese sources. Generating SEO-friendly outline structures. Never used for final copy. Its travel voice is too generic.
First-person review drafts in Rui's voice from raw notes. Better at restraint and tone than ChatGPT. Used for debugging dense problems (RLS, sitemap, canonicals). Everything still rewritten by hand before shipping.

The entire production codebase. React + Supabase backend, edge functions, sitemap, OG meta, RLS policies, image pipeline. Iterated on real components, not throwaway prototypes.

Burn through 20 layout directions in an afternoon. Picked none of them. Still learned what NOT to do. Used as a thinking tool, not an output tool.
The rating chip went through
eight versions.
Generic 5-star. Looked like Tripadvisor. Conveyed nothing.
Just the number. Cleaner, but no semantic signal at all.
Added a verbal label. Colour was wrong. Green for everything felt dishonest.
Four-tier semantic colour. Closer. Outline felt too quiet on listing cards.
Filled pill. Worked. But all chips looked identical on a long page.
Added icons. Too many shapes competing. Score got lost.
Split score visually. Solved hierarchy. But 'unrated' broke completely.
Rebalanced weights and shadow. Community rating was about to be split into a separate chip, but the verdict alone finally felt finished.

Bilingual, FTS-backed, grouped by what the tourist actually typed.
Search resolves both Portuguese and English queries against the same index. Results group by Places, Experiences, and Fun Facts, so the answer feels structured instead of infinite.
The unglamorous bugs
that actually shipped the product.
People keep asking what "the AI" did. There is no the AI. Each model is good at one slice of the problem and unusable for the others. The skill is knowing which one to reach for, and when to override it.
Search Console kept comparing canonical URLs against the Lovable preview subdomain. Locked the production host list in seo.ts; emitted noindex/nofollow on every non-canonical host.
An AI-generated draft confidently described a place that does not exist. Added a publishing gate: nothing ships without is_published=true and a verified visit_log entry.
supabase/migrations/publishing_guard.sql + create policy "must_be_verified" + on public.places for select + using ( + is_published = true + and exists ( + select 1 from visit_log + where place_id = places.id + ) + );
Original 4MB uploads were being served on mobile. Built a strict fallback chain (Medium → Large → Thumbnail → Transformation) so the smallest acceptable variant ships first.
Public listing pages silently truncated at 1,000 rows. Replaced every fetch with a paginated .range() loop and a unit test that fails if a helper forgets it.
lovablehtml.com → Cloudflare → Lovable origin. Three different URLs were claiming to be canonical. Single source of truth in canonical.ts; everything else derives.
Draft experience_items were SELECT-able by the anon role. Caught in security scan. Restricted to is_published=true OR admin role before launch.
The verdict chip rendered after the place title settled, pushing the entire card down 36px on first paint. Reserved height with a min-h skeleton so layout locks before async data lands. CLS dropped from 0.21 → 0.02.
First pass shipped every photo as 60% WebP. Looked fine on hero, looked plasticky on food close-ups. Switched to a per-variant quality curve: thumbnail 0.80, medium 0.82, large 0.85. Capped source width at 2400px so phone uploads stop being 6MB.
Legacy /place/<slug> URLs co-existed with the new /places/restaurants/<slug>. Google indexed both. 301 redirects with a custom-selected canonical fixed it in one crawl cycle.
None of this is glamorous.
But it's part of the job.
What ten weeks of shipping
actually taught me.
AI made execution faster. Judgement was still the hard part.
Ten weeks. One product, live in production. Models in every part of the loop. A handful of lessons I didn't expect, and none of them are about prompts.
Taste became more important, not less.
When the model generates ten viable directions in an hour, the bottleneck moves to knowing which one is right. The cost of generating dropped to almost zero. The cost of choosing went up.
Systems outranked visuals.
The chip I shipped on launch day looks almost identical to v4. What changed wasn't the pixels. It was the system underneath. What unrated means. When community shows. Why two ratings never blend. Visuals followed the logic.
Shipping exposed problems prototypes hid.
Every interesting bug in this case study only appeared in production. Canonical drift. CLS from late chips. The hallucinated restaurant. Real users, real Search Console, real Lighthouse runs. Figma never warned me about any of it.
Authenticity beat optimised content.
I wrote 'skip it' on places real tourists drive an hour to see. That one editorial decision did more for trust than any SEO page. The product's voice is the product. AI cannot fake having actually been there.
Iteration got cheaper. Decisions got more expensive.
AI made eleven chip versions almost free. It also made it tempting to keep going forever. The skill became noticing the difference between iterating because the answer is unclear, and iterating because I was avoiding the call.
Product thinking became the real bottleneck.
Design, code, and copy all got faster. The only thing that didn't was the work of figuring out what the product should refuse to do. That work scales with the designer, not with the model.
Senior work didn't get easier. It got more concentrated.
The boring parts compressed. What was left was almost entirely the hard part. Framing. Taste. Judgement. Restraint. AI made the job feel more senior, not less.
"AI helped me move faster. It did not replace product thinking.
If anything, it made taste the bottleneck again."
The model can ship a homepage in twenty minutes. It cannot decide whether the homepage should exist. That decision is still the most expensive thing on the page.
Every interesting choice in this project was a judgement call. What to publish. What to leave unrated. What to refuse to recommend. AI gave me leverage on everything around those calls. It never made one for me.

