Skip to content

Desktop journey readiness — merchant onboarding to consumer discovery ​

Status

🟠 Assessment, 2026-08-20. Measured against the live Claude Design prototype project (633dc069-6df8-4408-b625-068907c60c33, list_files + SCREENS.md pulled 2026-08-20, round 30) and against the repo at a45b21f. No local design cache was read.

Target journey: merchant desktop onboarding → create Ganapati stall → configure Setu Card → publish → marketplace → consumer discovers the stall → consumer views and interacts. Driver: native distribution is blocked on DUNS, so the desktop path must carry the first merchant.

0 · The one-paragraph answer ​

The merchant half of this journey is fully designed and already built — but as the Expo/RNW product, not as DOM. The consumer half is designed only as far as discovery and ordering, and the marketplace that connects the two halves has three approved designs and zero implementation. The fastest unblock is not a new screen: it is mounting the existing RNW export at /app, which ADR-0028 already decided and specified. The genuine design gap is a consumer desktop tier, which does not exist in the design at all.

1 · Already designed and ready for implementation ​

Merchant desktop console — prototype/desktop-console/, 16 screens ​

Round 20 for the console; round 22 added the two the journey starts with. Every screen carries light + dark plus loading, error and empty states.

Journey stepDesign fileNotes
Welcome, sign up, sign inAuth.dc.htmlThe front door desktop never had. The phone's mechanics unchanged (Google, email + password, email + 6-digit code, 24s resend); desktop adds both panes at once, Enter submits, one-paste code.
OnboardingOnboarding.dc.htmlThe phone's flow one for one (type → name → brand → industry → location → slug → alerts → highlights → celebrate), plus a step rail and a live Setu Card preview. Individual path visibly shorter. No plan step by design.
Create the stall (catalogue)Catalogue.dc.htmlBuilt for a stall entering 1,400–1,500 idols in four weeks: keyboard-first entry row, sticky attribute picks, inline-editable dense table, multi-select bulk edit.
Configure the Setu CardCardEditor.dc.htmlSection registry beside a live preview; writes the same override row the phone editor writes.
Publish / shareQRTools.dc.htmlThe one code, at print size, from the workspace slug.
Run the ordersCollections.dc.html, Payments.dc.html, ScanCollect.dc.htmlDay-axis order book with multi-select and keyboard traversal; money passbook; counter station.
Rest of consoleHome.dc.html, Messages.dc.html, Analytics.dc.html, Banking.dc.html, PlanBilling.dc.html, Profile.dc.html, Settings.dc.html, Notifications.dc.html

Consumer marketplace desktop — prototype/marketplace/, 3 screens ​

Public, indexed, and open browsing is the hard rule: browse, search, filter, open a stall and open a listing all work with no account. Registration is action-triggered and inline.

Journey stepDesign fileNotes
DiscoveryDiscover.dc.htmlRound 29 added it in front of Browse: resolves typed words into one of five outcomes (category, business, listing, place, demand nobody serves), then hands off to the indexed pages. Widening named rings, so an endless scroll never quietly changes subject.
Browse and searchBrowse.dc.htmlCategory-in-a-city listing page: persistent left facet rail with live counts, crawlable /page/n links, four-column photo-dominant grid. States: default, no shops in area, no results for filters, no search match, loading, error.
Listing detailItem.dc.htmlThe transaction gateway. primaryCta(vendor) decides the CTA, so a stall without payments shows Call and Message and no order control. Carries the inline consumer registration with a "Held for you" block so intent survives the interruption.

Public Setu Card — designed and already built ​

prototype/setu-card/{SetuCard,CatalogueSection,ItemDetail,PublicCatalogue,Featured}.dc.html. Live in apps/web at /:slug/setu-card, with /:slug/order and /:slug/order/:orderId/:reference already implemented.

2 · Missing or incomplete ​

⚠⚠ CORRECTED 2026-08-20, SAME DAY: THIS SECTION WAS WRONG, AND WRONG IN THE EXPENSIVE DIRECTION ​

It originally read "there is no consumer desktop tier" and listed six missing surfaces, the order code among them, calling it "the one that breaks a finished transaction". Measured after the owner challenged it: the consumer product already ships to desktop and the order code is built.

screen-conformance.json records the consumer tier at 10 of 11 built — consumer-home, item-feed, vendor-feed, item-view, vendor-view, consumer-chats, consumer-notifications, order-code (OrderCodeScreen), account and featured, every one reachable: true. Only scan-verify is unbuilt. resolveEntryRoute routes consumers. And because the consumer tier lives in the universal Expo app, expo export -p web emits all of it: consumer/order-code.html is 29,456 bytes, mounted at /app/consumer/order-code by this same change.

So the error was reading a DESIGN-PROJECT scoping note as a statement about the PRODUCT.VENDOR-PARITY.md §4 says "Saved, orders, account — out of scope for desktop", and I repeated it as settled. It is a note about which surfaces the marketplace DOM pages carry, authored design-side and never put to the owner — and read as product scope it contradicts CLAUDE.md's ENFORCED cross-platform-parity standard, whose exception path the owner retired on 2026-08-02. A desktop user must have no feature limitation, and structurally they do not: one Expo codebase reaches Android, iOS and web together, so parity here holds by construction rather than by effort.

⚠ The generalisable lesson, which is this repo's own most-repeated defect: a written scoping line in a document that is otherwise authoritative is still only a hypothesis about the product. I verified the design registry meticulously and then took a product claim from it on trust. Establish which artifact is authoritative for the question you are actually asking — the design project is authoritative for what a screen looks like, never for what the repo has built.

What is genuinely open (the corrected list) ​

ItemStatus
scan-verifyThe one unbuilt consumer screen (1 of 11).
Anonymous DOM buyer → live order codeA registered consumer has order-code on every surface. An anonymous marketplace buyer has only the confirmation URL (/:slug/order/:orderId/:reference), which is a bearer token and does carry the reference. Whether that page should also present a live re-minted code is a real design question, and the only consumer-desktop item still worth a prompt.
DOM marketplace vs /app division of labourDecision, below.

The division of labour that satisfies "no platform limitations" without a second implementation:/app carries the full consumer feature set on every surface including desktop; the DOM marketplace stays the public, crawlable discovery front door and hands off to /app for anything account-bound. Duplicating account surfaces into the DOM marketplace would be a second consumer implementation — the same mistake ADR-0019 refuses for the card ("one renderer, always DOM") and the same conflict as the DOM merchant console.

The original (incorrect) list, kept because deleting a wrong claim hides that it was made

It named these as missing desktop surfaces: order code, account and profile, order list and detail, chats, notifications, saved/favourites, and a standalone consumer sign-in. All but the last two are built and shipping to desktop via /app. Retained per this repo's rule that a superseded record is banner-stamped, never edited away.

Superseded original text ​

All 13 prototype/consumer/ screens are marked mobile only in the design registry. That is true of the DESIGN and false of the PRODUCT. The list that followed was:

Missing consumer desktop surfaceConsequence for the Ganapati journey
Order code / collect leg (OrderCode.dc.html is mobile only)The one that breaks a finished transaction. The buyer has no way to present a collectable code from a desktop.
Consumer account and profileA registered consumer cannot manage anything they created.
Consumer order list and detailNo "my orders" on desktop, only the single bearer-token confirmation URL.
Consumer chatsThe merchant console has a two-pane inbox; the consumer has no desktop reply surface.
Consumer notificationsNo desktop delivery for "your idol is ready".
Saved / favourites surfaceAnonymous device-save is designed inside the marketplace, but nothing lists what was saved.
A standalone consumer sign-in entrySign-in exists only inline inside a listing page. A returning consumer landing on qrsetu.com has no door.

Round-30 design content the schema cannot support ​

  • Ratings. Round 30 gave every marketplace card a rating chip and a quoted latest review from a RATINGS record in consumer-data.js. There is no ratings table in this repo. The design notes this reverses the earlier refusal (QRS-576) on the grounds that the opinions always existed and only the table was missing, which is true, and the table is still missing. Rating chips must be absent, never faked.
  • Photographs. Both marketplace grids are explicitly photograph-dominant. See §3(d).

3 · Architecture and backend dependencies, and the real conflicts ​

(a) ⚠ CONFLICT — the desktop console asks for a second merchant implementation ​

SCREENS.md states the desktop console is "a SEPARATE route group in apps/web, DOM/React over shadcn/Radix primitives … It is not React Native Web and not a scaled phone screen."ADR-0011 says the merchant product is one universal Expo codebase shipping to Android native, iOS native and responsive web via RNW.

So the design asks for a 16-screen DOM rebuild of a merchant product that already exists and already runs in a browser. Measured cost floor, today:

  • apps/web/src/ui/ contains 2 components (Button, TextField) plus cn.
  • apps/web/package.json has zero radix or shadcn dependencies.
  • apps/web has no authentication of any kind — no Supabase auth client, no session, no protected route. The desktop console needs all of it; the RNW app already has Google sign-in live.

This is not a one-day item and should not be attempted as one. The conflict deserves a deliberate resolution later (density, keyboard flow and multi-select are genuine desktop advantages RNW will not match), but it is a wave of work.

Resolution for the deadline, and it is already the decided architecture: mount the existing RNW export at /app. ADR-0028 specifies exactly this — "the assets directory is apps/web/build/client with apps/mobile/dist placed at /app. Two artifacts, one origin." That yields merchant desktop onboarding, stall creation, card editing, orders and payments with no new screens, because responsive web is one of the three R1 surfaces and is already built.

⚠ (b) Measured while implementing (a): EXPO_BASE_URL alone does not mount the app ​

Setting EXPO_BASE_URL=/app on expo export -p web exits 0 and produces a root-relative bundle: 0 app-prefixed references and 3 root /_expo/ references in dist/index.html. The CLI derives that variable from experiments.baseUrl in the app config during bundling; supplying it from outside does not drive the HTML rewriting. So a config change is genuinely required, and it carries a real blast radius, because e2e/ and the run-mobile driver both serve dist/ at root and would 404 on every asset.

The chosen shape: an app.config.js that spreads app.json and adds experiments.baseUrl only when an env var is set. Local, e2e and the driver stay root-relative and unchanged; the deploy sets the var. app.json remains the version SSOT, so version:set and check:version are unaffected. Recorded as QRS-779.

(c) ✅ The marketplace backend is ready — the part that can ship properly ​

Every read the three marketplace screens need is live and anon-granted, in the committed migration 20260818120000_v2_consumer_discovery_read_path.sql:

RPCSignature
get_consumer_item_feed(p_area text, p_sort text, p_filters jsonb, p_page integer)
get_consumer_vendor_feed(p_area text, p_sort text)
get_consumer_item(p_item_id uuid)
get_consumer_vendor(p_slug text)
get_states / get_cities() / (p_state_key text)

All are grant execute … to anon, authenticated, which is what makes open browsing possible with no session. packages/data/src/consumer/ is Supabase-backed and exports CONSUMER_RPC, CONSUMER_SORTS and CONSUMER_FILTER_THRESHOLD — the threshold is re-exported from the seam precisely so the client cannot invent a second one.

(d) ⚠ No public media URL exists, so a photograph-led marketplace has no photographs ​

packages/data/src/mediaUrl.ts fails closed and returns null until setPublicMediaBaseUrl() is called, which nothing does, because no bucket is provisioned. get_public_catalogue projects storage_key, never a URL. For a marketplace selling ₹45,000 idols this is commercially the largest single gap in the journey — nobody buys an idol from a line of text. It is a wave of work that has not shipped, not a bug in a caller, and it should be sequenced ahead of marketplace polish.

(e) The promotion layer must render nothing ​

The marketplace design carries ten promo slots and registers them in the Ad Manager's PLACEMENTS. ADR-0004's promo_slot fails closed forever pending a compliance_profile column that does not exist. Shipping a live resolver risks a compliance-restricted vertical carrying an ad it legally cannot. Do not implement the promotion layer; the slot renders nothing, the same posture the card manifest already takes.

