You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(souschef): actually remove ⌘V hint from input toolbar
PR #399 was supposed to remove the "⌘V works for URLs, text, and
images." hint from the Sous Chef input toolbar. The squash-merge
applied half the diff — the `handlePaste` comment update landed on
main, but the toolbar hunk (the `<span>` removal + `justify-between`
→ `justify-end` swap) was silently dropped, almost certainly because
of merge-base confusion after #397's earlier squash made the file
history ambiguous to GitHub's merge algorithm.
This branches fresh from current main and applies just the toolbar
change to avoid any repeat. After this, the toolbar contains only the
"Upload image" button, right-aligned.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(promo): scope-aware promo engine + membership/genesis Lightning discounts
Generalize the cookbook promo engine into a scope-aware engine and wire promo
codes into the membership (Cook+/Pro Kitchen) and Founders Club (Genesis)
Lightning checkouts. Cookbook export behavior is byte-for-byte unchanged.
Engine (Phase 1)
- Add PromoScope ('cookbook'|'membership'|'sponsor'|'genesis'|'all') + pure
scopeAllows() in cookbookPricing.ts. 'all' covers cookbook + membership
only, NOT genesis (a founder discount needs an explicit 'genesis' code).
- PromoEntry gains optional scope (absent => 'all', backward-compatible).
- applyPromo(kv, code, baseAmount, scope) now requires a scope and rejects
mismatches ('wrong_scope'). Membership/genesis are percent-only and capped
below 100% ('invalid_for_scope') so every activation stays behind a verified
Strike payment.
- Generic PROMOS_DISABLED kill-switch (all scopes); cookbook still honors
COOKBOOK_PROMOS_DISABLED.
- Seeded LAUNCH/FREEPACK defaults are now scope:'cookbook'.
- New $lib/promoEngine.server.ts barrel re-exports the engine under a
scope-neutral name for non-cookbook callers.
Money path (Phase 2)
- membership + genesis create-lightning-invoice accept promoCode, validate it
server-side, apply the promo to base USD (integer cents), then the existing
5% BTC discount stacks on the result before sat conversion (D2). Response
echoes { promo: { code, label, originalUsd, finalUsd } }. Server is the sole
source of truth for the charged amount.
- Genesis activation left untouched (still inline, paid-only).
Admin (Phase 3)
- /api/admin/promos upsert accepts + validates scope (NIP-98 auth, body-hash
binding, CODE_RE unchanged); enforces the percent-only/<100 caps for
membership + genesis at write time too.
- Admin UI: scope selector on add/edit rows, scope badge in the code list.
Checkout UIs (Phase 4)
- Cook+, Pro Kitchen, Genesis: "Have a promo code?" input + Apply calling the
new /api/membership/apply-promo preview endpoint; validated code is forwarded
to invoice creation; displayed price comes from the server response. Stripe
path is untouched.
Decisions as implemented: D1 promo on base USD in integer cents; D2 stack
(promo, then 5% BTC); D3 reject >=100% / flatOff on membership+genesis (no
free path); D4 genesis is its own scope and 'all' excludes it.
Migration note: legacy KV codes with no scope default to 'all', so they now
also apply to membership checkouts. The admin should re-scope to 'cookbook'
any existing code that must stay cookbook-only.
Tests: scope matching (incl. 'all' + genesis carve-out), USD-cents math, D2
stacking order, D3 rejection, plus cookbook backward-compat + kill-switches.
Full vitest suite + svelte-check pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: spe1020 <sethsager@Seths-MacBook-Air.local>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments