Release Notes

What’s shipped

What changed on indolent.design: checkout, downloads, docs.

Site
indolent.design··CAD on sale

Indolent CAD is on sale

Indolent CAD is on sale at $249.99 per year for one named seat, paid through Stripe's secure checkout. Version 0.7.0 is the first public signed release.

Added

  • CAD Buy buttons: every CAD button on the home page, /products,

/pricing and the CAD page says "Buy Indolent CAD — $249.99 / year" and opens the Stripe checkout for Indolent CAD. /buy?product=cad_solo goes to the same checkout. The CAD badge reads "Now selling" with the released version. The licence key is emailed by the Indolent CAD licence server once the order completes.

  • CAD sales switch: the server variable CAD_PAYMENT_LINK_URL (only an

https://buy.stripe.com/ link is accepted) turns CAD sales on; unset, every CAD surface says "Orders open soon". CAD_RELEASED_VERSION sets the version the badge shows. This site's own CAD checkout stays off in both states, so a sale is never licensed twice. See DEPLOY.md step 9c.

  • Home hero "Steel Studio": real Indolent CAD engine exports (a portal

frame and a W12 beam), studio-lit and always posed at a three-quarter view, with a title block measured from the exported files and a model switcher. A static poster paints first and the 3D view loads after it.

  • CAD product page redesign: real app captures, a proof strip, and a

pricing and terms section linking the CAD licence agreement and the getting-started guide. Sideways scrolling on phones is fixed.

  • Home CAD card: shows the Indolent CAD home screen beside the Forge nest

demo; the two cards are the same height.

Changed

  • Indolent CAD is presented as a complete product on every page. Updates

wording: "Includes the updates we release during your subscription year".

  • The CAD tab of this changelog now includes 0.7.0, and its note follows the

sales switch instead of always saying "Orders open soon".

Site
indolent.design··pricing

Forge moves to $49.99 per year; CAD Solo price confirmed

Forge moves to a $49.99/yr Stripe subscription with dated keys; CAD Solo $249.99/yr is confirmed (Buy still waits on STRIPE_CAD_SOLO_PRICE_ID).

Added

  • Forge subscription money path: checkout runs in Stripe subscription

mode (STRIPE_PRICE_ID must be the RECURRING $49.99/yr price); the webhook signs a DATED key YYYY-MM-DD.<sig over '<machine_id>|<date>'> whose date is the paid-through date (365-day term). FORGE_LICENSE_FORMAT now defaults to dated and FORGE_TERM_DAYS to 365; bare stays selectable by env for emergencies only.

  • Forge renewals: invoice.paid with billing_reason=subscription_cycle

and amount_paid > 0 for an existing Forge subscription signs a new dated key at previous expiry + 365 days (today + 365 if lapsed), updates the order (license_key, expires_at, renewal_invoice_id in one conditional updateOrderLicense), records a server-only renewal event and emails the key with the "paste it in Settings > License" step (emails/Renewal.tsx, Forge variant). The first invoice (subscription_create) belongs to checkout; subscription_update prorations, manual and threshold invoices (which Stripe also reports as invoice.paid, often for $0) are ignored. customer.subscription.deleted records a cancellation event only; the key expires on its printed date.

  • Renewal idempotency (migrations/007_orders_renewal_invoice.sql):

orders.renewal_invoice_id records the last invoice applied. Stripe delivers webhooks at-least-once; a redelivered or concurrently delivered invoice.paid now answers duplicate instead of extending the term (and, for Forge, signing and emailing a second key) again. Applies to CAD renewals too. Run `npm run migrate` before deploying this.

  • Admin activity feed renders renewal / cancellation rows (server-only

event types in lib/analytics.ts, kept out of the public beacon allowlist).

  • LICENSE_FORMAT_MAP maps 3.15 -> dated. npm run check:license-format

is red by design until the Indolent 3.15 desktop (commit 050cef8) ships; see DEPLOY.md Step 6b.

Changed

  • Forge pricing copy across the site: Indolent Forge Nesting is now $49.99 per

year, one machine, cancel any time. The license key is valid through the paid date; all updates are included while the license is active. Every hardcoded "$499", "one-time", "perpetual" and "forever" Forge string was rewritten (home, pricing, products hub, Forge page, compare, ROI, about, blog cost widget, Vibe cross-link, OG image, layout metadata + JSON-LD).

  • Pricing page: Forge card shows $49.99 / year with a YEARLY LICENSE badge;

CAD Solo shows $249.99 / year (price confirmed, chip removed by the catalog). JSON-LD Offers carry a yearly UnitPriceSpecification.

  • ROI calculator + RoiMini: payback uses the $49.99 first-year price

(FORGE_FIRST_YEAR_CENTS in lib/roi.ts) and labels it "per year, first year".

  • Pricing FAQ: the major-version-upgrade answer is replaced by "all updates

included while your license is active"; new yearly-license answer; refund answer notes the 30-day window applies to the first purchase and that renewals are avoided by cancelling before the renewal date (a surprise charge: email us). No renewal refund window is published; that number is still Blake's call.

  • Refunds page: 30-day money-back on the first purchase; renewals line covers

Forge and CAD with the same cancel-before / email-us wording.

  • Compare page 3-year math: Forge $149.97 ($49.99 x 3) vs ROMAC + PC8 $2,450;

the "ROMAC is genuinely cheaper" line now says when that is true (nesters alone, past year four).

  • ROMAC migration post: the derived TCO figures were still $499-era. Now

$2,300 saved over three years vs ROMAC + PC8 (no break-even period: Forge is cheaper from year one), three years of PC8 = 45 Forge years, ROMAC's $200 nesters cost less than Forge only from year five, and "auto-updates for life" became "all updates included while active".

  • /buy?product=cad_solo no longer says "Pricing to be confirmed" under a

confirmed price; the fallback CTA reads "Checkout opens once the Stripe price is live" (CAD Shop: "quoted per shop").

Site
indolent.design·

Multi-product checkout, CAD evidence, ROI, trust pages

The site now sells from one typed product catalog and can sell a second product the day it has a Stripe price.

Added

  • Product catalog (lib/products.ts): Forge Nesting ($499 perpetual, selling),

CAD Solo ($249.99/yr one named seat, price to be confirmed, Buy disabled until STRIPE_CAD_SOLO_PRICE_ID exists) and CAD Shop (quote only). Checkout, the Stripe webhook, license issuance and the activation email are product-aware.

  • Forge key format switch FORGE_LICENSE_FORMAT=bare|dated (default bare,

matching the shipped Indolent 3.14.3) with a CI guard (npm run check:license-format) that fails if the released desktop version is not mapped. npm run check:env prints the per-product env table before deploy.

  • Trust surfaces: /refunds, /security, a trust strip on the buy path, the

license key shown inline on /thanks, and a purchase-order path.

  • Proof: a computed before/after nest slider and ROI calculator on the Forge

page; real Indolent CAD engine outputs (NC1, PDF, DXF, STEP) beside the 3D viewer with a prompt-to-part demo.

  • Changelog now has a product switcher (Forge / Site / CAD). Forge notes are

synced from the desktop repo so the top entry is the real 3.14.3; CAD shows the pilot-builds banner.

  • Ops docs: docs/SELLING.md (Stripe products, webhook events, Railway env,

migration order, go-live gate) and a "Selling two products" section in DEPLOY.md.

Site
indolent.design··2

Connect

Connect goes from ported MVP to shippable product — live free beta.

  • Dedicated database. CONNECT_DATABASE_URL (falls back to the shared

DATABASE_URL until the Railway cutover); own migration track migrations/connect/ + npm run migrate:connect. Boundary + operations doc at docs/CONNECT.md. Retired migrations/003_connect.sql (001_init converges both fresh and pre-existing databases).

  • Card templates. Four designs — Executive (signature gold), Steel,

Blueprint (drafting-grid), Blackout — picked in the dashboard with live mini previews; all tokens data-driven in lib/connect/templates.ts. Customers can upload their own logo (client-resized data URL, ≤200 KB, PNG/JPEG only) which replaces the mark on the card and QR center.

  • Connect Pro billing ($5/mo). Stripe subscription checkout + customer

portal; subscription lifecycle handled in the existing webhook, discriminated by mode === 'subscription' + metadata.product === 'connect_pro' — the Forge license flow is byte-for-byte untouched and its regression suite still passes unmodified. Plan gate: lib/connect/plan.ts; CSV export is the first Pro feature.

  • Friction-free signup. /connect/start routes new users through the

existing onboarding form (their company + title become a site lead, tagged source='connect' via the new leads.source column) and on to the Connect dashboard; first-run checklist (fill card → pick template → publish). Product page flips to "Live — free while in beta" with "Create your card — free" CTAs.

  • Security hardening (from the pre-ship adversarial review): lead-capture

alerts go only to the owner's verified Clerk email (never the public, owner-settable profile.email), with a server-side honeypot, a 4 KB body cap, and a per-card hourly email throttle — closing an email-relay/mail-bomb vector. Re-subscribe reuses the existing Stripe customer and blocks checkout while any live subscription (incl. past_due dunning) exists, so no duplicate customers/charges. A late subscription.deleted for a replaced subscription can no longer drop a re-subscribed user. CSV export is now a real server-gated Pro route. past_due keeps Pro during Stripe's retry window. isTemplateId uses Object.hasOwn (no prototype-key matches).

  • Tests: 21 new (templates/validation, plan lifecycle + resubscribe guard,

webhook subscription branches incl. replay / out-of-order / stale-delete, CSV paywall, leads source). Suite: 23 files / 120 tests.

Site
indolent.design·

Indolent Connect now runs from this site

Ported the standalone indolent-connect app (Next 14 + Prisma) into this codebase on the site's own stack (postgres.js + SQL migrations + Clerk v7). Free tier end-to-end; billing is a follow-up.

Added

  • `/u/[handle]` — public Connect card: real hex ID mark, pointer tilt,

Save-button shimmer, client-side vCard QR (scan saves the contact), and a "Let's connect" lead form (honeypot-protected) that writes a lead and emails the card owner (emails/LeadAlert.tsx).

  • `/connect/dashboard` — Clerk-gated card editor: all card fields,

linkedin/github, publish toggle, live card + print-ready QR links, lead list with CSV export. One card per user (free tier).

  • APIs — POST /api/connect/lead (public), GET|PUT /api/connect/profile

(auth; handle validation + reserved words, http(s)-only links, friendly 409 on taken handles), GET /api/qr/[handle] (1024px PNG of the profile URL, built from CONNECT_BASE_URL so cards survive a future subdomain move).

  • `migrations/003_connect.sql` — connect_profiles / connect_links /

connect_leads (+ seeded published demo card /u/blake).

  • Gold brand tokens (gold, gold-hi, gold-bronze) in the @theme

block + tailwind.config; shared components/IndolentMark.tsx.

  • Tests — tests/lib/connect-db.test.ts (Testcontainers): seed, upsert,

handle uniqueness/validation, lead insert/list/cascade, vCard mapping.

Changed

  • Middleware now protects /connect(.*) and /api/connect/profile(.*).
  • Connect product page CTA links to the live demo card at /u/blake.

Dependencies

  • Added qrcode (runtime) and @types/qrcode (dev). MIT.
Site
indolent.design·

Website — interactive pass (CAD launch page, 3D viewers, nesting demo, Connect)

Added

  • Interactive 3D model viewers (components/ModelViewer.tsx) — three.js

(MIT), dynamically imported so it never lands in any page's initial bundle. Orbit + auto-rotate that yields to the user, steel PBR + edge lines, renders only on screen, prefers-reduced-motion respected. Two real engine-built GLBs shipped in public/models/ (portal frame 126 KB, beam w/ web holes 57 KB).

  • `/products/indolent-cad` rebuilt as the launch page — interactive portal-

frame hero, five-ways-in loop (prompt / sketch / DXF / PDF / 3D model → one package), screenshot tour, beam-with-holes viewer beside the DSTV copy, proof grid. Still coming-soon + waitlist CTA; no public pricing.

  • Live nesting demo on `/products/forge-nesting` (components/NestingDemo.tsx)

— a real first-fit-decreasing nest computed in the browser and animated onto 40′ sticks with live part count and yield; drops called out in cream. Canvas only, no new dependencies. Click to replay.

  • Homepage interactive hero — two-column hero with the orbiting portal

frame beside the copy, and a pointer-reactive brand mark (components/LogoMark.tsx): 3D tilt toward the cursor, specular light sweep, breathing ice glow. Falls back to static under reduced motion / touch.

  • Indolent Connect added to the lineup — new /products/indolent-connect

coming-soon page (digital business cards + lead capture, transparent launch pricing table), fourth coming-soon card on the homepage and /products, footer link, sitemap entries (Connect + the previously missing Vibe).

  • Scroll-reveal polish (components/Reveal.tsx) — IO-based fade/rise on

section cards, one-shot, reduced-motion safe.

Dependencies

  • Added three (runtime) and @types/three (dev). Both MIT.
Site
indolent.design·

Notes

_Site release shipped alongside Indolent Forge Nesting 3.7.0._

Website — LinkedIn-launch prep

Repositioned the Indolent Designs site for a public launch and closed the remaining Forge launch-polish gaps.

Added

  • Indolent CAD product page (/products/indolent-cad) — a "coming soon" page

for the new flagship: AI CAD for steel (describe a part → parametric model → shop drawing → NC1/DSTV). Added to the sitemap and footer.

  • Top-level `/privacy` page — fixes a sitewide footer/sitemap 404; documents

the real data flows and processors (Stripe, Resend, Clerk, Plausible, Railway).

  • `/contact/received` page — project inquiries now land on a proper contact

thank-you instead of the license order-complete page.

Changed

  • Positioning flipped to one-live / three-coming-soon. Homepage and

/products now present Indolent Forge Nesting as the single live product, with Trucking, CAD, and Vibe in a coming-soon row.

  • Indolent Trucking demoted to "coming soon — reach out for pricing." Removed

the monthly price, the production metrics (call volume / uptime), the named design-partner, and the "shipped"/"live in production" claims across the Trucking pages, the homepage, /products, /about, the footer, and the Vibe page's build list. CTAs now point at /contact.

  • Machine-ID copy on the buy form and docs now reflects the real IF-…

desktop format instead of the legacy 64-char hex description.

Fixed

  • Removed a dev screenshot placeholder that was shipping on the $499 Forge product

page; it now renders the real KISS-import screenshot.

  • Repointed Trucking CTAs off a raw Railway hostname onto internal routes.
Site
indolent.design·

Notes

_Site release shipped alongside Indolent Forge Nesting 3.6.0._

Admin Dashboard 2.0

Upgraded /admin from static totals to a full momentum dashboard — look great, easy to use, powerful.

Added

  • KPI cards with % deltas — visits, signups, downloads, purchases each show

current-period count vs prior period with a colour-coded delta (green up / red down).

  • Sparklines — 7-point SVG sparkline per KPI card rendered from the same timeseries

query; no chart library added.

  • Traffic chart in Phoenix time — "Today" view renders hourly bars (Phoenix is

fixed UTC-7, no DST) zero-filled so gaps are visible. Older ranges render daily bars. All bucketing via the phoenixMidnight helper in lib/analytics.ts.

  • Live activity feed — recent events (page views, signups, downloads, purchases)

pulled from the events + orders tables; purchases display the order amount from real order rows, not just the event record.

  • UTM campaign breakdown — top source/medium/campaign combos ranked by visit count.
  • Browser / OS breakdown — top user-agent families (parsed from events) ranked by

count.

  • Leads table with search — /admin accepts ?q= to filter the leads table by

email or company; server-rendered, no client JS required.

  • Hardened CSV export — GET /api/admin/leads.csv returns all leads as a

downloadable CSV. Non-admins receive a plain 403 Forbidden (not a redirect) so the endpoint cannot be probed via redirect-following.

  • Orders table with TEST badges — all-time orders list; test-mode orders are

clearly badged to separate them from real revenue.

  • 60-second auto-refresh — AutoRefresh client component calls router.refresh()

every 60 s so the server components re-run and the dashboard stays live without a manual reload.

Changed

  • app/admin/page.tsx — full rewrite; now an orchestration-only server component that

delegates rendering to focused sub-components under app/admin/components/.

  • lib/analytics.ts — extended Range type; added getOverviewWithDeltas,

getTimeseries, getActivityFeed, getUtmBreakdown, getTechBreakdown.

  • lib/leads.ts — getLeads accepts optional search param; added leadsToCsv.
  • lib/db.ts — added getOrders with is_test flag detection.

No migrations / env vars / new dependencies

All new features are served from existing tables (events, orders, leads). No new Railway env vars required. No npm packages added. Deploy with railway up.

Site
indolent.design·

Notes

_Site release shipped alongside Indolent Forge Nesting 3.5.0._

Clerk-gated trial download, lead capture, analytics, and admin panel

The trial download is now behind a Clerk sign-in wall. Visitors must create an account before downloading the desktop installer. This gives us a verified email + name for every trial user, plus the opt-in company/job title captured on a one-time onboarding screen.

Added

  • Download gate — all trial-download buttons now link to /download (gated), not the

raw GitHub URL. Clerk sign-in/sign-up is required before any installer download.

  • Lead capture via onboarding — after sign-up, users land on /onboarding and provide

company name + job title. Stored in a new leads table alongside the Clerk user ID and email. The onboarding gate is enforced server-side on the /download page via a DB check (lead completeness) — no Clerk session-token claim needed.

  • First-party analytics — events table records page_view, signup, download,

checkout_start, and purchase events. No raw IPs (hashed + salted). No analytics cookies; no cookie banner required.

  • Plausible integration (prod-only) — managed analytics script in <head>, gated on

NEXT_PUBLIC_PLAUSIBLE_DOMAIN. Zero impact on the first-party pipeline; purely a second pane of glass.

  • Conversion funnel — visit → signup → download → purchase tracked in Postgres. Visits/

signups/downloads come from the events table; the purchase stage is counted directly from the orders table (the source of truth), so revenue and purchase counts stay consistent. A purchase event is also recorded for the audit trail.

  • Private `/admin` dashboard — server-rendered. Shows overview stat cards, funnel with

conversion %, daily-visits bar chart (CSS/SVG, no chart library), leads table, and orders table. Access restricted to ADMIN_EMAILS (comma-separated allowlist) using Clerk's verified primary email. Defense in depth: middleware + requireAdmin() per route.

  • `@clerk/nextjs` v7 — Clerk is the single auth system for download gating and admin

access. Sign-in/sign-up pages at /sign-in and /sign-up are styled to the ice/steel/dark theme.

  • Migration 002_leads_events.sql — adds leads and events tables (apply with

npm run migrate).

  • New API routes: /api/download (records event + 302 redirect), /api/onboarding

(upserts lead + sets publicMetadata), /api/track (public beacon, always 204).

Changed

  • BREAKING: `NEXT_PUBLIC_TRIAL_DOWNLOAD_URL` → `INSTALLER_DOWNLOAD_URL` (server-only).

The raw GitHub installer URL is no longer published to the browser bundle. All trial entry points now go through /download → /api/download. Update Railway env accordingly and remove the old NEXT_PUBLIC_TRIAL_DOWNLOAD_URL var.

  • lib/db.ts — exports the sql singleton for reuse by lib/leads.ts and

lib/analytics.ts (avoids opening a second connection pool against Railway's low cap).

New required env vars

`` NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY CLERK_SECRET_KEY NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/download NEXT_PUBLIC_CLERK_SIGN_UP_FORCE_REDIRECT_URL=/onboarding ADMIN_EMAILS=holmeslucky@gmail.com INSTALLER_DOWNLOAD_URL=<stable GitHub release URL> ANALYTICS_IP_SALT=<openssl rand -hex 32> NEXT_PUBLIC_PLAUSIBLE_DOMAIN=indolent.design ``

No Clerk session-token customization is required — the onboarding gate checks the database (lead completeness) on the /download page, not a Clerk session claim.

Notes

  • Existing /buy checkout flow is public (no Clerk login wall) — the desktop app opens

/buy?machine_id= directly and must never hit a login redirect.

  • ADMIN_EMAILS is compared case-insensitively against Clerk's verified primary email.
  • Plausible account/domain must be created separately by Blake before the managed pane works.

First-party panel (/admin) works without Plausible.

Site
indolent.design·

Notes

_Site release shipped alongside Indolent Forge Nesting 3.4.0._

First public release

Indolent Forge Nesting is now available at indolent.design as a $499 perpetual-license commercial product. The same nesting engine that has been in daily shop use is now sellable, with a real license-issuance pipeline behind it.

Added

  • Public sales site at indolent.design with checkout, pricing, comparison, and docs
  • Stripe Checkout integration for $499 one-time payment
  • Ed25519 license signing pipeline (machine-ID-locked perpetual keys)
  • Automated license email delivery via Resend on successful payment
  • 14-day free trial download — full functionality, no credit card
  • 30-day money-back guarantee

Changed

  • Renamed product to Indolent Forge Nesting for commercial release
  • New brand: indolent.design domain, refreshed marketing site, professional installer

Notes

This is the first release where the binary contains a production license-signing public key. Earlier internal builds used a placeholder key.