AisleAsk — spatial Store Map
Ask (2026-07-24): each store gets its own page with a painterly grocery-store background, and drag-and-droppable aisles + sections placed on it — including the non-aisle perimeter (Produce, Meat & Seafood, Deli, Bakery, Floral, Pharmacy) and facilities (Front Entrance, Checkout, Restrooms, Customer Service). Drag/drop to lay out the real store.
Today AisleAsk sections are a flat ordered list (walk order). This adds a 2-D spatial layer on top of the same sections — the list stays the source of truth for the route; the map is a spatial view + editor of those same sections.
Data model (migration 570)
Additive on the existing tables — the map reuses aisleask_sections:
aisleask_sections.pos_x double precision— 0..1 normalized x on the map (null = unplaced, sits in the tray)aisleask_sections.pos_y double precision— 0..1 normalized yaisleask_sections.kind text NOT NULL DEFAULT 'aisle'—aisle|perimeter|facilityaisleask_stores.map_image_url text— the background image (a Midjourney/painterly grocery interior the owner pastes, or a generated one)
Normalized 0..1 coords so the layout survives any container size / image swap.
sort_order (walk order) is untouched — a section can be both in the walk order
AND positioned on the map.
Backend
listSectionsreturnskind,pos_x,pos_y(additive).addSection(userId, storeId, name, kind?)— kind defaultsaisle.POST /:storeId/sections/layout { positions: [{ id, pos_x, pos_y }] }— batch-save drag positions (one call on drop / debounced).POST /:storeId/sections/seed-perimeter— one-tap add the standard perimeter + facility zones if absent (Produce, Meat & Seafood, Deli, Bakery, Floral, Pharmacy =perimeter; Front Entrance, Checkout, Restrooms, Customer Service =facility).map_image_urlflows throughupdateStore/sanitizeStorePatch(paste a URL).POST /:storeId/map-background→generateStoreBackground— gpt-image-1 paints a painterly grocery interior (1536×1024, prompt keyed to the store name), uploads to theaisleaskStorage bucket (store-maps/<storeId>.png, upsert + cache-buster), and setsmap_image_url. ~$0.04/call, owner-triggered. Mirrorslooking-glass-scene-art.ts.
Frontend — the Map tab
A new 🗺 Map view on /dashboard/aisleask:
-
A canvas: the store background (
map_image_url, or a CSS painterly fallback). -
Each placed section renders as a draggable tile at
pos_x/pos_y; pointer-drag to reposition → normalized coords saved on drop. -
Unplaced sections (pos null) sit in a tray; drag onto the canvas to place.
-
A zone palette: aisle tiles are color A, perimeter B, facilities C, so the map reads at a glance. "+ Seed perimeter" adds the standard non-aisle zones.
-
Background: paste an image URL (bring a Midjourney painterly grocery interior).
-
Placed tiles carry geometry (migration 573:
pos_w/pos_hnormalized,rotationdegrees). Tap a tile to select it, then drag its corner handle to resize (stretch an aisle to its real length) or the ⟳ handle to rotate to the store's orientation. Each gesture saves only its changed fields via the batch layout endpoint. -
A Background opacity slider dims the painterly background (client-side view control) so the aisle/perimeter/facility tiles read while laying out.
Built blind first (like the glasses) — pointer-drag feel + tile sizing are on-device tuning. Reuses the existing sections; deleting/renaming still happens on the Store-layout tab.
Later (not v1)
- Storefront SEO page (asked 2026-07-24): pull the store's front-of-building
photo (upload / camera / Yelp / Google Places), run it through a painterly
artistic filter (gpt-image-1 image-edit), and use it as the hero of a public,
indexable per-store deals page — SEO surface for "<store> deals near me". Own
spec incoming:
AISLEASK_STORE_SEO.md. - Shopper "Shop" mode drawing the route as a path across the map.
- The crowd catalog carrying spatial coords so an adopted layout arrives pre-placed.