Skip to content

Store / Catalogue — Claude Design prompt ​

Status: ready to send · Target: the "QR setu Design System" Claude Design project · Owner ask, 2026-08-09: "the current catalogue screen in our design system is too simple and generic. We can use it as a reference, but the actual experience needs to be modern, feature-rich, and thoughtfully designed."

This page is the specification and the prompt. Everything in §1–§9 is grounded in what the v2 backend can actually serve today (schema quoted in §3) — so the returned design is buildable rather than aspirational. §10 is the copy-paste prompt.

Revised 2026-08-09 before sending, on an owner challenge (QRS-449): "we shouldn't accidentally design a domain-specific experience and then treat it as a generic Store/Catalogue foundation." Correct, and measurement found the risk was not the Ganapati persona (§2 explains why that stays) but a missing feature-split: store and store.media apply to all 14 industries while store.stock applies to 6 of 14, all of them goods. §2.1 is new and is the part of this document most likely to be skimmed and most expensive to get wrong.


1 · Why the existing screen is not enough ​

The shipped CatalogScreen is a flat list of rows: name, formatted price, an out-of-stock chip, and a bottom-sheet composer with four fields. It is a correct CRUD screen and a poor Store. Three specific gaps, all of which the schema already supports:

GapThe schema already has
No images, so every row looks identicalcatalog_item_media (ordered, with alt_text) + one media table
No grouping, so 40 items are one scrollcatalog_categories with position
Price is one number; no discount, unit, tax or variantscompare_at_price_minor, unit, tax_rate_bp, price_includes_tax, catalog_item_variants

And one product gap the schema cannot fix on its own: the screen renders state and prompts no action. CLAUDE.md's proactive-value gate rejects that by name — "if the honest answer is it lets them see/store X, the feature is not finished."

2 · Who this is for — the CONTEXT persona, and why it is not a domain persona ​

A Ganapati stall vendor in Pune, on a ₹8,000 Android, standing in their stall, adding an idol they finished this morning, one-handed, while a customer waits.

Not a Shopify merchant at a desk. Consequences that must show up in the design:

  • One-handed reach. Primary actions in the bottom third. Never a top-right "Save".
  • Adding an item must survive interruption. They will be interrupted mid-entry, every time.
  • Photos are taken, not uploaded. Camera first, gallery second, never a file picker.
  • Devanagari and English mix inside one field ("गणपती मूर्ती - small"). Type must not clip or reflow.
  • Money is ₹ with Indian grouping (₹1,50,000 — not ₹150,000).
  • Offline-tolerant. Patchy 3G is the normal case, not the edge case.

They serve category 1 (solo business owner) — CLAUDE.md's primary R1 audience. This is not the enterprise multi-location Store; that is a later, separate design.

⚠ This is a DEVICE-AND-CONTEXT persona, not an industry brief, and the distinction is the whole reason §2.1 exists. Every one of the six consequences above is equally true for a boutique owner, a salon, a tutor or an electrician in the same city on the same phone: none of them is specific to festival goods. The persona is named because a personaless prompt returns a desktop-shaped Shopify screen, which is the failure this document exists to prevent.

What DOES vary between industries is in §2.1, and it varies by FEATURE — never by archetype or industry. The one thing that must not be read out of this section is "design a festival-stall app". festival_stall's primitive composition is ['catalogue','ledger'] — 2 of 11, deliberately the thinnest in the taxonomy (the industry row says so in its own comment), so every other industry is a superset of it. A design that serves this vendor generalises upward; a design that assumes stocked physical goods everywhere does not.

2.1 · The variance axis — the Store is THREE features, not one ​

This section is load-bearing. A design that ignores it produces a Store that 8 of 14 industries cannot use.

The platform model is industry × archetype × primitives × grants (ADR-0020/0021). The Store surface is composed of three independently-grantable features, each backed by a different primitive:

FeaturePrimitiveApplies toCarries
storecatalogue14 of 14 industriesitems, categories, price, unit, tax, variants, availability, ordering
store.mediacatalogue14 of 14 industriesphotographs and galleries
store.stockledger6 of 14 industriestrack_inventory, stock_quantity, out-of-stock state

ledger is enabled for festival_stall, dairy, tiffin, kirana, boutique and sweet_shop — every one of them goods. It is enabled for ZERO time industries and ZERO expertise industries. So for a salon, a yoga trainer, a tutor, an electrician, a real-estate agent, a car-sales agent, a photographer and a direct seller, stock is not a concept and its control must not exist — not disabled, not empty, absent.

Two things that read alike and are not the same:

