product

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 y
  • aisleask_sections.kind text NOT NULL DEFAULT 'aisle'aisle | perimeter | facility
  • aisleask_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

  • listSections returns kind, pos_x, pos_y (additive).
  • addSection(userId, storeId, name, kind?) — kind defaults aisle.
  • 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_url flows through updateStore / sanitizeStorePatch (paste a URL).
  • POST /:storeId/map-backgroundgenerateStoreBackground — gpt-image-1 paints a painterly grocery interior (1536×1024, prompt keyed to the store name), uploads to the aisleask Storage bucket (store-maps/<storeId>.png, upsert + cache-buster), and sets map_image_url. ~$0.04/call, owner-triggered. Mirrors looking-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_h normalized, rotation degrees). 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.
AISLEASK STORE MAP — Docs | HiveJournal