Data model & scale-out

Barcelona is a content pack, not a rebuild.

The brief asked for "Madrid, with architecture flexible enough to add cities later." That constraint shaped the schema from the first table: City is a first-class entity everything else hangs off, not a config flag bolted on afterward.

Core entities
City
language[]string[]
currencyISO 4217
tax_ratedecimal
boundsgeometry
map_providerenum
statuslive/dev/planned
Tour
city_idfk → City
categorygallery/street
stops[]ordered fk[]
offline_pack_urlstring
Stop
tour_idfk → Tour
coordinatespoint
geofence_radiusmeters
ar_target_idfk → ARTarget
artwork_idfk → Artwork
locale_content{}map<locale,text>
ARTarget
methodgeospatial/image
reference_imagestring
lookup_codestring
last_verifiedtimestamp
Artist
bio{}map<locale,text>
social_links[]string[]
stripe_account_idstring
kyc_statusenum
Artwork
artist_idfk → Artist
medium, dimensionsstring
edition"n/total"
price{}map<currency,decimal>
Order
items[]fk[] → Artwork
statusenum
stripe_payment_intentstring
delivered_attimestamp
Review
order_idfk → Order (required)
rating1–5
moderation_statusenum

Review.order_id is a required foreign key, not optional — this is what makes "verified purchase" structural rather than a UI label.

Rolling out city #2

Because City holds language, currency, tax rate, map bounds and AR-provider region as data — not code — launching Barcelona is a content and configuration exercise. Here's what actually has to happen:

Config
Create the City record

Currency, tax rate, bounding box, default language — done in city-config.html in minutes, zero deploys.

Content
Produce tours

Route planning, stop copy in each supported language, audio narration — the same work that went into Madrid's four tours.

Content
Photograph AR targets

Reference images for indoor pieces feed the image-recognition index; outdoor stops just need accurate coordinates for geospatial anchoring.

One-time
Confirm VPS coverage

Check Google's Street View / VPS coverage for the new city's outdoor stops — this is a lookup, not engineering work.

One-time
Onboard local artists to Stripe Connect

Each artist completes Stripe's own onboarding flow — no custom payment code per country.

No item on this list is "write new app code." That's the payoff of building the multi-city architecture into Madrid from the start, instead of retrofitting it after city #2 is requested.