store.stock applicabilityDoes this business have inventory at all? Derived from primitive composition. If no, the whole surface is gone.
track_inventory per itemWithin a business that does have inventory, does the merchant count this item? Their own opt-in choice.

Design the Store so its item form composes rather than branches. The core (name, description, photo, price, unit, category, availability, ordering) is universal; stock is an additive section that may be entirely absent; media is a section that is present today for everyone but must not be structurally load-bearing either.

The gating vocabulary is FEATURE, never archetype or industry. "When store.stock is available, the item form gains a stock section" is correct. "For goods businesses, show stock" is a defect: branching on archetype or industry in app code is lint-gated (ADR-0021 D4), so a design expressed that way cannot be implemented as drawn.

The same universal screen must be shown serving all three archetypes, because kind and unit already span them and the fields are otherwise designed but never exercised:

ArchetypeWhat an "item" iskindunitstore.stock
Goods — a stocked item11-inch idol · a kurta · 500 ml milkproduct · menu_itempiece · kg · litreavailable
Time — a slota haircut · a yoga batch · a tuition termservice · coursehour · session · monthnot applicable
Expertise — an enquirya wiring job · a 3BHK listing · a wedding packageservice · package · listinghour · day · piecenot applicable

For Time and Expertise a price is frequently indicative rather than final, so "from ₹X" and "price on enquiry" must both be expressible without inventing a field: compare_at_price_minor is the was price and is not that, and there is no price_type column. Show how the design handles it within §3's fields, or say plainly that it cannot.

3 · The data contract — design only against these fields ​

Every field below is real and readable today. Do not invent fields; anything not listed does not exist and cannot be rendered.

catalog_itemsid · category_id · kind · name · slug · description · price_minor · compare_at_price_minor · currency · hsn_sac · tax_rate_bp · price_includes_tax · unit · availability · track_inventory · stock_quantity · position · attributes (jsonb) · status

  • kind ∈ product · service · package · menu_item · course · listing
  • unit ∈ piece · kg · g · litre · ml · metre · hour · day · month · session
  • availability ∈ available · out_of_stock · discontinued · coming_soon · draft
  • ⚠ price_minor is INTEGER PAISE. 45000 = ₹450.00. Never show a raw paise number.
  • compare_at_price_minor is the was price; the discount % is derived, never stored.
  • tax_rate_bp is basis points (1800 = 18% GST). price_includes_tax decides inclusive/exclusive.

catalog_item_variants — name · price_minor · stock_quantity · position (e.g. "11 inch", "18 inch") catalog_item_media — ordered images with alt_text; first = primary catalog_categories — name · slug · position, merchant-defined, per workspace

  • ⚠ attributes (jsonb) is NOT merchant-editable in R1 and must not be designed. It is the industry-variable field bag (a yoga item's {level, duration}, a listing's {bedrooms, carpet_area}), and it is deliberately not projected onto the public card (ADR-0014). Until an industry declares a typed field set, there is no UI for it. Designing a generic key/value editor here would put arbitrary merchant JSON in front of a non-technical user and invent the schema by accident.

Deliberately NOT available — do not design for these: cost price/margin (never leaves the merchant), per-item analytics (no analytics table exists yet), orders, reviews, barcode scanning, attributes.

4 · What the design must deliver ​

4.1 The Store overview (the main screen) ​

  • A real header that tells the merchant where they stand, not a title bar. Item count, how many are live vs draft, and whether the card is published.
  • Category-grouped, image-led items. A dense but scannable grid or rich list — the image is the identifier for a merchant with 40 idols, not the name.
  • Search + filter that a non-technical user can operate — by category, by availability. Filter must never be a hidden icon-only affordance.
  • Reorder by drag (position exists for exactly this). A merchant's own ordering is what the public card renders.
  • Empty state that proposes the first action, not one that describes the screen.
  • Per-item state visible at a glance: draft, out of stock, no photo, discounted.

4.2 Add / edit an item ​

  • Progressive, not a wall of 20 fields. Name + price + photo are the 80% path and must be reachable in one screen; unit, tax, category, variants, stock are revealed on demand.
  • Photo capture up front, multi-image, reorderable, with the primary one obvious.
  • The price field takes RUPEES and shows ₹ with Indian grouping. Add "was" price inline, with the discount % computed and shown live.
  • Variants as a repeatable row (name + price + stock), added only if the merchant wants them.
  • Availability as a real 5-state control, not an on/off switch — the shipped screen exposes 2 of 5.
  • Stock is two-layered, and both layers must be drawn (§2.1). The stock section is present only when the store.stock feature is available — absent entirely for 8 of 14 industries, not disabled and not empty. Where it is present, track_inventory is still the merchant's per-item opt-in. Show the item form both with and without the section, and make sure the form does not look truncated or unbalanced in the absence case.
  • Draft-first is legitimate: saving an incomplete item must be possible and clearly marked.

