Changelog

Product updates, improvements, and fixes.

v0.18.0

Referral program — buyers bring buyers

  • New /dashboard/marketing/referrals — per-merchant referral program. Configure reward type (percent, fixed, shipping-percent, shipping-fixed), separate values for the referrer and the new buyer, min-purchase floor, reward code TTL (30-365 days), attribution window (7-180 days), optional per-referrer lifetime cap, and program terms fine print.
  • Auto-issued reward codes reuse the existing DiscountCode machinery — so ledger, P&L, discount-usage reports pick them up with no extra plumbing. Codes are tagged source="referral_referrer" / "referral_referee" and are excluded from the storefront's public applicable-codes list so personal rewards don't leak to other buyers.
  • Every signed-in buyer gets a unique 8-char url-safe referral code at their storefront's /s/<slug>/account/referrals page — shareable link, suggested message, one-click copy, native share / WhatsApp / X buttons, live stats (clicks, signups, rewards earned).
  • Cookie-based attribution: clicking /s/<slug>/r/<code> drops storlaunch_ref_<accountId> (path-scoped per merchant so cross-merchant visits can't bleed), 302s to the storefront. Deep-linked ?ref= capture works too via a client-side component that strips the param after recording. Attribution commits when a brand-new buyer signs up via OTP under a matching cookie.
  • Reward fulfillment fires on payment-completed (both Xendit and PayPal webhook branches), transactional — either both sides get their code or neither does. Idempotent against webhook retries via attribution.status gate and DB-level @unique on CheckoutSession.referralAttributionId.
  • Refund clawback: when a qualifying checkout is refunded and neither issued code has been redeemed yet, both codes deactivate. If either was already used, codes stay live and the attribution is marked voided with reason refunded_after_use so reports can surface the recovery leak.
  • Guards against the usual abuse: self-referral blocked (same customerId or same email after trim/case-normalize), one attribution per new buyer per merchant, per-referrer reward cap enforced at fulfillment, cookie is per-merchant so a buyer on Shop A can never redeem Shop B's code.
  • Free tier is blocked from enabling the program (anti-spam — keeps the referral system from being used as an outreach/affiliate vehicle by unverified accounts). Pro and Business unlock it.
  • POST /api/v1/cron/referral-expiry-sweep flips pending attributions past their window to status=expired. Schedule alongside abandoned-cart-sweep.
  • CLI 0.15.0: sell referral-program {get, update, links, attributions, stats} — update merges with current state so you only pass the flags you want to change. buy referral {get-link, rewards} — a signed-in buyer can see their link + earned codes from the terminal.
v0.17.0

Blog CMS on every storefront

  • New /dashboard/marketing/blog — publish long-form content at /s/<your-slug>/blog. Markdown editor with live preview, cover image upload, tags, author name, per-post SEO fields. Drafts unlimited on every tier; Free tier caps *published* posts at 5, Pro and Business unlimited.
  • Server-rendered storefront blog pages — /s/:merchant/blog (card grid with excerpts, tags, author, publish dates) and /s/:merchant/blog/:slug (prose article with cover image). HTML-sanitized markdown body (sanitize-html) — safe to publish without worrying about raw <script> tags.
  • SEO out of the box: BlogPosting + Blog JSON-LD, OpenGraph + Twitter cards per post, sitemap.xml auto-indexes every published post, and a /blog/rss.xml RSS 2.0 feed discoverable from the storefront via <link rel="alternate" type="application/rss+xml">. Search Console + feed readers pick everything up automatically.
  • Publish / unpublish / delete state transitions preserved correctly: unpublishing keeps publishedAt history so re-publishing doesn't reset the timestamp. Drafts skip tier-limit checks entirely.
  • Storefront header adds a "Blog" link on desktop (hidden on mobile to keep the header compact).
  • CLI 0.14.0: sell blog list / get / create / update / publish / unpublish / delete — with --body-file to load markdown from disk and --publish to create + publish in one call (CI-friendly for repos that post release notes from a changelog/ folder).
v0.16.0

Product feeds for Google Shopping, Meta Catalog, and TikTok Catalog

  • Auto-generated product feeds at three stable URLs per merchant: /storefront/public/:merchantSlug/feeds/{google,meta,tiktok}.xml. Submit one URL per platform and your products show up in image-rich Google Shopping ads, Meta Advantage+ Catalog campaigns, and TikTok Shop ads. Feeds rebuild on every request and cache for 1 hour.
  • All three feeds use Google's RSS 2.0 spec with the g: namespace — Meta and TikTok both accept it natively. One <item> per variant under a shared g:item_group_id = product.id. Brand falls back to merchant store name when not set on the product. Image URLs are forced absolute so crawlers can fetch them.
  • Per-product feed fields in the product editor: GTIN (UPC/EAN/ISBN — auto-emits g:identifier_exists=no when missing), brand override, Google product category, and a feed-exclude toggle to omit a product entirely from ad-network catalogs.
  • New /dashboard/marketing/feeds page — master enable/disable, default Google product category (account-wide fallback), include-draft-products warning toggle, copy/preview buttons for all three feed URLs, and platform-specific submission steps.
  • CLI 0.13.0: sell feeds urls (print URLs), sell feeds inspect (fetch + validate XML — counts items, flags missing GTIN/image), sell feeds config get/set (--enable/--disable/--default-category/--include-unpublished).
v0.15.0

Abandoned cart recovery

  • New /dashboard/marketing/abandoned-cart — opt-in reminder emails for buyers who add items and don't check out. Configure delay (1-168h), email subject + preview, optional discount code attachment. 4 KPI cards (reminders sent, carts recovered, recovery rate, recovered revenue) + paginated recent-reminders table.
  • POST /api/v1/cron/abandoned-cart-sweep runs every 15 min. Finds eligible carts (verified buyer email, items present, abandoned past delay window, no reminder in last 72h, not opted out), snapshots the cart, sends a branded reminder via Resend. Atomic per-cart claim prevents double-sends under concurrent runs.
  • Per-cart-version eligibility: any cart edit resets the lastActivityAt clock so actively shopping buyers never get nagged. 72-hour anti-spam floor on top, so repeated edits never trigger more than one reminder per 72h.
  • Email: bullet-proof <table>-based HTML (Outlook + Gmail safe), preheader, inline CSS, plain-text fallback. List-Unsubscribe + List-Unsubscribe-Post headers (RFC 8058) so Gmail/Yahoo show their native one-click unsubscribe button.
  • Privacy: opt-in by default (enabled=false), signed HMAC unsubscribe tokens, BuyerEmailPreference table keeps buyers opted out across resign-ins. Transactional email (OTP, invoices, delivery tracking) is unaffected.
  • Recovery attribution: when a CheckoutSession completes for a customer who has an unrecovered reminder in the last 72h, that reminder is marked recovered. Time-window match (industry standard, matches Shopify/Klaviyo/Mailchimp). Dashboard shows recovery rate + recovered revenue over a 30-day window.
  • CLI 0.12.0: sell abandoned-cart config get/set, list, stats. --discount-code resolves friendly code strings via the existing /discount-codes list.
v0.14.0

Conversion tracking: Meta Pixel + CAPI, Google Analytics + Ads, TikTok Pixel

  • Per-merchant Meta Pixel on every storefront page with standard ecommerce events (PageView, ViewContent, AddToCart, InitiateCheckout, Purchase).
  • Meta Conversions API server-side Purchase events from the payment webhook — same event_id as the client Pixel so Meta dedupes. Keeps attribution alive on iOS Safari and under ad-blockers.
  • Client-side captures _fbp + _fbc cookies on /checkout mount and forwards them to CAPI, so Meta can attribute clicks across the 7-day ITP window.
  • Google Analytics 4 events with the proper schema (items[], value, currency, transaction_id). Google Ads conversion tracking piggybacks the gtag when you provide a conversion ID + purchase label.
  • TikTok Pixel with standard events auto-mapped (Purchase → CompletePayment etc.).
  • New /dashboard/marketing/pixels page — configure IDs, master enable/disable, CAPI token show/hide, inline hints pointing at where to find each platform's ID.
  • Public read endpoint /storefront/public/:merchant/pixels deliberately strips CAPI secrets — explicit allow-list that must be paired-reviewed on any edit.
  • CLI 0.11.0: sell pixels get/set/clear/test.
v0.13.0

SEO-ready storefronts — SSR + JSON-LD + sitemap + OG images

  • Storefront pages (/s/:merchant and /s/:merchant/:product) converted from client-rendered to server components. Crawlers see the product name, description, price, tags, and images in the HTML response before any JS runs.
  • Dynamic metadata on every storefront page: <title>, meta description, canonical, Open Graph + Twitter card tags, merchant-name page-title template.
  • Inline JSON-LD: schema.org/Organization + WebSite on the merchant root; Product (with offers.price, priceCurrency, availability flipping to OutOfStock when variants are exhausted, itemCondition=NewCondition) + BreadcrumbList on every product page.
  • Per-product Open Graph images via Next's ImageResponse — buyers sharing a product link in WhatsApp/Facebook/X get a 1200×630 card with product name, price, and thumbnail. Merchant-level card shows logo + name + description.
  • robots.txt auto-generated: allow public pages, disallow dashboard/api/checkout/cart/account.
  • Sitemaps: /sitemap.xml lists marketing pages; /s/:merchant/sitemap.xml lists the storefront root + every published product (merchants submit this to Search Console directly).
  • Backend: /api/v1/storefront/public/:merchant responses now include absolute logo/banner/thumbnail URLs + updatedAt; new GET /:merchant/sitemap endpoint feeds the Next per-merchant sitemap route.
  • CLI 0.10.0: sell seo inspect / sitemap / product-schema for quick pre-launch SEO verification.
v0.12.0

Public discount codes + per-item cart notes

  • Discount codes can now be marked public — they surface as a promo banner on the storefront product list, product detail, and cart. Click the banner to copy the code straight to the clipboard.
  • Cart items accept a per-item note (e.g. gift wrap, size in chest/waist) — the note flows through to the CheckoutSession metadata for the seller's fulfillment pipeline
  • New public endpoint: GET /storefront/public/:merchant/discount-codes — returns codes applicable to a given product / tag / cart subtotal
  • Editor: new Show on storefront toggle next to Active. Listing shows a Public/Private badge so sellers can tell at a glance which codes are promoted publicly
  • Storefront: cart layout aligned to the product list/detail max-width so navigation between the three pages feels consistent
  • CLI 0.9.0: sell discount-codes create/update now takes --public / --private; buy cart add / buy cart note handle per-item notes
v0.11.0

Storefront Cart + Buyer Auth UI

  • New /s/[merchant]/layout.tsx — shared header across every storefront page with merchant brand, cart icon (with item count), and Sign in / Account dropdown
  • Cart system: add multiple products to a cart, persist in localStorage when guest, sync to a server-side Cart on sign-in, and merge guest cart into the authed cart on first OTP verification
  • Cart drawer slides in from the header cart icon — line items with quantity steppers, remove button, subtotal preview, Checkout CTA
  • Full /s/[merchant]/cart page with editable line items, optional discount code, and a multi-item Proceed to Payment button
  • Backend: Cart + CartItem models, /checkout/cart CRUD + /merge routes, new /storefront/public/:merchantSlug/cart-checkout endpoint that creates a multi-item CheckoutSession (digital MVP — physical multi-item flow comes next)
  • AuthModal lifted to a shared component — buyers can sign in from any storefront page; the existing buyer dashboard still works unchanged
  • Account dropdown links: Orders, Invoices, Addresses, Account home, Sign out — finally a way to reach the buyer dashboard from the storefront
  • CLI 0.8.0: buy cart list/add/remove/clear/checkout
v0.10.0

Discount Codes & Vouchers

  • New /dashboard/discount-codes — create, edit, archive promo codes with percent / fixed / shipping-percent / shipping-fixed types
  • Scope control: whole cart, specific products (by productId list), or by product tags — the base the percent/fixed discount applies to
  • Rules: minimum purchase, global usage cap, per-customer cap, starts-at / expires-at windows, active toggle
  • Backend: validateCode() as a pure read (safe for public storefront preview) + idempotent redeem() committed from the payment webhook
  • Ledger: promo_discount + shipping_discount debit categories; P&L now has a Promotions block so discount cost is visible separately from operational expenses
  • Discount details snapshotted onto CheckoutSession so editing/deleting codes later never mutates past sales
  • Platform fees recomputed on discounted subtotal — merchants don't pay Storlaunch fees on revenue they gave away as promos
  • Public endpoint: POST /storefront/public/validate-discount — storefronts preview the discount without committing
  • CLI 0.7.0: sell discount-codes list/get/create/update/delete/validate
  • Sidebar: new Marketing section with Discount codes entry
v0.9.0

Payouts — Withdraw Funds to Bank

  • New /dashboard/payouts page — request payouts, track status, manage default bank account
  • Available-balance computation: ledger balance minus in-flight (pending + in_transit) payouts, so double-spending is structurally impossible
  • Bank account snapshot on payout creation — editing default bank later doesn't mutate history of past payouts
  • State machine: pending → in_transit → paid (or cancelled/failed). Merchants can cancel while pending.
  • On `paid` transition, auto-post a ledger debit (category: payout) with deterministic transactionId → idempotent replays
  • Manual mode now, Xendit disbursement upgrade path built in: method column + state machine stays identical when XenPlatform is approved; only the transport changes
  • New backend endpoints: GET /payouts, POST /payouts, /payouts/:id cancel/mark-in-transit/mark-paid/mark-failed, GET/PATCH /payouts/bank-account, GET /payouts/balance
  • CLI 0.6.0: sell payouts list/get/create/cancel/balance + sell payouts bank-account get/set
  • Sidebar: Payouts entry under Finance section
v0.8.0

Financial Reports — P&L, Cash Flow, CSV Export

  • New /dashboard/reports page with P&L and Cash Flow tabs, preset ranges (this month / last month / YTD / last 90 days) + custom date picker
  • P&L report: net revenue (sales − refunds), expenses breakdown (platform fees / channel fees / shipping), net profit
  • Cash Flow report: opening balance + closing balance + net change + inflows/outflows grouped by category
  • Ledger CSV export — download all entries for a period, format matches common accounting-software imports (date, reference, description, debit, credit, balance, customer_email)
  • Cash flow aggregates from signed deltas rather than stored balanceAfter — handles backdated entries correctly
  • New backend endpoints: GET /reports/pnl, GET /reports/cash-flow, GET /reports/ledger.csv (text/csv download)
  • CLI 0.5.0: sell reports pnl / cash-flow / export-ledger commands with --from / --to / --currency / --out flags
  • Sidebar: Reports entry under Finance section
v0.7.0

Ledger — Per-Merchant Money Log

  • New per-merchant ledger: every sale, refund, platform fee, channel fee, shipping cost, payout, and adjustment posts a signed entry with a running balance
  • Auto-post hooks on Xendit / PayPal payment success (sale + platform fee + channel fee) and on shipment creation (shipping cost)
  • Per-customer balance endpoint (AR view) — customerId FK stored so accounts-receivable workflows can build on this without a migration later
  • Idempotency keys on every entry (sourceType:sourceId:category) — webhook retries never double-post
  • Manual adjustments endpoint + dashboard modal for credits, debits, and write-offs (audit-logged via description)
  • New /dashboard/ledger page with balance card, filter-by-type/category, load-more pagination
  • CLI 0.4.0: sell ledger entries / balance / adjustments commands
v0.6.0

Inventory & Stock Management

  • Product variants (SKUs) — track sizes, colors, and other attributes independently
  • Multi-warehouse support — stock per variant per location with default-warehouse promotion
  • Stock adjustments with audit trail (manual_adjust, refund_restock, transfer_in/out, damaged, returned_to_supplier, initial_stock, import)
  • Low-stock alerts with per-variant thresholds surfaced in the Inventory dashboard
  • Bulk CSV import for stock levels (columns: sku, name, productSlug, warehouseId, quantity, lowStockThreshold, costPrice)
  • Stock reservation model — inventory is held for in-flight checkouts and released on expiry, commit, or cancel
  • Sidebar restructure — unified Fulfillment section with unique icons (Truck / Boxes / Warehouse / MapPin / Download)
  • CLI 0.3.0 — complete seller coverage for physical commerce: sell inventory (variants / warehouses / stock) and sell shipping (origin / couriers / shipments / track)
v0.5.0

Shipping & Fulfillment

  • Biteship integration — 16 Indonesian couriers (JNE, J&T, SiCepat, POS, TIKI, Wahana, SAP, Ninja, Lion, AnterAja, ID Express, Lalamove, Grab, Deliveree, GoSend, Borzo)
  • Live courier rates at checkout — buyers pick their preferred service with real-time pricing
  • Automatic shipping label generation on payment success
  • Physical product type with weight and dimension fields
  • Optional shipping insurance (opt-in at checkout)
  • Webhook-driven status tracking (pending → picked up → in transit → delivered)
  • Public buyer tracking page at /track/:waybillId
  • Merchant shipping settings (origin address, enabled couriers) in dashboard
  • Shipments dashboard with label printing, cancellation, and timeline view
v0.4.0

Production Launch

  • Production deployment with SSL and custom domain (storlaunch.forjio.com)
  • Full CI/CD pipeline: lint, test, build, deploy staging, E2E, deploy production
  • Nginx reverse proxy with automatic SSL certificate provisioning
  • Added about, changelog, blog, contact, status, and documentation pages
v0.3.0

Storefront Module & Public Pages

  • Public product pages at /s/:merchant/:product with SEO metadata
  • Product file uploads with multipart support
  • Digital delivery system with time-limited download links
  • License key generation and validation endpoints
  • README and GitHub repository description
v0.2.0

Payment Infrastructure

  • Hosted checkout page with QRIS, e-wallet, bank transfer, card, and PayPal support
  • Subscription billing with smart dunning (retry at 1h, 6h, 24h, 72h)
  • Webhook system with HMAC-SHA256 signature verification
  • Billing portal for plan management and invoice history
  • Xendit XenPlatform integration with OWNED sub-accounts (no customer KYC)
v0.1.0

Initial Release

  • Three independent modules: Payment, Storefront, Shipping
  • Dashboard with API key management, product management, and payment tracking
  • CLI tool (@storlaunch/cli) with auth, checkout, and storefront commands
  • REST API with Bearer token authentication and envelope response format
  • Free, Pro, and Business pricing tiers