New /app-shop page for SkateSpots merch, to be paid in sats only (Lightning or
Cashu) — no cards, no accounts, no middleman.
Design: gradient/glow hero ('Wear the scene' + Coming soon badge), an honest
stock strip (0 items / None pre-orders / Nothing for sale today), an 'In the
works' teaser grid (tees, decks, stickers, tools — dashed + 'soon', no prices),
a three-step 'How it'll work' (pick -> pay in sats -> ships), a newsletter
notify band (the drop lands there first) and a plain-English honesty footer.
Deliberately contains no items: no stock, no prices, no pre-orders, no buy
buttons. AGENTS.md documents that rule so nobody invents a catalogue later.
Wiring: registered in NAV_CATALOG as id 'app-shop' (appears in the desktop
'More' menu AND the mobile burger menu automatically), lazy route in AppRouter,
and added to the smoke-test route list so a broken page aborts deploys.
Verified: page renders desktop + mobile (all sections), listed in both navs,
smoke PASS with /app-shop.
- New '/trades' page: action-needed (incoming 'confirm this sale' requests as
seller, pending confirmations as buyer) with inline actions, a reputation
card, and the user's own trade records (role/counterparty/state) linking to
each listing. Nav entry (auth-only) + smoke route.
- DM inbox relays (kind 10050) are now block-filtered on both read and delivery
(closes the last relay caveat).
- AGENTS.md updated.
Gate: 101 tests, 0 errors/warnings, boot smoke green.
- New '/listing/:pubkey/:identifier' page: large gallery + lightbox, full
description, details, seller trust + trade reputation card, and full actions
(shared) for buyers and owners (mark sold/relist/delete)
- Extract ListingTradeActions (confirm/escrow request/ask-to-confirm/refund/
contact + escrow dialog) and use it in BOTH the grid card and the detail page
so there is one implementation
- useMarketplaceItem(pubkey, identifier) fetch hook
- Cards link their image + title to the detail page
- Smoke test covers /listing/:pubkey/:identifier
Gate: 101 tests, 0 errors/warnings, boot smoke green.
New '/mints' page: browse Community MintRadar mints with health (online/latency/
degraded/archived), NUT count, terms, and add-to-wallet on native.
MintRadar has no CORS, so it's fetched same-origin at /api/mints/*:
- prod: Netlify proxy redirect in public/_redirects (+ 10m cache in _headers)
- dev: Vite server.proxy in vite.config.ts
This also hides users' IPs from MintRadar. Data is unofficial/rate-limited;
the page degrades to a friendly error state. Nav entry + smoke route added.
Marketplace:
- Buyer can 'Ask seller to confirm' a sold listing -> publishes a 31872
Attestation Request (d/a/p), which the seller fulfils in one tap
- Seller sees incoming requests in the DM thread ('Confirm this sale?') and the
fulfilling 31871 carries the spec's 'request' tag
- useTradeAttestationRequest / useIncomingTradeRequests / useListingTradeRequest
- NIP.md documents 31872 and states escrow is intentionally NOT implemented
(coco-cashu has no P2PK/HTLC locking, wallet is native-only, and release-on-
attestation needs a witness) so nothing looks trustless that isn't
Hardening:
- scripts/smoke-test.mjs navigated to /settings etc. WITHOUT a hash, so with
HashRouter it only ever loaded the homepage and reported PASS. It now puts the
route in the hash, covers settings/stash/collections/stats/marketplace, and
fails on the 'This page slammed' error boundary (not just boot failure)
Uses the existing gift-wrap primitive (kind 14 rumor, one p-tag per recipient):
- useGroupConversations: lists multi-recipient threads, bucketed by the sorted
participant key; the inbox shows a Groups section
- GroupConversationPage (/messages/group/:participants): encrypted group thread
with sender names, send + error feedback
- smoke test now boots the new route
Group creation UI (multi-select in NewMessageDialog) is the next step. For
stronger guarantees (forward secrecy, rosters) Marmot/MLS or Cordn would be the
protocol to adopt later; noted in the hook.
New /leaderboards route (linked from the More menu): aggregates kind-9735
receipts into top-zapped spots and top supporters, with week/month/all-time
tabs. Reuses the batched zap helpers. Also hardens the deploy smoke test to
boot lazy routes (/, /leaderboards, /bounties), since route chunks can fail
independently.