4.3 Proactive surfaces — required, not decorative ​

This is the part that makes it a product rather than a form. Every one below is derivable from stored state; none fabricates an insight.

Design a SLOT with a fixed anatomy, not a fixed list of nudges. The action item is one reusable component; its content is configuration attached to the workspace's industry or archetype, resolved at runtime (ADR-0009). A nudge drawn into the screen for one vertical is the conditional sprawl the platform model exists to prevent, and branching on archetype or industry in app code is lint-gated (ADR-0021 D4). So the deliverable is: the anatomy (icon or count, one line of plain-language claim, one primary action, a dismiss), plus enough example renderings to prove the anatomy holds.

Universal — available to every industry:

  • "3 items have no photo" → a dated, dismissible action item that deep-links to those items. (Rationale to show the merchant: items with photos get more enquiries.)
  • "Your card is still a draft" → publish prompt. The card is created draft by provisioning, so this is the single most valuable nudge in the product.
  • A first-item celebration that leads to share your card, not to a dead end.

Feature-conditional or industry-configured — each must degrade to absent, never to a disabled tile:

  • "2 items are out of stock" → restock or hide. Requires the store.stock feature, so it does not exist for 8 of 14 industries (§2.1).
  • A seasonal or cyclical prompt, whose copy is industry configuration. Render two different examples so the anatomy is visibly not built around one of them: "Ganesh Chaturthi is in 3 weeks — add your seasonal items" (festival stall) and "12 customers are due to reorder this week" (direct seller). A design that only draws the first will be implemented as a festival feature.

Anti-noise rules (hard): in-app surfacing only, never a push. Dismissible. Never more than two action items visible at once. Never a fabricated number.

4.4 The seam that must be designed deliberately ​

The merchant edits in the app (React Native); the customer sees the public card (DOM web). Those are two renderers over one design-token package, and the merchant must be able to trust that what they build is what a customer sees. Design an explicit "preview as customer" affordance — it opens the real live card URL, it is not a second renderer.

5 · Visual direction ​

  • Follow the existing design system. Apple-style soft corners (rounded-3xl shells, rounded-2xl inner panels), Plus Jakarta Sans for UI, Baloo 2 for display, the QR-monogram gradient only for brand/emphasis — never as a flat accent.
  • Zero hard-coded colours. Semantic tokens only.
  • Light AND dark, both complete. Non-negotiable.
  • Restrained motion. Compositor-friendly transforms; every animation reduced-motion-aware.
  • Modern but not trendy — this must still look right in three years to a merchant who is not design-literate.

6 · Screens to return ​

  1. Store overview — populated (≈12 items, 3 categories), with an action item visible
  2. Store overview — empty state
  3. Store overview — search/filter active
  4. Add item — the 80% path (name, price, photo)
  5. Add item — expanded, store.stock AVAILABLE (unit, tax, category, variants, stock)
  6. Add item — expanded, store.stock NOT AVAILABLE — the same form for a salon or a consultant, with the stock section absent rather than disabled. This is the screen that proves the design composes instead of branching (§2.1); without it the Store is a goods-only design.
  7. Item detail / edit, including the delete confirmation
  8. Category management
  9. The action-item surface (inline card, sheet or banner), shown with two different configured examples so the anatomy is visibly not built around one vertical (§4.3)
  10. Store overview for a Time or Expertise business — the same screen listing services or packages priced per hour, session or month, with no stock state anywhere. May be a variant of (1) rather than a new layout; the point is to prove the layout survives the content change.

Each with light + dark, at 360×740 (the tightest real device) as the primary artboard.

7 · Constraints the design must respect ​

  • Touch targets ≥ 44px. Enforced by an automated gate, not a preference.
  • WCAG AA contrast on every text/background pair. accent is a fill token — it fails AA as small text.
  • No em dash or en dash in any copy. Gated. Use a comma, colon, parentheses, or two sentences.
  • Every string is an i18n key — en / hi / mr. Devanagari must not clip at any size.
  • No in-app purchase or upgrade CTA. Apple 3.1.3(d): the native app is a free companion. A quota prompt may say a limit was reached; it may not link to payment.
  • One codebase, three surfaces (Android native · iOS native · Web PWA). Nothing may depend on a gesture or capability that does not exist on all three.

8 · What NOT to design ​

Orders/checkout · reviews · per-item analytics charts · barcode scanning · cost price or margin · multi-location or org-level Store · an admin builder UI · anything requiring a field not in §3.