(f) URL taxonomy needs sign-off before the first crawl ​

marketplace is already a reserved slug (20260808110000_v2_reserved_slugs.sql), so there is no namespace collision. But the taxonomy is marked proposed, permanent once indexed: /marketplace/<category>/<city>, /marketplace/<category>/<city>/<area> and /page/<n> as crawlable paths; facets as noindex parameters with a canonical back to the path; a listing at /<slug>/item/<item-slug> as the card's sibling. ADR-0028 governs first segments, and the vendor slug namespace is flat and at the root, so a first segment spent is spent permanently. Confirm before the first crawl, not after.

4 · The exact design delta ​

Everything the target journey needs on the merchant side is designed. The delta is entirely consumer-desktop, plus two data-truth corrections:

#DeltaWhy this journey needs it
D1Consumer desktop order code❌ WITHDRAWN — order-code is built and mounted at /app/consumer/order-code.
D2–D6account · orders · saved · chats · notifications❌ WITHDRAWN — all built in the consumer tier and shipping to desktop web via RNW. See the correction in §2.
D1aLive order code for an ANONYMOUS marketplace buyerThe one survivor: an anonymous buyer holds a confirmation URL, not an /app session.
D9scan-verifyThe single unbuilt consumer screen (1 of 11).
D7Rating-less marketplace card stateRound 30 assumed a ratings table that does not exist.
D8Image-less marketplace card stateNo media pipeline, and the grids are photograph-dominant.

D1, D7 and D8 are the ones that block implementation. D2–D6 can follow, because open browsing means the discovery and purchase path does not depend on them.

5 · Prompt for Claude Design — missing consumer desktop screens only ​

Send to the prototype project (633dc069-6df8-4408-b625-068907c60c33), not the design-system project. It deliberately asks for nothing that already exists: no marketplace redesign, no merchant console change, no mobile consumer change.

Copy-paste prompt
text
Add a CONSUMER DESKTOP surface to prototype/consumer-desktop/. This is new: all 13 screens in
prototype/consumer/ are mobile only, and the desktop marketplace (prototype/marketplace/) currently
ends at ordering, so a consumer who buys on a desktop has nowhere to go afterwards.

Do NOT redesign anything that exists. Do not touch prototype/marketplace/, prototype/consumer/,
prototype/desktop-console/ or prototype/setu-card/. Reuse their kits and data: read
../consumer/consumer-data.js and ../marketplace/market-kit.js, and match the shell language of
prototype/desktop-console/ (same chrome, same focus ring, same light plus dark) while remembering that
a consumer is not a merchant and has no workspace, no sidebar of business modules and no capabilities.

Screens, in priority order.

1. OrderCode.dc.html  (HIGHEST PRIORITY, the only gap that breaks a finished transaction)
   The desktop twin of prototype/consumer/OrderCode.dc.html. The buyer's half of the merchant's
   Scan to collect. The code is re-minted on open and refreshed every few minutes, so a screenshot
   taken earlier is refused later, and the screen must say so in plain words. Because a desktop is not
   carried to a stall, the desktop version's primary job is TRANSFER: show the code large enough to be
   read aloud or photographed, plus a print view and a "send to my phone" affordance. States: live code,
   refreshing, expired and re-minted, order not yet payable, order already collected, error.

2. Auth.dc.html
   A standalone consumer sign in and sign up door. Mechanics identical to
   prototype/desktop-console/Auth.dc.html (Continue with Google, email plus password, email plus a six
   digit code, 24 second resend, Enter submits, one paste fills the code). What differs is the framing:
   this person owns no business, so the left pane must not promise merchant features. It must also carry
   the "Held for you" continuity the marketplace listing page already uses, because a consumer arrives
   here mid intent. States: sign up, sign in, code sent, verifying, error.

