mapped.
Published city guides connected through one geographic system
RGuide turns researched city knowledge into a spatial product travelers can browse, trust, and use in place. I designed and engineered the complete platform—from the interaction model and responsive system to the database, publishing tools, media pipeline, localization, and production operations.
open_in_new Explore the live product
From Prototype to Platform
The product moved from a local-data map prototype to a production platform in 105 calendar days. Select a milestone—or watch the build advance—to follow the change in emphasis.
Built the split-screen explorer, responsive map behavior, route structure, and first local guide model.
The governing decision stayed consistent: increase the structure behind the interface without increasing the complexity in front of the traveler.
The System at a Glance
The system is organized in layers. Open any layer below to see what it owns and why the separation matters.
01 Experience Map + route + responsive UI
A Next.js App Router interface keeps the map, destination hierarchy, filters, guide rail, selected guide, and selected place synchronized. URLs represent real product state, so an interaction can also become a shareable and indexable page.
- Desktop split-screen and mobile sheet patterns
- Map camera, boundary, marker, and guide-selection state
- City, category, guide, event, venue, creator, and locale routes
02 Application Server reads + client state
Server components and scoped endpoints assemble only the destination and guide data a route needs. Zustand and focused React hooks handle transient explorer state, favorites, itinerary workspaces, and places-been behavior without turning the database into UI state.
- Scoped app-data and editorial-guide reads
- Authentication, profile, submission, and analytics endpoints
- Static HTML and local fallbacks for graceful degradation
03 Data Normalized source of truth
Supabase/Postgres stores destinations, venues, editorial entries, stops, events, schedules, classifications, hours, media, and citations as reusable records. PostGIS points and boundary polygons turn the editorial model into a geographic one.
- Relational records replace legacy blob-table workflows
- Canonical venues share facts across many guides
- Row-level policies separate public reading from controlled writes
04 Delivery Views + caches + media
Database views and versioned render caches transform normalized records into the stable card shape expected by the interface. Cloudflare R2 holds canonical imagery and responsive renditions, while local snapshots protect key destination and boundary experiences from upstream outages.
- Normalized records → render view → versioned cache
- Source image → canonical media → responsive renditions
- Live data → scoped fallback → crawlable output
05 Operations Publish + verify + learn
Purpose-built scripts and runbooks make content operations repeatable. Guide publishing resolves entities, verifies structure and hours, ingests media, refreshes caches, and audits the final route. Localization, analytics, SEO, and event workflows use the same operational discipline.
- Guide, event, media, hours, and translation pipelines
- Schema, content-source, SEO, and publish verification
- First-party click analytics and affiliate attribution
Designing the Data Model
The decisive implementation shift was separating authored meaning from rendered presentation. Early content could move quickly as local objects, but every new guide repeated destinations, venue facts, images, and sources. That made scale fragile: a venue closure or changed opening time could require edits in many unrelated lists.
The normalized model gives each fact one owner and lets guides compose those facts into an editorial point of view.
Canonical records converge through secure views, versioned caches, and localized delivery.
This structure supports both reuse and editorial specificity. A venue owns its address, coordinates, operating state, classification, hours, and canonical media. A guide stop owns the reason that venue belongs in a particular story, its order, contextual copy, and journey timing. Updating shared truth no longer erases the authorial reason for inclusion.
A Typed Taxonomy Instead of Generic Tags
Food, nightlife, stay, nature, culture, activities, routes, and essentials need different filters. The schema therefore uses typed fields—lodging type, food service type, cuisine, nightlife type, music genre, price tier, and curated attribute vocabularies—rather than a single undifferentiated tag array.
That structure powers useful questions in the interface: Which neighborhoods are strongest for cocktail bars? Which stays are social but not party hostels? Which restaurants are reliable after midnight? The filtering model is a direct expression of the content model.
Building the Publishing Engine
Content quality depends on operations, not only copy. I created a repeatable pipeline that treats a guide as a dataset with editorial judgment.
Define the user need, guide scope, authoritative sources, and minimum stop quality.
Match destinations and reuse canonical venues before creating any new entity.
Write entries and ordered stops with classification, coordinates, sources, and hours.
Ingest canonical media, responsive renditions, boundaries, and provider-backed details.
Generate render views, refresh current caches, and expose the guide through scoped routes.
Audit hours, sources, schema shape, media, URLs, SEO output, and live rendering.
The repository contains dedicated workflows for editorial guides, destination descriptions, city boundaries, venue hours, weekly events, R2 media, translation batches, cache refreshes, and verification. These are small operational products inside the product: each one defines inputs, quality gates, failure handling, and a deterministic output.
Built to stay useful when a service fails.
A travel guide should not disappear because a database or image service is temporarily slow. RGuide prepares a verified version of published content so the essential experience can remain available.
Serve the newest published version.
Structured destination, venue, hours, source, and media records are assembled into a frontend-ready guide. The interface requests only the city or guide the traveler is viewing.
Use the last verified version.
Saved guide content, map boundaries, destination descriptions, and image fallbacks keep the page usable while the live service recovers.
A reusable product language.
The wireframes isolate the logic behind the interface before the visual system is applied: geographic orientation stays visible, guides remain comparable, and every editorial claim resolves into a useful place.
Two scales, one model
From product shell to guide detail- 01Browse by hierarchyThe left rail narrows the world into regions, countries, cities, and neighborhoods.
- 02Keep position visibleThe map remains present while the traveler changes scope or compares options.
- 03Filter consistentlyThe same category system follows the traveler through every geographic level.
- 04Compare before openingThe guide index summarizes the choice before revealing the full editorial route.
- 01OrientName the guide, its category, scope, and available actions.
- 02Keep contextExpose adjacent guides without ejecting the traveler from the city.
- 03Explain and provePair editorial rationale with sources and an ordered visual route.
- 04Resolve to actionTurn the guide’s argument into a specific place a traveler can use.
- 1
- 2
- 3
- 4
- 5
- 6
Tokens and controls
Small rules establish system-wide behaviorThe system in use
City orientation → expanded editorial guideThe interface uses one consistent mental model across scales. The left side answers where am I? The map answers how does it relate spatially? The guide rail answers what is worth doing and why? Selecting a destination, neighborhood, category, guide, or place updates the other surfaces rather than creating disconnected navigation modes.
Interaction and Routing Work Together
- City and neighborhood boundaries load only when they become relevant.
- Guide markers, selected places, and the camera share one state model.
- Expanded guides update the URL immediately, preserving the current destination and category context.
- Each city, category, guide, event, and venue has crawlable server-rendered output in addition to the interactive explorer.
- The responsive system reorganizes the same hierarchy into mobile controls and sheets rather than reducing it to a separate, weaker product.
Performance and Delivery Systems
Map products become slow when everything is treated as global. RGuide instead reduces work at every layer.
Routes request the current city, destination, or guide instead of repeatedly loading the complete editorial catalog.
Neighborhood scoring and boundary geometry wait until the user reaches the relevant destination scope.
Normalized joins are converted into versioned, frontend-ready payloads with an explicit current-cache contract.
R2 ingestion creates canonical, deduplicated image records and right-sized renditions for cards and details.
Metadata, sitemaps, canonical URLs, server output, and local fallbacks keep search access independent of client interaction.
A web manifest and service worker turn the responsive site into an installable web app without forking the experience.
Systems for Growth
The same architecture supports product growth without turning the core explorer into an advertising shell.
- Localization: normalized translation tables and locale-specific render caches preserve one canonical English record while delivering complete Spanish routes, metadata, and sitemaps.
- SEO: city, category, query-focused guide, event, venue, country, and continent routes translate explorer state into useful entry points for search.
- Analytics: first-party click collection batches events, records campaign context, and powers a protected internal dashboard while retaining a Vercel analytics layer.
- Monetization: stay calls-to-action use city and guide context to create attributable affiliate routes without changing editorial ranking.
- Participation: authentication, profiles, favorites, saved places, and controlled guide submission add user value while keeping public write paths gated.
Pageview growth, actual to projected.
The solid line accumulates verified production pageviews. The dotted continuation projects the recent viewing rate forward four weeks.
- Observed pageviews
- 7,912
- Unique visitors
- 1,115
- Four-week projection
- 9,332
What the build proved.
RGuide proved that a travel platform can grow without making the traveler experience harder to use. From the first prototype to 749 published entries, the interface kept the same clear pattern while the system underneath became more structured and reusable.
Facts are stored once.
Destinations, venues, events, hours, sources, and images each have one shared record instead of being copied into every guide.
Correct a fact once; every guide that uses it receives the update.Guides add the meaning.
Editors can explain why a place matters, when to visit, and where it belongs in a route without rewriting its underlying facts.
Shared data stays accurate while every guide keeps its own point of view.The interface stays simple.
Focused APIs, ready-to-render views, responsive images, caches, and fallbacks keep the map fast as the catalog grows.
Travelers see a consistent product—not the complexity behind it.World to street.
The same geographic model carries a traveler from broad orientation to a useful, editorially curated route.
World→Continent→Country→City→Neighborhood→Guide
-
01
Orient
World
Begin with a spatial overview of available travel knowledge.
-
02
Focus
Europe
Move from the global index into a browsable regional collection.
-
03
Narrow
Spain
Compare destinations through a country-level view.
-
04
Explore
Barcelona
Pair city context, live geography, and editorial guides.
-
05
Understand
Neighborhoods
Move between districts without losing city context.
-
06
Act
Selected guide
Open a curated route designed for use on the street.