9 · How this will be judged ​

  1. Could a stall vendor add a photographed, priced item one-handed, in under 60 seconds, on a ₹8,000 phone?
  2. Does the screen prompt a next action, or only display state?
  3. Is every rendered value backed by a field in §3?
  4. Does it hold at 360×740 in Devanagari, in dark mode?
  5. Would it still look considered next to a 2029 app?
  6. Does the same design serve a salon and a consultant, with the stock surface absent rather than disabled — and does the item form still look complete without it? (§2.1)
  7. Is the action item a slot with configured content, or a fixed list of nudges written for one vertical? (§4.3)

9.1 · THE DESIGN EXISTS, in the prototype project — and there are TWO projects ​

⚠ Read this before auditing anything in Claude Design (QRS-451). The design is split across two projects and CLAUDE.md names only one:

ProjectTypeHolds
37245d93… "QR setu Design System"DESIGN_SYSTEMThe token and component library — 43 components, 11 token files, and six templates/* that predate the current screen set
633dc069… "QR setu prototype"PROJECTThe actual screens — 19 mobile-console, 13 admin-panel, 4 customer-flow, 4 onboarding. It vendors the library in as _ds/qr-setu-design-system-37245d93…/

The Store design is prototype/mobile-console/Catalogue.dc.html in the prototype project, and it is sound — see §9.2. An earlier audit of the library project found no Catalogue and concluded the prompt had never been applied; that was wrong, and the lesson is recorded as QRS-451: an absence proves nothing until the search space is established.

The two screens in the LIBRARY project that are still not a starting point ​

Both are pre-v2 and neither may be edited or forked:

FileWhat it isWhy it is not the Store
ui_kits/merchant-console-v2/modules.jsx → Catalogue({ ws })A 27-line desktop 3-column grid inside a 1280×860 consoleIts sample data is ws.domain === 'cafe' ? [chai items] : [salon items], and the console's default workspace is "Chai & Charcha, Café · Bandra West" — which is the whole reason it reads as a restaurant menu
ui_kits/qrsetu/MenuBuilder.jsxThe legacy Digital Menu builder (Masala Chai ₹40, an on/off Switch per item, an in-app second render of the public menu)Digital Menu is legacy/, excluded from R1, and slated for an R2 re-home onto Goods. Its Edit/Preview split also contradicts ADR-0019's one-renderer decision

Three specifics from the console module must never be carried forward:

  1. ws.domain === 'cafe' is exactly the industry branching ADR-0021 D4 lint-gates. The module's own subtitle claims "the same screen serves any business; only the fields change by category" while the code hardcodes two industries — the gap between intent and implementation, in one file.
  2. A Schema: menu item chip exposes internal vocabulary to a merchant.
  3. A sponsored FeaturedTile renders in the first catalogue grid cell (getPromo('catalogue.tile')). ADR-0004 requires the promo seam to be inert and fail closed forever in R1 while compliance_profile/ad_restricted does not exist. It is also an ad shown to the merchant inside their own catalogue, which is a product decision nobody has taken.

⚠ That console's manifest still encodes the pre-v2 model and should not be read as current: PLAN_RANK {free, pro, business}, DOMAIN_LABELS {cafe, salon, clinic, retail} — café and clinic are excluded verticals — a duplicate menu module alongside catalogue, and flat feature:'orders'|'bookings'|'payments' flags rather than ADR-0021's 8 scopes × 3 axes.

Leaving both untouched is the reuse rule applied correctly: the surface differs, so nothing about them is being reused.

9.2 · The returned design, validated against this spec ​

prototype/mobile-console/Catalogue.dc.html — a single interactive prototype (390×864) with two sheets (sheetForm, sheetCategories) rather than ten static artboards, which is better than what §6 asked for. It uses this spec's data contract verbatim: price_minor in paise (×106 references), compare_at_price_minor (×48), track_inventory (×45), availability (×45), variants (×55), unit, tax_rate_bp, price_includes_tax, position, plus कुल्हड़ Chai for the Devanagari mixing case.

§2.1's variance is implemented the right way — one screen, a switchable businessProfile:

Demo profilehasStockpublishedindustryNudge
Cafe · Chai & Charchatruetruenull
Salon · Glow Studiofalsefalsenull
Yoga studio · Sahyadri Wellnessfalsetruenull
Festival stall · Ganpati Bappa Artstruetrue"Ganesh Chaturthi is in 3 weeks…"
Distributor · Shree Wholesale Traderstruetrue"12 customers are due to reorder this week."

hasStock:false on the two Time businesses is precisely the store.stock absence §2.1 demanded, and industryNudge is per-profile configuration carrying both contrasting examples §4.3 required. The published:false salon profile supplies the "your card is still a draft" state. The design is correct on the point this document exists to enforce.

Defect 1 — the default demo profile, and why Cafe nonetheless STAYS ​

default: 'Cafe · Chai & Charcha', so the file opens on a café menu until the dropdown is changed. That is the whole of what was reported as "our Ganapati example came out as a restaurant menu" — demo data, not structure. The default moves to Festival stall, the R1 launch vertical.

⚠ An earlier draft of this section said to REMOVE the Cafe profile. That was wrong, and the schema settles it: catalog_items.kind is check (kind in ('product','service','package','menu_item','course', 'listing')) — menu_item is a first-class kind in v2, so a profile exercising it is legitimate, and Digital Menu's R2 re-home onto Goods is a recorded decision (owner, 2026-08-09). The draft prompt's instruction that "menu_item should now appear nowhere" contradicted our own CHECK constraint.

The constraint that belongs on OUR side, not in the design: there is no cafe row in industries (verified — all 14 seeded rows), so the Cafe profile is R2-only and must never become an app test fixture. apps/mobile/.../catalog/testFixtures.ts takes its shapes from the four current-industry profiles, never from this one.

No duplication and no per-industry fork. That would start a path to 14 Store screens, is unimplementable (one Expo Router route serves all 14 and archetype branching is lint-gated), and is the defect QRS-449 corrected here.

Defect 2 — Distributor has stock, and the taxonomy says it should not ​

hasStock: true on the Distributor profile, while store.stock is backed by ledger and direct_seller.enabled_primitives is ['catalogue','party','recurrence','balance','fulfilment'] — no ledger. One of the two is wrong. QRS-453 recommends fixing the TAXONOMY, not the design: a distributor genuinely holds boxes, and ledger "carries a UNIT, so it also serves points and litres", which is the volume-point accounting MLM compensation bands on. Owner decision.

⚠ Note the shape of this find: validating the design against the schema caught a SCHEMA defect. That is the argument for doing this validation at design-return time rather than at implementation time.

9.3 · Validation of the corrected design (2026-08-09, after §10.1 was applied) ​

Verdict: compliant. Every instruction followed, nothing invented, no structural drift. Verified by diffing profile blocks by content (line-based diffing gives false positives here — the new profiles shift every line below them):

CheckResult
Default profile✅ Festival stall · Ganpati Bappa Arts, and first in the enum
Profile count✅ 5 → 8
Cafe · Salon · Festival stall · Distributor✅ byte-identical to the previous version
Yoga studio✅ changed only where instructed (the kind:'course' item, unit:'month')
New profiles✅ Dairy hasStock:true · Boutique hasStock:true · Real estate hasStock:false — all three match enabled_primitives (dairy and boutique have ledger, real_estate does not)
kind coverage✅ all six: product 24 · menu_item 12 · service 9 · listing 5 · package 5 · course 1
unit coverage✅ piece · session · litre · kg · month · g · ml
Structure✅ sheetForm, sheetCategories, toast unchanged — no screen or sheet added or removed
Invented fields✅ none. "2BHK", "sq ft" and "facing" appear only inside name and description, exactly as instructed
New price-type field✅ none added — and that constraint produced QRS-456, below

Two findings, neither a design defect.

F1 — price_minor = 0 is the on-enquiry sentinel, and it cannot stand (QRS-456) ​

Told to express "price on enquiry" using only existing fields, the design used zero — 3 of its 5 listings carry price_minor:0, plus a form hint: "Leave price at 0 to show 'Price on enquiry' on your card." It had no alternative: price_minor bigint not null check (price_minor >= 0).

The sentinel is ambiguous with genuinely free (a free demo class, a free consultation), it is a value the platform reasons about (Buy vs Enquire CTA) which ADR-0010 says must be a typed column, and it breaks sort and filter in the one vertical where price filtering is the primary query — "under ₹50L" would match every on-enquiry listing. Recommendation: a pricing_mode enum 'fixed' | 'on_enquiry', with 'from' staying derived — which the design already does correctly, computing it from the cheapest variant and storing nothing.

✅ Forbidding the design from inventing a field is what made this visible rather than letting a plausible price_type column arrive with no decision behind it.

F2 — the Distributor profile is a wholesaler, not a direct seller (QRS-453 option c) ​

Its items are Toor Dal, Basmati Rice, Sunflower Oil, Milk, Paneer, Ghee — a B2B grocery wholesaler. But direct_seller is archetype expertise, described as "Reorder-cycle tracking … MLM", with recurrence + balance and no ledger. A dal-and-rice wholesaler is goods, so the content contradicts the archetype of the row it represents — and is very likely why hasStock:true was chosen. Fixing the content resolves QRS-453 with no taxonomy change. Not urgent: it is demo data.

Which additional demo profiles earn their place — three, not ten ​

A profile earns inclusion by exercising a distinct ITEM SHAPE, never by being a distinct industry. ADR-0020's governing economics apply to the design too: the cost is O(primitives), not O(industries), and fourteen demo profiles would pay O(industries) inside the design.

CandidateVerdict
real_estateAdd — kind:'listing', hasStock:false, price on enquiry. The only shape with no fixed price, covered by nothing
dairyAdd — the reference composition (9 of 11 primitives), unit:'litre', a recurring commitment
boutiqueAdd — stocked, non-seasonal, size variants. ADR-0021's explicit contrast case against dairy
tutorSkip — primitives identical to yoga_fitness
tiffinSkip — its own row comment says "structurally identical to dairy"
kirana · sweet_shop · photographer · electrician_plumberSkip — recombinations that do not change what an item looks like
car_salesSkip for now — the flagship Enterprise case, but its Store concerns are ADR-0022/0023 subtree sharing and campaigns, a different screen that R1 does not have

How per-industry difference is expressed — four mechanisms, all DATA ​

Recorded because "different store types have different requirements, handled during client-side and backend development" is two-thirds right and one-third the exact inversion to avoid. The structure is identical for all 14 industries — catalog_items is ONE table. The COMPOSITION varies, through these and nothing else:

#MechanismExample
1Feature applicabilitystore.stock absent for Time and Expertise — the section does not exist
2Enum subsets — same columns, different valuessalon kind:'service' + unit:'hour'; dairy kind:'product' + unit:'litre'
3attributes jsonb{carpet_area} for a listing, {fat_percent} for dairy — ⚠ see QRS-452, the mechanism is EMPTY and archetype-grained where it needs to be industry-grained
4ConfigurationindustryNudge, category suggestions — attached to the industry, resolved at runtime

Filters vary for free because they are catalog_categories rows (data). A per-industry authored filter set would be 14 configs to maintain and is the version to refuse.

⚠ None of the four is a branch in app code, and "handled during development" is the failure mode, not the plan. Variation is resolved once, by the resolver; ADR-0021 D4 lint-gates the alternative.

⚠ Fix the design before implementing against it, or cafe sample data becomes the app's test fixtures. The prompt is §10.1.

10.1 · The correction prompt (send this one) ​

Target: project 633dc069… "QR setu prototype", file prototype/mobile-console/Catalogue.dc.html. Deliberately minimal, because §9.2 found the design sound: it changes demo data only and explicitly forbids touching the UI.

In prototype/mobile-console/Catalogue.dc.html, change the demo data only. Do not change the UI, layout, component structure, styling or behaviour of any screen or sheet, and do not remove any screen or sheet. The design is right; it needs a different default and three more sample businesses.

1. Make Festival stall · Ganpati Bappa Arts the default profile. It is our launch business, so it should be what opens. Keep the Cafe · Chai & Charcha profile exactly as it is: our Digital Menu feature is being rebuilt on this same Store, so menu_item stays a supported item type and that profile is the one that exercises it.

2. Keep all five existing profiles unchanged. Cafe, Salon, Yoga studio, Festival stall and Distributor. Their hasStock, published and industryNudge values are the whole point of the screen: hasStock: false on Salon and Yoga is what proves the stock section disappears for businesses with no inventory, published: false on Salon is what shows the draft-card prompt, and the two contrasting industryNudge examples are what prove the action item is a configured slot rather than a festival feature. Do not touch any of them.

3. Add three new profiles, in the same shape as the existing ones. Each exists to exercise an item shape the current five do not:

  • Dairy · Gokul Dairy — hasStock: true, published: true, industryNudge: null. Our richest business type. 2 categories (for example Milk and Paneer & Curd), 5 to 6 items with kind: 'product' and units of litre, ml and g so the non-piece units are visible, one item priced per litre with a compare_at_price_minor, one out_of_stock, one coming_soon.
  • Boutique · Aarna Handlooms — hasStock: true, published: true, industryNudge: null. Stocked goods that are not seasonal, which is the deliberate contrast against the festival stall. 2 categories (for example Sarees and Kurtas), 5 to 6 items, kind: 'product', unit: 'piece', at least one with size variants, one with a compare_at_price_minor so the discount badge shows, one draft, and one with no image.
  • Real estate · Sahyadri Properties — hasStock: false, published: true, industryNudge: null. The important one, because it is the only business here whose items have no fixed price and no stock at all. 2 categories (for example Apartments and Plots), 4 to 5 items with kind: 'listing', and prices shown as indicative or on enquiry rather than exact. Show how a listing with no firm price reads on the overview card and in the edit sheet using only the existing fields — do not add a new price-type field. No stock control anywhere in this profile. ⚠ Do not add per-item custom fields such as bedrooms, carpet area, floor or facing. Those belong to a separate contract we have not settled yet, so anything designed for them now would have to be thrown away. Put that kind of detail in the item's existing name and description instead.

4. Add the one remaining unused item type: a kind: 'course' item in the Yoga studio profile, for example a 6-week beginners course at unit: 'month'. Our six item types are product, service, package, menu_item, course and listing, and after this change every one of them appears in at least one profile.

That is the whole change. No visual or structural edits.

⚠ Deliberately NOT in this prompt: any UI for attributes (per-industry fields such as carpet area or fat percent). The mechanism is unresolved on our side — QRS-452 — and asking for a design over an undecided contract is the architecture-gated mistake design-system/screen-reviews/ exists to prevent. And Distributor's hasStock is left alone here because QRS-453 is likely a taxonomy fix, not a design fix.

10.2 · The original prompt (already sent, kept for the record) ​

Create a NEW template in this project at templates/store-catalogue/StoreCatalogue.dc.html, with its own ds-base.js and support.js alongside it, matching the folder structure the other templates use.

DO NOT modify, fork, copy or restructure any existing file. Leave ui_kits/merchant-console-v2/**, ui_kits/qrsetu/MenuBuilder.jsx and every existing template exactly as they are. Those are a desktop console and a legacy Digital Menu prototype; this is a new mobile surface that has no design yet.

Three things in the existing console catalogue module must NOT be carried into this design: (1) branching sample data on ws.domain === 'cafe' — one screen serves every business, and industry-conditional design cannot be implemented in our codebase; (2) a Schema: menu item chip exposing internal vocabulary to the merchant; (3) a sponsored or partner tile inside the catalogue grid — advertising is out of scope and must not appear.

Design the Store (Catalogue) experience for QRSETU's merchant mobile app — the screens where a small business owner manages the products or services shown on their public Setu Card. Native mobile app screens.

The user, and this is a CONTEXT persona rather than an industry brief: a Ganapati idol stall vendor in Pune, on a ₹8,000 Android, standing in their stall, adding an idol they finished this morning — one-handed, while a customer waits. Not a Shopify merchant at a desk. Primary actions belong in the bottom third; adding an item must survive being interrupted; photos are taken with the camera, not uploaded; names mix Devanagari and English in one field; money is ₹ with Indian digit grouping (₹1,50,000). Every one of those constraints is equally true for a boutique, a salon or a tutor on the same phone — none of them is about festival goods, and this must not become a festival-stall app.

⚠ ONE SCREEN SERVES 14 INDUSTRIES ACROSS 3 BUSINESS TYPES, AND THE VARIANCE IS THE HARD PART. An "item" is a stocked product (idol, kurta, 500 ml milk), or a bookable slot (haircut, yoga batch, tuition term, priced per hour/session/month), or an enquiry-led service or listing (wiring job, 3BHK listing, wedding package). The Store is composed of three independently-available features, not one: store (items, categories, price, unit, tax, variants, availability, ordering) and store.media (photographs) are available to all 14 industries, but store.stock (inventory counts and out-of-stock state) is available to only 6 of 14 — every one of them a goods business. For a salon, a yoga trainer, a tutor, an electrician, a real-estate agent, a car-sales agent, a photographer or a direct seller, stock is not a concept and its controls must be ABSENT, not disabled and not empty. So design the item form to compose — a universal core plus additive sections — and show it both with and without the stock section, with the form still looking complete and balanced in the absence case. Note carefully: whether stock exists at all is a per-business capability, while track_inventory is a separate per-item opt-in within a business that has stock. Both layers must be visible. Also, for slot- and enquiry-based businesses a price is often indicative, so "from ₹X" and "price on enquiry" must be expressible using only the fields listed below — there is no price_type field to invent.

What exists today is too generic — a flat list of name + price with a four-field sheet. It is correct CRUD and a poor Store. Use it as a reference for the component vocabulary only.

Design against exactly these fields, and invent none: items have name, description, kind (product/service/package/menu_item/course/listing), price_minor (integer paise — 45000 is ₹450), compare_at_price_minor (the "was" price; discount % is derived, never stored), currency, unit (piece/kg/g/litre/ml/metre/hour/day/month/session), tax_rate_bp (basis points; 1800 = 18% GST) with price_includes_tax, availability (available/out_of_stock/discontinued/coming_soon/draft), opt-in track_inventory + stock_quantity, and position for merchant ordering. Items belong to merchant-defined categories (ordered), may have ordered images with alt text, and may have variants (name + price + stock, e.g. "11 inch" / "18 inch"). There are no orders, no reviews, no per-item analytics, no cost price and no per-industry custom-field editor — do not design them.

Deliver: (1) a Store overview that is image-led and category-grouped, with search and availability/category filtering, drag reordering, and per-item state visible at a glance (draft, out of stock, no photo, discounted); (2) an add/edit flow that is progressive — name, price and photo reachable in one screen, with unit, tax, category, variants and stock revealed on demand; (3) a real 5-state availability control, not an on/off switch; (4) category management; (5) an explicit "preview as customer" affordance that opens the live public card.

It must prompt action, not just display state — but design a SLOT, not a fixed list of nudges. The action item is one reusable component whose content is configuration attached to the merchant's industry, resolved at runtime. Give it a clear anatomy (a count or icon, one line of plain-language claim, one primary action, a dismiss) and then show enough different examples to prove the anatomy is not built around one vertical: "3 items have no photo" and "your card is still a draft — publish it" (both universal), "2 items are out of stock" (only where store.stock is available, so it must degrade to absent), and two contrasting configured examples — "Ganesh Chaturthi is in 3 weeks, add your seasonal items" for a festival stall and "12 customers are due to reorder this week" for a distributor. If only the festival one is drawn, it will be built as a festival feature, which is exactly wrong. Every item derives from stored data. Never more than two visible at once. No push notifications. No fabricated numbers. No upgrade or payment CTA anywhere (the native app is a free companion — Apple 3.1.3(d)).

Visual direction: follow the existing QR setu design system — Apple-style soft corners (rounded-3xl shells, rounded-2xl inner panels), Plus Jakarta Sans for UI, Baloo 2 for display, the QR monogram gradient reserved for brand emphasis only. Semantic colour tokens only, zero hard-coded colours. Complete light and dark. Restrained, compositor-friendly motion. Modern but not trendy: it must still look considered in three years to a merchant who is not design-literate.

Constraints: touch targets ≥ 44px; WCAG AA contrast on every text pair (accent is a fill token and fails AA as small text); no em dashes or en dashes in any copy; all copy must work in English, Hindi and Marathi without clipping; one design must work on Android, iOS and mobile web.

Return these screens, each in light and dark, primary artboard 360×740: Store overview (populated, ~12 items across 3 categories, with an action item visible) · Store overview empty state · Store overview with search/filter active · Add item (the 80% path) · Add item expanded WITH the stock section · Add item expanded WITHOUT it, for a salon or consultant — the section absent, not disabled · Item detail/edit with delete confirmation · Category management · the action-item surface with two contrasting configured examples · Store overview for a slot- or enquiry-based business (services or packages priced per hour, session or month, no stock state anywhere; a content variant of the first screen is fine, the point is proving the layout survives it).

Judge your own output against: could this vendor add a photographed, priced item one-handed in under 60 seconds on a cheap phone; does the screen prompt a next action rather than only showing state; is every value on screen backed by a field listed above; does it hold at 360×740 in Devanagari in dark mode; would the same design serve a salon and a consultant with the stock surface absent and the item form still looking complete; is the action item a slot with configured content rather than a fixed list written for one vertical.


Parity status ​

Design artefact, not code — no surface to verify yet. The implementation that follows it ships to Android native · iOS native · Web PWA together, and §7's constraints are the ones the automated gates (layout-invariants touch-target measurement, axe-core contrast, the i18n em-dash gate) already enforce.

Proactive-value answer ​

§4.3 is this document's reason for existing. The shipped Catalogue screen passes every technical gate and fails CLAUDE.md's proactive-value gate — it lets a merchant see and store items and prompts nothing. Every action item specified there is derived from stored state (a missing catalog_item_media row, setu_cards.status = 'draft', availability = 'out_of_stock', a date), so none can fabricate an insight, and all are in-app and dismissible so none spends the merchant's attention twice.

The nudges are a SLOT with configured content, not a list written into the screen — which is also what makes §2.1's variance affordable. A prompt whose copy comes from industry configuration (ADR-0009) means a new vertical inherits its own nudges without a code change, while a nudge drawn for one vertical would be the archetype branching ADR-0021 D4 lint-gates. And §2.1's second-order proactive payoff: because store.stock applicability is data, a business without inventory is never shown a restock prompt it cannot act on — R-07's rule "never surface an action item the user cannot act on" (operating-rules.md) holding by construction rather than by per-screen care.