3. Orders.dc.html
   My orders: a list plus a detail pane beside it, not over it, following the Collections two pane
   pattern. Each row carries the reference in the platform's Crockford format, the stall, the item, both
   status axes, what was paid and what is due at the stall. Detail opens the order code (screen 1).
   States: has orders, one order, no orders yet, loading, error.

4. Saved.dc.html
   What the marketplace saved. It must work for an ANONYMOUS visitor whose saves live on the device, and
   state honestly that registering is what makes a save follow them to another device. Never a signup
   wall. States: has saves, anonymous with saves, no saves, a saved piece since sold.

5. Chats.dc.html
   Two pane, same shape as prototype/desktop-console/Messages.dc.html, from the consumer's side. It must
   read the same chat-core.js the merchant thread reads. States: has conversations, no conversations,
   blocked by the business.

6. Notifications.dc.html
   The consumer's list. Order progress, a message, a stall update. Each individually mutable. States:
   has notifications, all read, empty, error.

TWO DATA TRUTH CORRECTIONS to the existing marketplace, the only changes I am asking for outside the
new folder. Both are cases where round 30 drew something the platform cannot supply, and drawing it
anyway forces the build to either fake it or diverge.

  A. RATINGS DO NOT EXIST. There is no ratings table in the platform and none is planned for this
     release. Every rating chip, review count, quoted review, category average and aggregateRating in
     Browse.dc.html, Discover.dc.html and Item.dc.html needs a designed ABSENT state: what the identity
     row, the stall line, the answer panel and the listing trust block look like with no rating at all.
     Not "New on QR setu", which still implies a scale. Nothing.

  B. THERE ARE NO PHOTOGRAPHS YET. No media bucket is provisioned, so every image slot resolves to
     nothing on day one, and both marketplace grids are photograph dominant. Design the no-image state
     for the Browse grid cell, the Discover stream card and the Item listing gallery. It must not look
     broken or like the stall's own photo failed, because a buyer reads a torn page icon as the vendor's
     fault. Reserve the same box from the stored ratio so nothing reflows when photographs arrive.

Constraints that apply throughout.
  - Open browsing is the hard rule and these screens do not weaken it. Discovery, browsing, viewing a
    stall and viewing a listing stay fully usable with no account. Registration stays action triggered.
  - There is no in app purchase or upgrade CTA anywhere in these screens.
  - A capability the platform does not have must be absent, never shown disabled and never shown locked.
    Locked is only for something a paid plan would unlock, and none of these are.
  - DO NOT use em dashes or en dashes anywhere in generated copy, labels or examples. Use a comma, a
    colon, parentheses, or two short sentences.
  - Light and dark, plus loading, error and empty states on every screen.
  - Responsive down to 390px verified by measurement, no horizontal overflow, touch targets reaching
    44px through a hover:none breakpoint rather than by inflating desktop controls.
  - Register every new screen in SCREENS.md in its own section, so the registry stays the only place a
    screen list is maintained.

6 · What is being implemented in parallel, and what is deliberately not ​

Doing nowWhy
Mount the RNW export at /appADR-0028's decided shape; unblocks the whole merchant half with zero new screens. Blocked on §3(b), tracked as QRS-779.
Marketplace routes on the live consumer RPCsThe only journey step with a complete backend and no implementation.
Record the taxonomy decision before the first crawlA spent first segment is permanent.
Deliberately not doingWhy
The 16-screen DOM desktop console§3(a). A wave, not a sprint, and RNW already covers the journey.
The promotion layer§3(e). Fails closed forever pending compliance_profile.
Rating chips§2. No table. Absent, not faked.
Consumer desktop D2–D6Awaiting the §5 designs; open browsing means the purchase path does not need them.
  • Consumer Marketplace Spec — the 2026-08-10 specification these screens were designed from. ⚠ Its status banner still reads "screens do not exist yet"; three now do.
  • Screen conformance — the presence ledger. ⚠ It tracks 36 screens across mobile-console, consumer and onboarding only; the 16 desktop-console and 3 marketplace screens are absent, so check:screens is blind to this entire assessment.
  • ADR-0028 — one origin, /app, reserved first segments.