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.
Review.order_id is a required foreign key, not optional — this is what makes "verified purchase" structural rather than a UI label.
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:
Currency, tax rate, bounding box, default language — done in city-config.html in minutes, zero deploys.
Route planning, stop copy in each supported language, audio narration — the same work that went into Madrid's four tours.
Reference images for indoor pieces feed the image-recognition index; outdoor stops just need accurate coordinates for geospatial anchoring.
Check Google's Street View / VPS coverage for the new city's outdoor stops — this is a lookup, not engineering work.
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.