Skip to content
CAI
Software that uses CAICheck a score

antiwork/gumroad

43.4

Weak · 27 September 2026

303.8k

lines of production code

Ruby

with TypeScript

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a comprehensive e-commerce platform for digital creators, handling the full lifecycle of product sales, payments, and payouts. It provides sellers with robust tools for storefront management, marketing automation, and customer engagement, supported by a modernized, client-side rendered interface. The platform integrates complex financial logic for multi-currency transactions, tax compliance, and agent-assisted store operations.

How it got here

2025 — frontend modernization and payment expansion

200 changes.

The project undertook a comprehensive migration of the frontend infrastructure, replacing the legacy Sprockets and React-on-Rails asset pipelines with Vite and Inertia.js while standardizing styling with Tailwind CSS. Simultaneously, the backend saw significant expansion in payment processing capabilities, adding support for new global methods like UPI and Pix, enhancing Stripe and PayPal integrations, and introducing robust compliance and payout management features.

2026 — Inertia.js migration and platform modernization

62 changes.

This period focused on migrating the majority of the frontend to Inertia.js and React, replacing server-rendered views with client-side navigation across user, seller, and public-facing pages. The work also included significant infrastructure updates such as the test suite migration to Minitest, the introduction of an internal admin API, and the launch of new features like the conversational Agent and automated marketing tools.

Features

Add Apple OAuth support and configure Vite for the frontend build

The application now supports login via Apple, including the necessary root certificates and an initializer that handles the cross-site nonce cookie workaround and fixes a Rails 8 parameter parsing issue for the pwned-password check. The frontend build has migrated to Vite, with configuration for asset hosts and manual chunking for heavy libraries like the rich-text editor, charts, and PDF.js. Additionally, the test suite now isolates Redis databases per concurrent run to prevent key collisions, and the deployment pipeline includes a check to refuse migrations if interrupted pt-online-schema-change leftovers remain on tables.

config · high confidence

Add Churn analytics page

Introduces a new Churn analytics page (app/javascript/pages/Churn/Show.tsx) that displays churn metrics including a chart, quick stats, and a date range picker. The component allows users to filter data by specific products and toggle between daily and monthly aggregation views, syncing the selected date range with server-side data reloads.

app/javascript/pages/Churn · high confidence

Add authenticator app and passkey management to password settings

The Password settings page now includes dedicated sections for managing two-factor authentication methods. Users can set up an authenticator app via a QR code or manual secret key, verify the setup, and securely save or download the generated recovery codes. Additionally, a new Passkeys section allows users to add, rename, and remove passkeys (where browser-supported), with a limit of ten passkeys per account.

app/javascript/components/Settings/PasswordPage · high confidence

Add tax form download capability to the dashboard

Users can now download available tax forms directly from the dashboard. A new 'Tax forms' button opens a popover where users can select specific tax years via checkboxes, with options to select or deselect all years, and then trigger downloads for the chosen documents.

app/javascript/components/server-components/DashboardPage · high confidence

Added pending state page for Stripe redirect payments

A new 'Pending' page has been added to the checkout returns flow to handle Stripe redirect payment methods. When a user is redirected back to the site after authorizing a payment, this page displays a 'Your payment is being processed' message and automatically reloads every 3 seconds to check for completion. It includes logic to stop polling after 5 minutes or if session storage is unavailable, ensuring users are not left in an infinite loop while waiting for the payment to finalize.

app/javascript/pages/Checkout/Returns · high confidence

Added social account connections for Instagram, TikTok, and YouTube

Users can now connect their Instagram, TikTok, and YouTube accounts to the platform. This change introduces dedicated OmniAuth strategies for each service, allowing users to authenticate and link these social profiles. The connections are gated by feature flags (instagram\_connect, tiktok\_connect, youtube\_connect) and are accessible via the social connections settings page, with fallback redirects to login if the feature is unavailable or the user is not signed in.

_lib/omni\auth · high confidence

Admin users can now investigate related accounts and enrich payout data directly from the admin interface. The new RelatedUsersService allows admins to find other users sharing an IP address, payment address, or card fingerprint with a target user, supporting fraud and abuse investigations. Additionally, the ScheduledPayoutEnrichmentService now attaches seller context to payout batches, including product counts, affiliate counts, risk state, top product categories, and unpaid balance, providing a more comprehensive view of seller activity during payout processing.

app/services · high confidence

Document new and existing API endpoints in the public reference

The public API documentation now includes detailed reference pages for several previously undocumented or sparsely documented endpoints. This update adds full documentation for the Media Library (GET, POST, DELETE /media), the file upload flow (POST /files/presign, /complete, /abort), and product covers (POST, DELETE /products/:id/covers). It also documents the Earnings breakdown endpoint (GET /earnings), the full lifecycle of product custom fields (CRUD /products/:id/custom\_fields), and the audience email management endpoints (CRUD /emails). Additionally, existing endpoints for Offer Codes, Payouts, Licenses, and Product Reviews are now fully documented with structured response fields, cURL examples, and Gumroad CLI equivalents, providing creators with clear guidance on how to integrate with these features.

app/javascript/components/ApiDocumentation/Endpoints · high confidence

Enable video review playback and upload configuration

Customers can now view approved video reviews on product pages, as the system exposes streaming URLs and SMIL playback endpoints gated by moderation status and purchase verification. Additionally, the upload flow is supported by an endpoint that provides the necessary AWS credentials and S3 endpoint configuration for direct video uploads.

_app/controllers/product\_review\videos · high confidence

Help center page now includes category sidebar and embedded help videos

The Help Center page now features a navigable category sidebar (CategorySidebar) that lists help topics and highlights the active section, alongside support for embedded help videos (mountHelpVideos). Videos are initialized via JW Player based on data attributes, and user engagement is tracked via Google Analytics events for video start, progress (at 25%, 50%, 75%), and completion. This change also introduces shared TypeScript types (SidebarCategory, ArticleLink, ArticleCategory) to support these UI components.

app/javascript/components/HelpCenterPage · high confidence

Internal API endpoints for approving and rejecting product review videos

Added two new internal API controllers, ApprovalsController and RejectionsController, under the product\_review\_videos namespace. These endpoints allow authenticated internal users to approve or reject specific product review videos by their external ID, enforcing authorization checks before updating the video's status.

_app/controllers/api/internal/product\_review\videos · high confidence

Introduce Store Agent chat persistence, streaming, and HTML preview endpoints

Sellers can now resume Store Agent conversations after page refreshes, as the backend persists chat history server-side and exposes it via a new \latest\ endpoint. Streaming replies are handled by a dedicated SSE controller that supports real-time token rendering and includes robust recovery logic for broken connections, ensuring turns are tracked and persisted even if the stream drops. Additionally, a new preview endpoint allows sellers to see a live, script-enabled visual preview of custom HTML changes proposed by the agent before confirming them, resolving previous issues where raw markup was displayed. The legacy affiliate and cart controllers have been removed from this internal API scope.

app/controllers/api/internal · high confidence

Introduce admin API token and authorization infrastructure

This change adds the backend models required for the new admin API token lifecycle and OAuth device authorization flow. It introduces \AdminApiToken\ to manage token minting, hashing, and expiration, \AdminApiAuthorizationCode\ to handle the PKCE-based authorization code exchange, and \AdminApiAuditLog\ to record every admin API action for audit purposes. These models provide the foundation for the internal admin authentication and access logging features.

app/models · high confidence

Introduce automated marketing actions and holdout logic

This change introduces the core data models for the new auto-marketing feature. It adds \Marketing::Action\ to manage the lifecycle of social posts (including X/Twitter and Email), handling states like recommended, approved, queued, and posted, with specific logic to allow sellers to reconnect X accounts without losing pending actions. It also adds \Marketing::Channel\ to define supported channels and \Marketing::HoldoutAssignment\ to freeze a 20% holdout group of sellers for A/B testing based on their prior sales buckets.

app/models/marketing · high confidence

Introduce dedicated Following wishlists page

Users can now view and manage their followed wishlists via a new dedicated page that displays a table of wishlists including the name, URL, product count, and creator details. The page allows users to unfollow wishlists directly from the list using a popover menu, with immediate UI updates and success or error notifications. The view also includes an empty state with a placeholder image and a link to help documentation when no wishlists are being followed.

app/javascript/pages/Wishlists/Following · high confidence

Introduce first-class Pages with a rich-text editor and image upload support

Sellers can now create and edit custom pages directly from the dashboard using a rich-text editor that supports inserting images via paste, drag-and-drop, or toolbar button. The editor includes a save guard that prevents persisting content until in-flight image uploads have resolved to stable CDN URLs, ensuring previews and saved content remain consistent. The Pages index lists the profile as the 'Home' page and any custom pages, distinguishing between rich-text pages and custom HTML pages built by agents, with appropriate editing paths for each.

app/javascript/pages/Pages · high confidence

Introduces new presenters for admin, API, checkout, and discovery surfaces

This change adds a suite of new presenter classes in app/presenters to structure data for various product surfaces. Admin presenters (ScheduledPayout, UserRiskState) expose payout and risk details for the admin interface. API presenters (ProductSections, Workflow) provide structured JSON for profile sections and email workflows. The checkout presenter (StripePaymentPresenter) manages the configuration for the new Stripe Payment Element, including buyer-currency presentment and client-confirm flows. Discovery presenters (CategoryPage, RecentlyViewed) handle SEO metadata and product recommendations. Additional presenters (Agent, Guardian, HelpCenter, IncomingCollaborators, PublicApiProps) support the conversational agent dashboard, legal guardian settings, help center navigation, collaborator management, and the public product API.

app/presenters · high confidence

Launch of Gumroad Blog feature with Inertia.js integration

This change introduces a new Gumroad Blog feature, implemented via new controllers (BaseController and PostsController) that serve content through Inertia.js. The PostsController exposes blog posts (index and show actions) by fetching installments associated with a configured blog owner, rendering them as Inertia props for frontend components. It includes authorization checks via Pundit and sets a layout of 'inertia', indicating a shift to a client-side rendered experience for this section of the application.

_app/controllers/gumroad\blog · high confidence

Launch of internal admin API with token-based authentication and audit logging

This change introduces a new internal admin API (\/internal/admin\) that replaces the previous admin web UI. It provides a comprehensive set of read and write endpoints for managing users, purchases, products, payouts, and compliance, along with specialized tools for stranded-buyer recovery and SendGrid suppression management. Access is secured via a new \AdminApiToken\ system that supports per-actor authorization and token revocation, and all write actions are automatically recorded in an \AdminApiAuditLog\ with redacted parameter snapshots to ensure full accountability for administrative changes.

app/controllers/api/internal/admin · high confidence

New AI agent skills for development, production debugging, and operations

Added a set of new agent skills under \.agents/skills/\ to standardize and automate key workflows. The \commit\ skill enforces linting, type-checking, and test confidence before staging changes. The \gumroad-prod-console\ skill and its \prod\_query.sh\ script provide a read-only, persistent Rails runner for production debugging with improved host discovery, stale-key handling, and slow-instance retry logic. The \email-blast\ skill enables safe, one-off production email campaigns with Metabase recipient validation and dry-run previews. The \create-issue\ and \review-pr\ skills guide the drafting of structured GitHub issues and the execution of multi-pass PR reviews against project guidelines, while the \test-confidence\ skill automates diff-aware test execution to verify change safety.

.agents · high confidence

New API endpoints for creating and updating workflow emails

A new \EmailsController\ has been added to the API v2 workflows namespace, enabling users to create and update email installments within a workflow. The endpoint accepts parameters for subject, body, and delay configuration (amount and unit), while enforcing validation rules such as preventing delays on abandoned cart workflows, ensuring delay values do not overflow the installment rule column, and requiring both delay amount and unit to be provided together.

app/controllers/api/v2/workflows · high confidence

New API v2 endpoints for storefront management, media, and seller operations

The API v2 surface is significantly expanded with new controllers for managing storefront pages (create, update, delete, and pull HTML), handling public media library uploads and deletions, and configuring product-level refund policies. Sellers can now manage product covers and thumbnails via dedicated endpoints, update bundle contents, and configure upsells and cross-sells. Additional endpoints expose seller earnings, tax forms, and upcoming payouts, while email marketing capabilities are extended with schedule, unschedule, and audience filtering. The API also introduces a Muse MCP connector for agent integration, public help article lookups, category discovery, and UTM link management, alongside direct OAuth uploads for product media.

app/controllers/api/v2 · high confidence

New Billing Settings page for managing invoice details

A new Billing settings page has been added, allowing users to manage the billing details used to pre-fill invoices. The page includes fields for full name, business name, street address, city, state, ZIP code, and country, with conditional logic to show the state field for US addresses and a business ID field for specific countries. Users can also add additional notes and toggle auto-email invoice settings.

app/javascript/pages/Settings/Billing · high confidence

New CI efficiency, local dev isolation, and migration safety tools

This update introduces several new scripts to the bin directory to improve developer experience and CI reliability. \bin/branch-specs\ and \bin/rspec-changed\ enable branch-aware test selection, mapping changed files to relevant specs to run only what is necessary instead of the full suite. \bin/reuse-full-suite\ allows main branch CI to skip redundant Fast/Slow runs if a PR already tested the same code tree. For local development, \bin/dev-lane\ provides isolated parallel environments with scoped ports and databases, while \bin/test-confidence\ uses AI to plan and execute tests for faster feedback. Additionally, \bin/check-migration-versions\ prevents database collisions from duplicate migration versions, and \bin/classify-hung-checkout\ automates re-runs for stuck CI checkouts. The toolset also includes \bin/minitest-shard\ for test distribution, \bin/vite\ for the new frontend build system, and \bin/setup\ now initializes the DynamoDB engagement table.

bin · high confidence

New OAuth Application Edit page in Settings

A new page has been added to the Settings area to allow users to edit OAuth applications. This page, located at app/javascript/pages/Oauth/Applications/Edit.tsx, renders an ApplicationForm within the standard Settings Layout, utilizing Inertia for data fetching and typia for runtime type assertion of the application props.

app/javascript/pages/Oauth · high confidence

New React hooks for data fetching, lazy loading, and UI interactions

Added five new custom React hooks to the application's hook library: useLazyFetch and useLazyPaginatedFetch for handling asynchronous data retrieval with support for pagination modes (append, prepend, replace) and type-safe response parsing via typia; useLazyLoadingProps to conditionally apply eager or lazy loading attributes based on user preferences; useDropbox to dynamically load the Dropbox JavaScript SDK; usePersistentExternalScript for safely injecting external scripts that persist across component unmounts; and useScrollToElement to reliably scroll to DOM elements after they have been fully rendered using a double requestAnimationFrame pattern.

app/javascript/hooks · high confidence

New Sidekiq jobs to detect and alert on stranded buyers, negative balances, and stalled email blasts

This change introduces a suite of new Sidekiq background jobs that proactively detect operational issues and alert internal teams. Specifically, the system now scans for established buyers and subscribers stranded behind platform blocks, sellers with negative destination balances on Stripe, and email blasts or abandoned-cart sequences that have stalled without completing. It also detects discrepancies between seller dates of birth on Stripe versus internal records, and monitors for stale platform blocks holding established buyers. These jobs provide visibility into edge cases that previously required manual investigation or seller reports.

app/sidekiq · high confidence

New Tailwind-based UI component library

The application now uses a new set of React UI components (Alert, Avatar, Calendar, Card, Checkbox, CodeSnippet, ColorPicker, DefinitionList, Details, Fieldset, FormSection, InlineList, Input, InputGroup, Label, LinkButton, Menu, PageHeader, Pill, Placeholder, ProductCard, Radio, Range, Rows, Select, Sheet, StretchedLink, Switch, and Table) built with Tailwind CSS and Radix UI primitives. This replaces the previous SCSS-based styling, providing consistent, accessible, and themeable components for the interface.

app/javascript/components/ui · high confidence

New Tax Center page for viewing and managing tax documents

Users can now access a dedicated Tax Center page to view available tax documents, select specific tax years, and download forms. The page includes an FAQ section explaining 1099-K thresholds and fee deductions, and allows users to request transaction reports for informational purposes. This replaces the previous navigation structure with a new InertiaJS-based interface featuring tabs for Payouts and Taxes.

app/javascript/pages/TaxCenter · high confidence

New accounting and creator notification emails

Added a suite of new email templates for accounting and creator communications. Accounting mailers now include daily finance ledger reports, Stripe balance summaries, global sales tax summaries, and US states sales tax summaries, along with failure and backstop alerts for these scheduled jobs. Creator-facing mailers now notify sellers of direct affiliate removals, product-level refund policy changes and auto-enforced policies, chargeback evidence deadlines, and various payout issues including invalid account holder names, retry exhaustion, and permanent PayPal failures. Additional templates cover subscriber data exports, 1099-K transaction reports, and notifications for undeliverable webhooks or receipts.

app/views · high confidence

New checkout components and tests for Stripe Payment Element, gifting, and upsells

This change introduces the core React components and test suites for the new Stripe Payment Element checkout flow, including PaymentElementInput and PaymentForm, which handle card and wallet payments with seller theme support. It also adds the GiftForm component (with tests) to allow buyers to hide their identity from recipients, and new UpsellModal and CrossSellModal components (with tests) to present upgrade and cross-sell offers during checkout. Additionally, it includes the acknowledgedEmails utility and tests for persisting email typo dismissals, and the applePayRecurringPaymentRequest utility with tests to correctly configure Apple Pay merchant tokens for recurring memberships.

app/javascript/components/Checkout · high confidence

New compliance and payout sections on the Payments settings page

The Payments settings page now includes dedicated sections for Account Status, Beneficial Owners, and Legal Guardians, alongside updated Account Details and Bank Account forms. Users can now view their account verification status and compliance actions, manage beneficial owner details with country-specific ID validation, and, for sellers aged 13–17, add a legal guardian to enable payouts. The page also displays clearer guidance for restricted countries and handles Stripe-rejected account states with specific balance release information.

app/javascript/components/Settings/PaymentsPage · high confidence

New controllers for ACME challenges, AI agent dashboard, single-customer emails, churn analytics, and first-class pages

This change introduces a suite of new controllers in app/controllers that power several new seller-facing capabilities and infrastructure endpoints. Sellers can now manage first-class Pages (including a customizable profile home page) via PagesController, view churn analytics on the ChurnController dashboard, and access the conversational AI Agent tab through AgentController. The platform also adds infrastructure for domain verification (AcmeChallengesController, IndexnowKeysController), a dedicated endpoint for sending single-customer emails from the Sales page (SingleCustomerEmailsController), and a new Churn analytics view. Additionally, it establishes the Collaborators management UI (Collaborators::\* controllers), community chat features (Communities::\* controllers), and secure redirect handling (SecureRedirectController).

app/controllers · high confidence

New conversational Agent dashboard tab with eligibility gating and mobile layout fixes

A new Agent page has been added to the application, providing a conversational interface powered by Claude Opus 4.7 that supports streaming responses and follow-up suggestions. The implementation includes eligibility gating: if a user is not eligible, the chat interface is locked and displays a specific heading and explanation explaining why access is restricted. Additionally, the mobile layout has been fixed to ensure proper visibility of the composer and header on iOS devices, with the header hidden on small screens to prevent empty bars.

app/javascript/pages/Agent · high confidence

New customer detail page and updated audience statistics icons

A new CustomerDetailPage component has been introduced to provide a dedicated view for individual customer information, replacing the previous inline or server-rendered approach. Additionally, the AudienceQuickStats component has been updated to use Boxicons for its iconography, migrating from the legacy Icon component to ensure consistent styling and rendering of the follower statistics.

app/javascript/components/Audience · high confidence

New customer listing and detail pages

Added new Inertia.js page components for the Customers section: Index.tsx renders the customer list using the existing CustomersPage component, and Show.tsx renders the customer detail view using the CustomerDetailPage component. These pages serve as the entry points for viewing customer data in the application.

app/javascript/pages/Customers · high confidence

New daily finance event ledger and Stripe balance summary reports with improved refund accounting

Finance teams now have access to a new daily 'event-ledger' report that tracks immutable financial events (sales, refunds, disputes) by the day they occurred, ensuring daily sums aggregate exactly to monthly totals for better auditability. Additionally, a new monthly Stripe balance summary report is generated for all Antiwork entities (Gumroad, Flexile, Helper, Iffy), merging balance, activity, and payout data into a single CSV emailed to finance. Existing monthly reports have been updated to scope refund sums strictly to the reported month and to use 'effective' refunds, ensuring that reversed or failed refunds are correctly excluded from financial totals.

app/business/payments/reports · high confidence

New icons added to the Getting Started onboarding grid

The Getting Started onboarding grid now includes visual indicators for several new milestones and actions. New SVG icon components have been added to represent the CLI, customizing a profile, email blasts, the first follower, the first payout, the first product, the first sale, and making an account. These icons support a checked state to visually confirm completion of these specific onboarding steps.

app/javascript/components/icons · high confidence

New in-product support contact form and agent fallback note

Users can now submit support requests directly through a new modal form in the Help Center, which captures their email, issue category, and message, and includes a fallback link to email [e-mail redacted]. Additionally, a new note is displayed on surfaces where AI agents build or modify pages, offering a direct email link for users who prefer manual assistance or encounter issues with agent-generated content.

app/javascript/components/Support · high confidence

New invoice generation pages with payment selection and persistent form data

Users can now generate invoices through new Inertia-based pages (Confirm and New) that allow selecting specific membership payments from a list. The New invoice form retains entered details—such as business name and address—when switching between payments or after a successful download, ensuring a smoother experience. The form also supports country-aware business IDs (like VAT) and includes validation for required address fields.

app/javascript/pages/Purchases/Invoices · high confidence

New marketing and customization tools in the Product Share tab

The Product Edit Share tab now includes several new capabilities: an Abandoned Cart Email card that lets sellers preview and enable automated cart reminders; a Landing Page Editor that provides an AI prompt to generate custom HTML product pages; a Share Your Launch card for drafting and posting launch updates to social channels like X and email; and a Tag Selector that raises the product tag limit from 5 to 10. Additionally, the Taxonomy Editor now supports Structured Attributes (inferred and editable) to power Discover filters, and the Discover Fee Selector for boosting visibility has been removed.

app/javascript/components/ProductEdit/ShareTab · high confidence

New mobile Store Agent and expanded seller management APIs

This update introduces a conversational Store Agent for the mobile app, allowing sellers to chat with an AI assistant that can propose and execute store changes (like updating products or managing commissions) via a new \AgentController\ and an SSE streaming endpoint (\AgentStreamsController\). It also adds a comprehensive Sales API (\SalesController\) for paginated seller-side purchase management, including editing customer details, handling refunds, revoking access, and marking items as shipped. Additionally, sellers can now list and delete their own products via a new \ProductsController\, manage subscription cancellations, and update call URLs and license statuses through dedicated controllers. The mobile analytics endpoint now supports hourly data buckets and seller time zones, while the purchases search has been optimized to stop computing entitled creator posts, significantly improving response times.

app/controllers/api/mobile · high confidence

New multi-payout export feature and standardized payout data types

Sellers can now export multiple payout periods at once via a new 'Export all' popover in the Payouts section, allowing them to select specific years and individual payouts to download as CSV files. This feature is supported by a comprehensive update to the shared TypeScript types in the Payouts component index, which now explicitly defines bank account structures for numerous international formats (including specific handling for Gibraltar using Sort Code + Account Number) and standardizes the data shape for current payout statuses, ensuring consistent display of balances, skip reasons, and period details across the dashboard.

app/javascript/components/Payouts · high confidence

New public-facing documentation and help pages

The application now includes several new public pages: an API documentation page (Api) that lists endpoints for products, files, emails, workflows, and more; a Gumroad Ping documentation page (Ping) explaining webhook parameters and delivery guarantees; a Charge help page (Charge) explaining billing; a License Key Lookup page (LicenseKeyLookup); and a Widgets page (Widgets) for embedding products and subscribe forms. The Widgets page has been migrated to use Inertia.js and typia for type safety, and the API documentation page includes tests to verify the ordering of workflow endpoints.

app/javascript/pages/Public · high confidence

New visual assets for the About page

The About page now includes new illustrative graphics, specifically blog post circle icons and a 'make your road' graphic, to enhance the visual presentation of the company's story and content.

public · high confidence

OAuth device authorization flow and mobile app improvements

Users can now authorize applications on devices without a browser through the new OAuth device authorization flow, which includes dedicated controllers for handling device code generation and user approval. The OAuth authorization screen now supports a unified admin authorization path, allowing team members to optionally grant admin scopes via a checkbox when using the Gumroad CLI. Additionally, the mobile app login experience has been streamlined by skipping the standard authorize prompt for mobile clients, and OAuth application management has been migrated to an Inertia-based UI with improved error handling and reserved name validation for the Store Agent.

app/controllers/oauth · high confidence

Preview iframe now bridges product catalog requests

The CustomHtmlPreview component now acts as a bridge for the 'gumroad:products' message protocol, allowing untrusted HTML rendered in the preview iframe to request paginated product slices from the dashboard. This enables sellers to see accurate product listings in their page previews instead of the preview hanging indefinitely. The bridge validates offset and limit parameters, defaults the limit to the configured maximum if omitted, and ensures replies are matched to the correct request and document context.

app/javascript/components/Pages · high confidence

Product editor gains price insights, default discount codes, and touch-friendly cover management

Sellers now have a Price Checker widget in the Product Edit tab that compares their pricing against similar products on Gumroad, complete with a distribution chart and a checklist for match accuracy. A new Default Discount Code Selector allows automatic application of specific discount codes to products. The cover editor now supports touch devices by ensuring the remove button is tappable without triggering drag actions, and it includes a 10 MB upload size limit for images in the description editor. Additionally, the Pay What You Want (PWYW) toggle is now correctly handled for $0-base products with paid variants, allowing PWYW to coexist with priced versions while preventing invalid configurations.

app/javascript/components/ProductEdit/ProductTab · high confidence

Public wishlists now include structured data for SEO

Public wishlists now generate JSON-LD structured data (Schema.org ItemList) to improve search engine visibility. This change introduces a new \Wishlist::StructuredData\ concern that renders product details, including prices and URLs, for up to 20 items on the first page. The implementation handles edge cases such as missing prices or currencies to prevent rendering errors, ensuring that search engines can properly index the content of public wishlists.

app/models/concerns/wishlist · high confidence

Server-side storage for Store Agent conversations

The Store Agent's chat history is now persisted to the database instead of living only in the browser's React state. This means refreshing the page or switching devices no longer loses the conversation, and the chat history is recoverable and auditable via the new \ai\_conversations\ and \ai\_messages\ tables.

db · high confidence

Support passkey-based login via WebAuthn

Users can now sign in using a passkey (WebAuthn) in addition to traditional methods. This change introduces a new controller that handles the authentication ceremony, verifying the user's credential against stored public keys and signing them in while preserving their session state and cart data.

app/controllers/logins · high confidence

Removals

Removal of Admin Form component

The Admin Form component has been removed from the application. This component previously handled form submissions for admin actions, including loading states, confirmation prompts, and error alerting via the server alert component. Its deletion indicates that the specific admin UI features relying on this generic form handler are no longer present or have been replaced.

app/javascript/components/Admin · high confidence

Removal of Advanced Settings page components

The \AdvancedPage\ and \EditApplicationPage\ components within the Settings section have been removed from the codebase. This deletion eliminates the user interface for managing advanced configuration options, including custom domains, blocked customer emails, notification endpoints, application listings, and account deletion with balance forfeiture.

app/javascript/components/server-components/Settings/AdvancedPage · high confidence

Removal of AffiliateSignupForm component

The AffiliateSignupForm component, which previously handled the UI for managing affiliate links, individual product commissions, and the global Gumroad Affiliate Program settings, has been removed from the codebase. This deletion eliminates the client-side form logic for these specific affiliate configuration features.

app/javascript/components/AffiliatesDashboard · high confidence

Removal of CustomersPage component

The CustomersPage component, which previously handled the display and management of customer lists including filtering, sorting, and detailed customer actions, has been removed from the application. This change eliminates the legacy client-side implementation for the audience's customer overview, likely as part of a broader migration to server-rendered or alternative UI patterns for this section.

app/javascript/components/server-components/Audience · high confidence

Removal of CustomersPage download and filter popover components

The \DownloadPopover\ and \FilterPopover\ React components within the CustomersPage have been removed from the codebase. This deletion eliminates the client-side logic previously used to render the CSV export date-range picker and the filter content injection, indicating these UI elements are no longer served or managed by these specific server-component wrappers.

app/javascript/components/server-components/CustomersPage · high confidence

Removal of DisputeEvidencePage and ProductPage components

The DisputeEvidencePage and ProductPage components within the Purchase module have been deleted. This removes the client-side React implementations for the dispute evidence submission form and the product display page, indicating these views are no longer served or managed by these specific server-component files.

app/javascript/components/server-components/Purchase · high confidence

Removal of legacy Admin navigation component

The legacy Admin navigation component (Nav.tsx) has been removed from the application. This file previously rendered the main navigation framework for the admin interface, including links to Sidekiq and Flipper, and handled the user avatar popover with logout and impersonation controls. Its deletion indicates that this specific navigation implementation is no longer used, likely replaced by a new structure or migrated to a different styling approach as suggested by related commit messages.

app/javascript/components/server-components/Admin · high confidence

The \Footer\ and \Nav\ components previously located in the Home directory have been removed from the codebase. This deletion eliminates the standalone footer containing the Gumroad subscription form and social links, as well as the navigation bar that handled active state detection and mobile menu toggling for the home page, indicating these UI elements are no longer part of the current application structure.

app/javascript/components/Home · high confidence

Removal of legacy Public server components

The ChargePage and LicenseKeyPage components located in the server-components/Public directory have been removed. These files, which previously rendered specific support content using the LookupLayout wrapper, are no longer part of the application codebase, indicating a migration or consolidation of these public-facing support pages.

app/javascript/components/server-components/Public · high confidence

Removal of legacy server-rendered Profile pages

The legacy server-rendered components for the Profile area (CoffeePage, PostPage, ProductPage, SettingsPage, WishlistPage, and the main Profile index) have been removed from the codebase. These files, which previously handled rendering for creator profile sections, product purchases, posts, settings, and wishlists using inline styles and specific layout wrappers, are no longer present. This change eliminates the old server-component implementations for these profile-related views, likely as part of a broader migration to a different rendering strategy (such as Inertia or client-side routing) that handles these pages elsewhere.

app/javascript/components/server-components/Profile · high confidence

Removal of the WidgetsPage component

The \WidgetsPage\ component, which previously allowed users to generate and copy embed codes for product overlays and subscribe forms, has been removed from the application. This change eliminates the ability to manage these specific widget embeds directly through this page.

app/javascript/components/server-components/Developer · high confidence

Removal of the legacy Helper Tools API

The internal Helper Tools API endpoints (including user management, purchase operations, payouts, and webhooks) have been removed from the application. This change eliminates the \Api::Internal::Helper\ namespace and its associated authentication logic, effectively deprecating the previous integration method for support staff tools.

app/controllers/api/internal/helper · high confidence

Removed CheckoutDashboard Discounts and Form pages

The DiscountsPage and FormPage components within the CheckoutDashboard have been deleted. This removes the user-facing interfaces for managing discount codes and configuring the checkout form custom fields.

app/javascript/components/server-components/CheckoutDashboard · high confidence

Removed legacy React server components for Discover, Product, and Wishlist pages

The legacy ReactOnRails server components for the Discover, Product, and Wishlist pages have been removed from the codebase. This cleanup eliminates the \ProductPage\, \WishlistPage\, and the main \Discover\ index component (including its search reducer, carousel logic, and URL state management) which were previously registered via \serverComponentUtil\. These files are no longer part of the application's rendering pipeline.

app/javascript/components/server-components/Discover · high confidence

Removed legacy server-component wrappers for Product pages

The \CartItemsCountPage\, \IframePage\, and \ProductPage\ server-component wrappers in the Product area have been removed. These files previously handled specific rendering contexts (such as iframe communication and layout wrapping) and are no longer part of the codebase, indicating a shift away from this specific server-component implementation pattern for these product views.

app/javascript/components/server-components/Product · high confidence

Security

Fix widget host validation to prevent domain spoofing attacks

The widget's host validation logic has been corrected to use proper DNS label boundaries instead of simple string suffix matching. Previously, hosts like 'evil-gumroad.com' could pass validation because they ended with the trusted domain string; the new implementation ensures that only the exact domain or its legitimate subdomains are accepted, closing a security vulnerability where an attacker could register a similar domain to intercept widget messages. This change also normalizes fully-qualified domain names (trailing dots) and handles empty custom domains safely.

app/javascript/widget · high confidence

Behavioural changes

Accurate payout date projections and improved payout eligibility messaging

Sellers now see accurate projected payout dates that reflect the specific weekday each payout rail (e.g., UK bank, US bank, PayPal) is processed on, rather than a generic weekly cycle. The system also provides clearer, context-aware messaging for skipped payouts, distinguishing between admin and processor-initiated pauses, explaining terminal PayPal rejections, and handling specific cases like below-minimum balances and legal guardian requirements for minors. Additionally, the minimum payout threshold has been raised from $10 to $100, with a special $1 floor for permanently rejected Stripe accounts to ensure they can still receive their remaining balance.

app/business/payments/payouts · high confidence

Add status sorting to Upsells page

Users can now sort the list of upsells by their status. This is enabled by adding 'status' to the allowed sort keys and implementing the corresponding database ordering logic for the 'paused' attribute.

app/models/concerns/upsell · high confidence

The utility for generating Stripe transfer URLs has been updated so that links in the admin interface now point directly to the specific payout page instead of the general transfers list. This change constructs a deeper URL path including the Stripe workspace ID and, when applicable, the specific account context, ensuring admins land on the exact transaction details rather than a generic dashboard view.

app/business/payments/utilities · high confidence

Admin web UI removal and redirect updates

The admin web interface has been removed, leaving only the internal admin API and two specific entry points: user impersonation and Stripe dashboard redirection. Consequently, the impersonation flow now redirects users to the products page instead of the dashboard, and the unimpersonate action redirects to the root path. Additionally, the HelperActionsController, which previously handled impersonation and Stripe dashboard links, has been deleted, with its functionality consolidated into the BaseController.

app/controllers/admin · high confidence

Advanced Settings page modernized with new UI components and Inertia.js integration

The Advanced Settings page has been refactored to use the new FormSection, Fieldset, and Input UI components, replacing legacy HTML structures and CSS classes. All form submissions (OAuth applications, account deletion, ping endpoints, credit cards) now use Inertia.js router methods instead of manual fetch requests, and type checking has been switched from ts-safe-cast to typia. The Account Deletion section now clarifies that product files remain accessible to buyers who have already purchased them, and the Applications section allows deleting OAuth apps directly from the list.

app/javascript/components/Settings/AdvancedPage · high confidence

Analytics page receives a major UI and performance overhaul

The Analytics page has been rebuilt to improve performance, accessibility, and visual consistency. The sales chart is now loaded asynchronously to prevent blocking the initial page render, and a new error boundary ensures the rest of the page remains usable if the chart fails to load. The interface has been migrated to Tailwind CSS and modern UI components, including a new product selection popover with a sticky footer, standardized table layouts for locations and referrers, and accessible loading skeletons that replace generic spinners. Additionally, the sales chart now features a weighted end-of-day projection that accounts for the seller's historical sales patterns, and the layout now includes a dedicated Churn tab for eligible users.

app/javascript/components/Analytics · high confidence

Audience counts now served from Elasticsearch

Audience member counts are now retrieved from Elasticsearch instead of the database, ensuring that filtered and total audience sizes are consistent and come from the same data source. This change introduces a new \Searchable\ concern that maps audience data to an Elasticsearch index, supporting filters for active customers and minimum license uses. For filters requiring database joins (like minimum license uses), the system falls back to SQL to maintain accuracy, while other counts leverage Elasticsearch for performance.

_app/models/concerns/audience\member · high confidence

Authentication UI modernization and social provider updates

The authentication interface has been redesigned using Tailwind CSS, replacing the previous layout with a split-screen view featuring a new PageHeader and Logo component. Social authentication options have been updated: Facebook login has been removed, Apple login is now available in the mobile app, and brand icons have been switched to Boxicons. Additionally, Stripe signup is now conditionally disabled based on feature flags, and the Google OAuth redirect parameter has been corrected from 'referer' to 'origin'.

app/javascript/components/Authentication · high confidence

Blog pages migrated to Inertia.js with React components

The Gumroad Blog listing and single-post views have been rewritten as React components using Inertia.js, replacing the previous server-rendered or Sprockets-based approach. The new Index page displays posts in a responsive grid with dynamic text clamping and tag filtering, while the Show page renders rich-text content via TipTap and tracks view counts. This change introduces typia for runtime type validation and relies on the new shared BlogLayout component for consistent structure.

app/javascript/pages/GumroadBlog · high confidence

Build pipeline overhaul: faster builds, smarter deploys, and automatic preview apps

The CI/CD pipeline has been significantly restructured to improve speed, reliability, and developer feedback. Docker image builds now use BuildKit with registry caching against ECR, drastically reducing build times by persisting layers across agents, and the web image is pushed directly from the builder to skip local export overhead. Production deploys are now skipped automatically if a commit changes only non-shipping files (like specs or docs), and a new content-addressed S3 cache for preview-app assets skips the slow asset compilation step when source inputs haven't changed. Additionally, preview environments are now generated for every branch by default (removing the previous opt-in label requirement) and provisioned in parallel with asset compilation to reduce overall pipeline duration.

.buildkite/scripts · high confidence

Bundle edit UI modernized with Inertia.js and Tailwind CSS

The Bundle Edit interface has been migrated from a legacy React pattern to Inertia.js for navigation and Tailwind CSS for styling. This update replaces custom layout and alert components with shared UI primitives (Alert, CartItemList, LinkButton), standardizes the visual design of product items and selectors, and adds creation date and URL display to search results. The change also improves the user experience by replacing page reloads with client-side routing and updating the 'Update Purchases' workflow to use Inertia's post requests with scroll preservation.

app/javascript/components/BundleEdit/ContentTab · high confidence

Bundle editor migrated to Inertia.js with typia validation and Boxicons

The bundle editing interface (Content, Product, and Share tabs) has been rewritten using Inertia.js for client-side navigation and state management, replacing the previous implementation. This change introduces typia for runtime type assertion of page props to ensure data integrity, and migrates all iconography to the Boxicons library. Users will experience smoother, faster transitions between editing sections without full page reloads, while the underlying data handling is now strictly typed to prevent errors.

app/javascript/pages/Bundles · high confidence

Bundle editor refactored to use Inertia.js and Tailwind CSS

The BundleEdit component has been migrated from a React Router-based context pattern to an Inertia.js-driven layout, replacing the local state management with explicit props and a new tab-based navigation system. This change includes a structural refactor of the pricing logic into a shared utility module, updates to the product preview to support new fields like TikTok Pixel integration and sold-out variant hiding, and a visual overhaul to align with the new Tailwind CSS styling and Boxicons.

app/javascript/components/BundleEdit · high confidence

Checkout Dashboard UI and behavior updates

The Checkout Dashboard now uses Inertia's useForm hook for the checkout form, replacing custom API calls, and migrates styling to Tailwind classes. Sellers can now disable gifting, which immediately hides the gift section in the checkout preview without requiring a save. The PayPal connection section now warns sellers before disconnecting if it removes their only payout rail. The Discounts page no longer crashes when the search query contains a percent sign. The Upsells page adds pause/resume functionality and allows sorting by status.

app/javascript/components/CheckoutDashboard · high confidence

Checkout form page migrated to Inertia.js

The checkout form page (Show.tsx) has been rewritten to use Inertia.js for rendering, replacing the previous implementation. The component now utilizes \usePage\ to retrieve necessary props such as pages, user, cart items, products, and PayPal connection details, and passes them to the existing \FormPage\ component.

app/javascript/pages/Checkout/Form · high confidence

Checkout management UI migrated to Inertia and enhanced with advanced discount scoping

The checkout management interface now uses Inertia for rendering pages (Discounts, Upsells, Form), replacing previous direct JSON or partial renders with server-side props passed to Inertia components. This migration includes adding meta tags for SEO and handling form updates via redirects with Inertia error injection. Additionally, discount codes now support more granular scoping, including exclusions ('all products except selected'), specific option/variant restrictions, ownership-based tiers, and existing-customer limits. Upsell creation and updates are now handled by a dedicated service object, and the controller now includes a new returns controller to handle Stripe redirect post-payment flows, displaying processing states or redirecting to success/failure pages.

app/controllers/checkout · high confidence

Clarified OAuth permissions in Authorized Applications list

The Authorized Applications settings page now displays human-readable descriptions for each OAuth scope granted to connected apps (such as 'Full access to your account' or 'See your sales data'), replacing the previous raw scope names. This change helps users understand exactly what data and actions each authorized application can access before deciding to revoke access.

app/javascript/pages/Settings/AuthorizedApplications · high confidence

Collaborators interface migrated to Inertia and React

The Collaborators management interface has been rebuilt using Inertia.js and React, replacing the previous server-rendered implementation. This change introduces new React components for the collaborator form, layout, and details sheet, enabling a more dynamic user experience. The form now handles product selection, commission validation, and email input with client-side feedback, while the details sheet provides a modal view of collaborator information and associated products.

app/javascript/components/Collaborators · high confidence

Collaborators pages migrated to Inertia.js and React

The Collaborators interface (Index, New, Edit, and Incomings pages) has been rewritten as React components using Inertia.js for navigation and state management. This migration replaces the previous server-rendered approach, introducing client-side form handling via \useForm\ and prop validation with \typia\. The UI now utilizes Tailwind CSS for styling and Boxicons for iconography, while retaining the existing \CollaboratorForm\ component and layout structure.

app/javascript/pages/Collaborators · high confidence

Collaborators tables use Inertia partial reloads and improved click targets

The Products and Memberships tables in the Collaborators section now use Inertia partial reloads for pagination, replacing the previous custom async request handling. This change also improves the user experience by making the entire product name cell clickable via a stretched link, addressing reports that tapping near the name did nothing, and adds RTL support for product names.

app/javascript/components/ProductsPage/Collabs · high confidence

Communities page chat UI components removed

The client-side React components that previously rendered the community chat interface—including the message list, individual message cards, input field, and sidebar list—have been deleted from the CommunitiesPage. This removes the local rendering logic for chat messages, user avatars, date separators, and the scroll-to-bottom button, indicating the chat view is now handled by a different implementation (likely server-side or a different client architecture).

app/javascript/components/server-components/CommunitiesPage · high confidence

Communities page migrated to Inertia with TypeScript and Boxicons

The Communities Index page has been rewritten as a new TypeScript component using Inertia.js for navigation and state management, replacing the previous implementation. This change introduces runtime type validation via typia for page props, updates the icon library to Boxicons, and implements a robust chat scroll mechanism using MutationObservers to preserve scroll position during message updates.

app/javascript/pages/Communities · high confidence

Communities page migrated to Inertia with new chat UI components

The Communities page has been migrated to Inertia, introducing a new chat interface built from scratch. This includes components for displaying chat messages (ChatMessage, ChatMessageList) with features like date separators, unread indicators, and auto-scrolling, as well as a message input component (ChatMessageInput) and a community list sidebar (CommunityList). The implementation uses Boxicons for icons and Tailwind CSS for styling, replacing the previous legacy button props and SCSS forms. A new hook (useCommunities) manages state using typia for type assertion, and the UI now supports editing and deleting messages, with visual feedback for unread counts and community selection.

app/javascript/components/Communities · high confidence

This change introduces a new \.claude/settings.json\ file that explicitly defines an allowlist of permitted Bash commands (such as git, docker, rails, and npm) and file operations (Read, Write, Edit) for the Claude Code agent, ensuring it can perform necessary development tasks securely. Additionally, it establishes symbolic links in \.claude/skills/\ for various project-specific workflows (including commit, review-pr, and create-issue), pointing to the shared skill definitions located in the \.agents/skills/\ directory to make these capabilities available within the Claude Code context.

.claude · high confidence

Creators can now create brand accounts from the account switcher with email confirmation and payout setup options

Creators can now spin up new 'brand' accounts directly from the account switcher, which are real Gumroad accounts with their own email, username, and brand name. This feature requires email confirmation before creation and optionally allows carrying over existing payout setup. Additionally, deleted sellers are now hidden from the account switcher, and all seller controllers now enforce account email confirmation before allowing actions.

app/controllers/sellers · high confidence

Custom field inputs now require purchase token and use shared UI components

The CustomField components for file and text inputs now require the buyer's download token when submitting data, ensuring that only authorized purchases can write custom fields. Additionally, the visual presentation of these inputs has been updated to use the application's shared UI library (such as Card, Rows, Input, and Placeholder) instead of legacy SCSS-based styling, resulting in a consistent look and feel across the download page.

app/javascript/components/Download/CustomField · high confidence

Custom page styles now support gradient directions and margin-auto utilities

The build script for custom product landing pages has been updated to include Tailwind utilities for gradient direction (e.g., \bg-linear-to-r\) and \margin-auto\ (e.g., \mx-auto\). This ensures that gradient-based headlines and centered layout patterns compile correctly in custom pages, preventing previously broken styles from rendering as empty or invisible elements.

scripts · high confidence

Developer dashboard UI modernization and new Analytics tab

The Developer dashboard has been updated with a new layout featuring a shared navigation header and footer, replacing the previous standalone header. The interface now uses a unified design system, migrating custom form elements (fieldsets, inputs, selects, textareas) and buttons to shared UI components styled with Tailwind CSS. Additionally, a new 'Analytics' tab has been added to the product selection interface, allowing users to count views from self-hosted pages, and the existing 'Embed' and 'Modal Overlay' tabs have been restyled with new icons.

app/javascript/components/Developer · high confidence

Discover page migrated to Inertia with new UI components

The Discover page has been rewritten as a new Inertia-based React component (Index.tsx), replacing the previous implementation. This change introduces a modernized user interface using Tailwind CSS for styling, Boxicons for iconography, and a new Skeleton component for loading states. The page now features a scrollable carousel for featured products, a Black Friday banner with live stats, and structured SEO title generation. It also integrates recently viewed items and recommended wishlists, providing a more dynamic and visually consistent browsing experience.

app/javascript/pages/Discover · high confidence

Dispute evidence submission now holds responses until the deadline and supports multiple file uploads

Sellers can now upload multiple evidence files and revise their dispute response at any time before the deadline, with the system holding the submission until the due date to prevent premature processing. The interface enforces a one-shot submit mechanism that disables the save button while uploads are in progress, ensuring all selected files are included in the final packet, and restores previously saved radio selections and text fields so sellers can continue editing their answers without losing context.

app/javascript/pages/Purchases/DisputeEvidence · high confidence

Download page legacy components removed

The DownloadPage component area has been refactored by removing the legacy React components: AudioPlayerContainer, Layout, WithContent, and WithoutContent. This cleanup eliminates the previous implementation of the audio player, page layout, content rendering logic, and access-denial states (such as inactive membership or expired rental messages) from this specific location, indicating a migration to a different architectural approach for the download page.

app/javascript/components/server-components/DownloadPage · high confidence

Elasticsearch index names now support environment-specific suffixes

The Elasticsearch index names for balances and installments are now dynamically constructed by appending an environment-specific suffix (via the ES\_INDEX\_SUFFIX environment variable) to the base index names. This allows multiple isolated development or testing environments to use separate Elasticsearch indices without name collisions, while maintaining backward compatibility when the suffix is empty.

app/models/concerns/balance, app/models/concerns/installment · high confidence

Emails page migrated to React Router

The Emails page has been migrated from a server-component rendering model to a client-side React Router implementation. This change replaces the previous routing and data-fetching logic with \react-router-dom\ hooks (\useLoaderData\, \Link\) and route definitions, enabling client-side navigation between the Drafts, Published, and Scheduled tabs without full page reloads.

app/javascript/components/server-components/EmailsPage · high confidence

Enforce purchase authorization for Discord integration actions

The Discord integration now strictly verifies that a user is a valid, entitled purchaser before allowing them to join or leave the Discord server. This change introduces a new authorization check that ensures access is granted only to signed-in users who own the product or those presenting a valid download token, preventing unauthorized access via external IDs alone. Additionally, the controller now handles unexpected non-JSON responses from the Discord OAuth flow and catches JSON parsing errors to prevent unhandled exceptions.

app/controllers/integrations · high confidence

Enhanced X (Twitter) connection management and TikTok support in Social Settings

The Social Connections settings page now supports TikTok as a new connectable provider. For X (Twitter), the interface allows sellers to reconnect their account without first disconnecting it, and explicitly warns users if their current token lacks write permissions needed for posting launch posts. The disconnect action for X is now protected by a confirmation dialog that explains the consequences, including the potential loss of sign-in capability.

app/javascript/pages/Settings/SocialConnections · high confidence

Enhanced compliance handling for Stripe and PayPal merchant onboarding

This change introduces robust support for beneficial owners and legal guardians in Stripe onboarding, including new managers to sync guardian data for under-18 sellers and validate complex beneficial owner requirements (such as Japanese kana fields and Colombian ID formats). It also improves PayPal integration by blocking ineligible countries, validating OAuth grants against specific partners, and providing clearer error messages when accounts cannot receive payments. Additionally, the system now maps US business types to Stripe structures, syncs account holder names for specific countries, and normalizes compliance fields like nationality across both payment providers.

_app/business/payments/merchant\registration · high confidence

Enhanced currency handling, payout transparency, and infrastructure updates

Buyers now see prices in their local currency with improved reliability: exchange rates are cached locally to prevent failures when Redis is unavailable, and the system gracefully degrades to the seller's price if a rate is missing. The Payouts dashboard provides greater transparency by showing the specific reason for skipped payouts (such as below-minimum balance), displaying accurate skip dates, and accounting for chargeback reserves in the payout amount. Additionally, the platform has migrated from S3 to MinIO for local development and test environments, replaced the legacy Shakapacker asset pipeline with Vite, and updated the OAuth scope descriptions to clarify permissions for creators.

app/helpers · high confidence

Enhanced download page layout, media playback, and native app integration

The download page now supports per-folder expansion settings, allowing sellers to control whether folders start open or collapsed, with single-folder pages automatically expanding. Media playback has been improved with video frame styling that respects aspect ratios and native app resume support, passing saved playback positions to iOS, Android, and React Native webviews. The UI has been modernized with Tailwind CSS, Boxicons, and new component patterns like LinkButton and Rows, while the 'Open in app' popup now correctly applies store badge colors. Rich content links now support license key substitution and purchase ID appending for Gumroad posts.

app/javascript/components/Download · high confidence

Enhanced error tracking for processor rejections and FX quote invalidation

The payment charging error handling now captures specific processor rejection reasons, allowing the system to record why a purchase failed (e.g., Stripe error codes or PayPal rejection reasons) rather than leaving the reason blank. Additionally, a new error type has been introduced to handle cases where a locked foreign exchange quote expires or drifts beyond tolerance during checkout, ensuring the user is prompted to re-quote instead of attempting to charge an invalid amount.

app/business/payments/charging/errors · high confidence

Enhanced payment tracking, mandate support, and refund reliability

This update improves payment accuracy and reliability by recording the specific Stripe payment method type (e.g., UPI, iDEAL) on purchases for better volume measurement, and introducing support for Indian e-mandates to handle recurring card charges correctly. It also adds new charge event types to track PaymentIntent success/processing states and failed bank-transfer refunds (iDEAL, Bancontact, ACH), ensuring the system reflects asynchronous refund outcomes accurately. Additionally, the charging infrastructure now supports processor-specific amounts and FX quotes, and fixes a serialization bug in FlowOfFunds that previously misspelled the currency key.

app/business/payments/charging · high confidence

Enhanced public lookup forms with year/month scoping and improved UX

The public charge and license-key lookup forms now allow users to scope their search by purchase year and month, improving the accuracy of results. The interface has been updated to use Tailwind CSS and Boxicons for a modern look, and the layout now offers receipt recovery even on non-licensed product pages. Additionally, the page automatically scrolls to the result message upon completion, and separate loading states are provided for card and PayPal lookups to prevent double-submission issues.

app/javascript/components/Public · high confidence

Enhanced purchase risk controls, refund logic, and review identity options

This update introduces stricter fraud prevention by screening buyer IPs against platform blocks (excluding seller IPs to prevent false positives) and enforcing a chargeback grace period that groups related disputes. Refund handling is significantly improved: refunds are now blocked during active disputes, team-member refunds require a reason and notify the creator via email, and buyer-presentment refunds correctly calculate amounts in the buyer's local currency. Additionally, buyers can now choose to publish reviews as Anonymous or with their account identity, and video reviews are supported.

app/modules/purchase · high confidence

Exclude blocked countries from shipping destination options

The shipping destination dropdown now filters out countries flagged as blocked by the compliance module. Previously, all countries returned by the compliance list were included; the code now explicitly rejects any country identified as blocked before merging it into the available options, ensuring users cannot select restricted destinations.

_app/modules/shipping\destination · high confidence

Expanded TypeScript type definitions for new features and UI updates

This change introduces a comprehensive set of new TypeScript type definitions and declaration files to support recent product capabilities and infrastructure updates. It adds types for domain settings, UTM link management, and complex workflow structures (including installments and abandoned cart logic), as well as detailed payment and compliance models for Stripe Connect (handling SSN, nationality, and regional address formats). It also includes type declarations for new third-party integrations like TikTok Pixel and EPUB.js, updates CSS variable definitions to reflect new Tailwind-based theming, and adds support for new asset formats (WebP) and HTML attributes (fetchpriority, scroll-region).

app/javascript/types · high confidence

Expanded email previews and updated notification templates

This update significantly expands the available email previews in the development environment, adding new templates for admin chargebacks, internal notifications (payments, risk, migrations, awards, VAT), affiliate removals, and various seller notifications including Stripe balance summaries, PayPal payout failures, undeliverable subscriptions, and refund policy changes. It also introduces new buyer-facing previews for presentment currency refunds, partial refunds, and file-ready notifications. Additionally, the preview infrastructure has been updated to use the configured AWS S3 endpoint for file URLs and switched CSV generation to a safe format to prevent formula injection.

_lib/mailer\previews · high confidence

Expanded payment, discount, and profile capabilities in parser types

The parser definitions in app/javascript/parsers have been updated to support new product and account features. Payment handling now includes UPI as a card type and allows expiration dates to be null. Discount logic has been enhanced to support tiered percentage discounts, fixed-amount discounts that apply once per cart, and exclusion scoping for specific products or options. Product listings now display buyer-local currency prices, seller verification status, and original prices. Creator profiles support YouTube channel linking, CAPTCHA requirements for unreviewed sellers, hidden subscribe forms, and reputation summaries. Additionally, new settings pages for billing and social connections have been added, and TikTok Pixel integration is now supported in analytics data.

app/javascript/parsers · high confidence

Expanded payout failure classification and seller messaging

The system now distinguishes a wider range of payout failure scenarios to provide clearer feedback and more accurate retry logic. New failure reasons include currency mismatches (Stripe destination currency mismatch, below minimums, intervention required), processor issues (rate limits, unavailability), and account status changes (retired accounts, negative destination ledgers). For PayPal specifically, the system now explicitly handles and explains rejections such as locked accounts (3015), unsupported countries (3148), and currency restrictions (14159), determining which are retryable versus terminal. Transient processor errors are now excluded from the consecutive failure count that pauses sellers, while internal reconciliation failures (like negative ledgers) are flagged to prevent automatic retries that could duplicate payments or confuse sellers.

app/models/concerns/payment · high confidence

Expanded permissions and new policy scaffolding for seller settings and storefront features

This change introduces a comprehensive set of new Pundit policies and refines existing ones to support new seller capabilities and tighten access control. New policies are added for Churn analytics, Gumroad Blog posts, Marketing actions, Custom Pages, Product Review Videos, Direct Affiliates, Billing, Passkeys, Social Connections, and TOTP (2FA), defining who can view or manage these specific areas. Existing policies are updated to permit new attributes and actions: product editing now allows custom HTML, currency changes, hiding sold-out variants, ISBN storage, and refund period configuration; checkout forms can now toggle ACH payments, gifting, and PayPal card funding; and upsells can be paused. Access for team admins is broadened in several areas, including the ability to update payout settings and manage team invitations, while identity verification remains owner-only. Additionally, feature flags for UTM links and reviews are removed in favor of direct role-based access, and the community feature is restricted to accessible communities only.

app/policies · high confidence

The UtmLinkForm now clears validation errors only for the specific field being edited, rather than wiping all form errors at once. This change resolves a race condition where editing one field would inadvertently clear pending validation errors on other fields, ensuring that users see accurate, persistent error states for unaddressed issues during form submission.

app/javascript/components/UtmLinks · high confidence

Followers pages migrated to Inertia.js for SPA navigation

The Followers section (Index, Cancel, and FromEmbedForm pages) has been converted from a traditional API-based or server-rendered approach to use Inertia.js. This change enables smoother, single-page application-style navigation without full page reloads when managing subscribers, viewing cancellation confirmations, or handling embed-based subscription flows. Users will experience faster interactions and preserved scroll state during these operations.

app/javascript/pages/Followers · high confidence

Graceful handling of team invitation rate limits

The team invitation flow now catches HTTP 429 rate-limit errors and returns the server's specific error message to the user interface, ensuring sellers understand why an invitation was refused (e.g., exceeding the per-account limit). Previously, such errors would likely have been treated as generic failures. This change also replaces the \ts-safe-cast\ library with \typia\ for runtime type assertion and removes the unused \fetchMemberInfos\ function.

app/javascript/data/settings · high confidence

GumroadRuntimeError now exposes the original underlying error

The GumroadRuntimeError class now stores and exposes the original underlying error (such as a Stripe::InvalidRequestError) via a new \original\_error\ attribute. This allows error handling code to access specific details like the processor's error code for debugging purposes when a runtime error occurs.

lib/errors · high confidence

Handle SMTP fatal errors in mailers

The mailer error handling now catches Net::SMTPFatalError in addition to authentication and syntax errors, ensuring that fatal SMTP responses (such as 550 errors) are treated as permanent failures and logged appropriately rather than causing unhandled exceptions.

app/mailers/concerns · high confidence

Hardened team invitation sending and acceptance

Team invitations are now subject to stricter validation and rate limiting to prevent abuse and ensure data integrity. Senders must have an active account and are capped by a new throttle system that returns specific error messages and retry-after headers when limits are exceeded. The invitation acceptance flow has been updated to reject links from inactive sellers, uses database locking to prevent race conditions during membership creation, and validates the recipient's email format before resending. These changes ensure that invitations cannot be sent by suspended accounts and that the acceptance process is atomic and secure.

app/controllers/settings/team · high confidence

Help Center layout now offers email support and a contact modal

The Help Center layout component has been updated to replace the previous support ticket UI with a mailto-based email support link when the search button is not displayed, alongside a new 'Contact support' button that opens a modal for direct assistance. This change also integrates Boxicons for the search icon and utilizes Inertia.js for navigation, providing users with immediate access to support via email or a dedicated contact form.

app/javascript/pages/HelpCenter · high confidence

Help Center migration to Inertia.js with structured contact support

The Help Center has been rebuilt using Inertia.js, replacing the previous server-rendered views with client-side rendered components for articles, categories, and the contact form. This change introduces a new in-app contact form that validates input and asynchronously sends emails via ActiveJob, while preserving legacy URL compatibility by permanently redirecting old .html suffixed paths and specific broken article links (such as the jobs page) to their canonical locations. Additionally, comprehensive SEO metadata (Open Graph, Twitter Cards, canonical tags) is now automatically applied to all Help Center pages to improve link previews and search engine indexing.

_app/controllers/help\center · high confidence

Help center articles now use Inertia.js for navigation and support deep-linking to specific sections

The Help Center's article listing and detail pages have been rewritten as React components using Inertia.js, replacing the previous server-rendered approach to enable faster, client-side navigation between articles. This change introduces a robust internal link interceptor that preserves URL fragments (including browser text directives) when jumping between sections of different articles, ensuring users land exactly where they clicked rather than at the top of the destination page. The article index page also features a new client-side search filter that highlights matching terms in article titles.

app/javascript/pages/HelpCenter/Articles · high confidence

Help center content is now managed via YAML data files

The help center's content structure has been refactored to use YAML data files (\articles.yml\ and \categories.yml\) backed by \ActiveYaml::Base\ models. This change allows help articles and their categories to be defined and maintained as data rather than code, simplifying how support documentation is organized and updated without requiring code deployments for content changes.

_app/models/help\center · high confidence

Improved Buildkite pre-command hook with resource cleanup and ECR login error handling

The Buildkite pre-command hook now proactively frees up disk space by pruning unused Docker containers, volumes, networks, images, and builders before the build step begins. Additionally, the Docker login to Amazon ECR is now wrapped in error handling; if the login fails, the hook logs the failure and exits immediately, preventing subsequent build steps from running with invalid credentials.

.buildkite/hooks · high confidence

Improved PayPal dispute handling, refund accuracy, and logging security

The PayPal payment processor now handles dispute resolutions more robustly by recognizing buyer-favorable and undecided outcomes, preventing incorrect 'lost' status assignments when PayPal webhooks lack a clear decision. Refund processing has been hardened to preserve exact processor fees, validate multi-currency amounts safely using BigDecimal, and skip automatic refunds if webhook data is incomplete or invalid, with errors reported via the new ErrorNotifier abstraction. Additionally, sensitive data in external API request logs is now redacted to protect merchant credentials, and unused API endpoints and constants have been cleaned up.

app/business/payments/charging/implementations/paypal · high confidence

Improved PayPal payout validation and error transparency

The PayPal payout processor now enforces stricter validation rules, explicitly blocking instant payouts and checking against a specific list of countries where PayPal accounts can receive funds. It also introduces logic to permanently pause payouts to addresses that have been refused by PayPal for unfixable reasons (such as unsupported receiving countries), while ensuring sellers see a clear explanation for the block. Additionally, internal diagnostic notes regarding these validation failures are now hidden from the seller's Payouts dashboard to reduce noise.

app/business/payments/payouts/processor/paypal · high confidence

Improved accessibility for seller-chosen accent colors

The system now uses WCAG contrast calculations instead of HSL lightness to determine whether text on a seller's chosen accent color should be black or white. This ensures that all seller-selected colors meet the WCAG AA minimum contrast ratio, preventing issues like black text on bright green backgrounds or low-contrast text on saturated reds.

app/javascript/utils · high confidence

Improved balance visibility and transfer reliability

The system now accounts for pending (settling) Stripe funds when calculating available balances for external payouts, ensuring that upcoming payouts are not understated due to temporary negative pending balances. Additionally, internal creator transfers now support idempotency keys to prevent duplicate processing, and transfer logging references have been updated from Slack to generic chat rooms.

app/business/payments/transfers · high confidence

Improved character limit feedback for custom receipt fields

The Custom message and Button text inputs in the Receipt tab now display a dynamic character count (e.g., "120 of 500 characters used") instead of a static limit. This change clarifies how much text has been entered and why input might be cut off, while also associating the limit description with the fields for better screen reader accessibility.

app/javascript/components/ProductEdit/ReceiptTab · high confidence

Improved comment section UX and styling

The PostCommentsSection now clears the input field after posting a comment and closes the edit form after a successful update, preventing confusion with stale text. Additionally, deleting a comment with replies now correctly updates the total comment count by accounting for all deleted IDs, and the section's layout has been migrated to Tailwind CSS classes for consistent styling.

app/javascript/components/Post · high confidence

Improved cover sizing and accessibility for product media

Product covers now adapt their frame shape to the aspect ratio of the currently active cover rather than the first one, preventing landscape covers from being squeezed into 16:9 frames. Portrait covers are capped at a maximum height to keep the buy box visible, while landscape and square covers remain uncapped. Video covers now display a poster frame instead of a black idle screen, and the player is sized responsively using the video's native aspect ratio. Image covers include an alt attribute derived from the product name for better accessibility, and navigation arrows are now visible icons that appear on hover.

app/javascript/components/Product/Covers · high confidence

Improved email delivery reliability and new notification jobs

The application now uses a custom \MailDeliveryJob\ to handle transient SMTP failures (timeouts and server busy errors) by retrying quietly with exponential backoff, which prevents Sentry from being flooded with alerts for errors that resolve on retry. Additionally, two new jobs have been introduced: \SendMembershipPriceUpdateEmailJob\ to reliably send membership price change notifications with retry logic, and \SubscriptionCancellationEmailJob\ to ensure cancellation emails are sent only after the transaction commits, preventing duplicate or lost notifications.

app/jobs · high confidence

Improved email resend reliability and audience count accuracy

Sellers can now resend emails to non-openers with a dedicated controller that enforces a 24-hour throttle and a three-send limit, while using a strict 300ms time budget for the recipient count preview to prevent request timeouts on large audiences. The system also allows resuming incomplete email sends manually, ensuring only one sender runs at a time via Redis locking. Additionally, audience counts are now served from a centralized engine for consistency, and recipient counts support new filters for active customers only and minimum license uses.

app/controllers/api/internal/installments · high confidence

Improved file upload reliability and virtualized performance in the Content editor

Sellers now experience a more stable and responsive product content editor. The editor prevents cancelled or failed file uploads from blocking saves and correctly displays upload failures so sellers can retry. To handle products with many files, the editor now uses virtualized scrolling, rendering only visible file rows to maintain performance. Additionally, a new nudge encourages sellers to add an EPUB version alongside PDFs for better mobile reading, and file embeds copied from other products are now correctly mapped to the seller's existing files.

app/javascript/components/ProductEdit/ContentTab · high confidence

Improved handling of client-side payment actions and FX quote errors

The Stripe error handler now raises a specific error for invalid foreign-exchange quotes, allowing for more precise failure reporting. Additionally, the intent status logic has been expanded to recognize next-action types for Pix, UPI, Alipay, and Cash App as client-handled, preventing false alerts when buyers return to the checkout page mid-flow. It also correctly identifies client-side redirects for methods like Klarna and iDEAL, ensuring that abandoned redirects on these specific payment methods do not trigger unnecessary alerts.

app/business/payments/charging/implementations/stripe/helpers · high confidence

Improved navigation reliability and EPUB reader safety limits

This update patches two underlying libraries to improve stability and security. First, it patches @inertiajs/core to fix a navigation bug where clicking a link would silently fail if the background prefetch request failed; the new behavior ensures the click always triggers a real navigation as a fallback. Second, it patches epubjs to enforce strict memory and size limits (e.g., 32MB archive size, 10,000 entry count) when opening EPUB files in the browser, preventing potential crashes or denial-of-service from malformed or excessively large archives.

patches · high confidence

Improved pricing validation, currency handling, and membership wording

Users now see clearer wording for fixed-length memberships that only charge once (e.g., a 12-month membership billed yearly), avoiding confusing auto-renewal language. The system prevents 404 errors and invalid states when entering very large price values by enforcing a 32-bit integer cap and validating against supported currencies. Additionally, stale price rows are automatically retired when a product's display currency changes, ensuring consistent pricing display and search indexing.

_app/modules/base\price · high confidence

Improved receipt delivery reliability and routing logic

The system now supports sending separate receipts for multi-item orders and ensures that resend operations preserve delivery history instead of overwriting it. It also fixes issues where receipts were lost for specific email providers (web.de, GMX, mail.com) by introducing logic to detect Resend SMTP settings and map them to equivalent SendGrid credentials. Additionally, receipt record ID determination has been updated to handle split charge receipts and normalize lineage for better deduplication.

_app/models/mailer\info · high confidence

Improved reliability and accuracy for refunds, disputes, and receipts

This update enhances the reliability of financial event processing and the accuracy of buyer-facing information. Refund handling now correctly processes partial refunds in the buyer's presentment currency, prevents duplicate refund records through stricter locking and deduplication, and automatically reverses balance debits when asynchronous bank refunds fail. Dispute workflows are now replay-safe, ensuring that side effects like balance decrements and notifications are not lost if a webhook delivery crashes mid-process, and dispute amounts are displayed in the buyer's local currency alongside the canonical USD amount for clarity. Additionally, receipt generation logic has been simplified and hardened to correctly handle memberless bundles and ensure receipts render from the appropriate purchase grain.

app/models/concerns/charge · high confidence

Improved reliability and data accuracy for affiliate product eligibility checks

The Global Affiliates product eligibility controller now handles invalid URLs more robustly by catching additional URI parsing errors, preventing server crashes during validation. Additionally, the logic for fetching product data has been updated to verify the API version and permalink presence, and it now retrieves the 'recommendable' status directly from the product model rather than relying on the public JSON endpoint, ensuring that affiliate-specific eligibility flags are accurately reflected in the response.

_app/controllers/global\affiliates · high confidence

Improved reliability for affiliate and follower audience member updates

The system now handles database contention more gracefully when updating audience member records for affiliates and followers. Changes to \Affiliate::AudienceMember\ and \Follower::AudienceMember\ introduce retry logic for \RecordNotUnique\ errors during upserts, ensuring that race conditions do not cause checkout failures or data loss. Additionally, \LockWaitTimeout\ errors are now caught, logged, and trigger a background job to refresh the audience member details asynchronously, preventing immediate user-facing errors. The email validation logic in these concerns has also been updated to use a dedicated \EmailFormatValidator\ instead of a direct regex match.

app/models/concerns/affiliate · high confidence

Improved reliability of the Store Agent chat stream and recovery

The Store Agent chat now handles interrupted server-sent event (SSE) streams more gracefully. If a stream breaks mid-reply, the client automatically reconciles the partial content with the server-persisted turn, ensuring users see the complete agent response rather than a truncated message or an error. The chat also correctly manages late-arriving suggestions and proposal confirmations, preventing stale UI states or duplicate actions when streams settle out of order. Additionally, the component includes robust handling for rate limits and stalled connections, providing clearer feedback to users when actions are blocked or when the agent is unavailable.

app/javascript/components/Agent · high confidence

Inertia app shell and layout infrastructure with prefetch reliability fix

This change introduces the core Inertia.js application wrapper and layout system, establishing global providers for design settings, domain configuration, user agent detection, and feature flags, alongside dedicated layouts for public, logged-in, and standalone contexts that handle flash messages and meta tags. It also includes a regression test ensuring that failed prefetch requests do not silently block subsequent user navigation, guaranteeing that clicking a link while a background prefetch is in flight still results in a successful page load.

app/javascript/inertia · high confidence

Introduce 'Recently Viewed' section and migrate Discover search to Inertia

The Discover page now includes a 'Recently Viewed' product row, allowing users to clear their history per identity (signed-in user or anonymous browser GUID) without affecting other identities. The search experience has been migrated to Inertia, replacing client-side fetches with server-side rendering for autocomplete results, which improves reliability and enables lazy loading for off-screen images. Additionally, the layout and navigation have been updated to support subdomain-based discovery, ensuring links and menus correctly target the specific discover domain when enabled.

app/javascript/components/Discover · high confidence

Introduce client-side Inertia navigation with dynamic sidebar and account popover

The application now uses a dedicated client-side navigation component built on Inertia.js for Inertia-powered views, replacing the previous server-rendered navbar in those contexts. This new sidebar features dynamic link promotion based on user permissions, a 'Start selling' entry for buyers, and a profile popover that displays team memberships, a 'New Gumroad' creation action, and Settings. The navigation also includes a 'Help' link and a logout option, with prefetching behavior tuned to prevent stale states during navigation.

app/javascript/components/client-components · high confidence

Added new \HomeNav\ and \HomeFooter\ React components to the shared UI library. The navigation bar now conditionally uses Inertia \\<Link\>\ for internal routes and standard \\<a\>\ tags for external or non-Inertia destinations to prevent double-request issues, and includes a fix for the 'Start selling' button visibility in dark mode. The footer now features a conditional currency selector for buyer presentment, updated social media links, and a Gumclaw link, while also optimizing link rendering to avoid suboptimal XHR failures.

app/javascript/components/Home/Shared · high confidence

Introduces server-side persistence and throttling for the Store Agent

The Store Agent chat history is now persisted server-side rather than relying solely on browser state, allowing conversations to survive page refreshes and device switches. A new \AgentConversationPersistence\ concern manages the storage of turns, replays the server-held transcript to the model, and enforces a 100-message history cap to control token costs. Additionally, a new \AgentRequestThrottling\ concern enforces a shared 30-request-per-hour limit across all surfaces (web and mobile) for both sending messages and confirming changes, providing sellers with clear feedback on their remaining budget.

app/controllers/concerns · high confidence

Invoice generation, dispute evidence, and product pages migrate to Inertia

The purchase invoice, dispute evidence, and product pages now use Inertia for rendering, providing a more responsive user experience. Invoice generation now supports business names and country-aware VAT IDs, allowing sellers to correctly handle tax refunds and reverse-charge notes. Dispute evidence submission has been secured by requiring seller login to prevent IDOR vulnerabilities, and sellers can now upload multiple files which are merged into a single PDF, with submissions held until the deadline to allow revisions. The product page now includes custom seller styles in the props passed to the frontend.

app/controllers/purchases · high confidence

Isolated production console queries and test-suite reuse validation

A new script pins production database queries to a verified, isolated Puma container (excluding shopper containers) to prevent interference, writing an atomic config file that enforces strict image, memory, and naming checks. Additionally, a new self-test validates the test-suite reuse logic, ensuring that Fast/Slow matrices are complete and that reuse is skipped when the tree differs or the workflow matrix drifts.

script · high confidence

Library layout refactored to use Inertia.js and shared UI components

The Library component layout has been updated to align with the Inertia.js migration, replacing standard HTML anchor tags with Inertia's \<Link\> component for navigation. The layout now utilizes shared UI components, specifically \<PageHeader\> and \<Tabs\>, to render the navigation tabs (Purchases, Saved, Following, Reviews). Additionally, the feature flags for reviews and following wishlists have been removed, as these features are now permanently enabled, simplifying the component's props and ensuring these tabs are always visible.

app/javascript/components/Library · high confidence

Library page re-architected with Inertia.js, Tailwind CSS, and new UI components

The Library page has been rebuilt to use Inertia.js for navigation and Tailwind CSS for styling, replacing the previous implementation. This change introduces a new component library (including LinkButton, ProductCard, and Modal) and migrates icons to Boxicons. Functionally, the page now relies on server-side pagination and filtering rather than client-side slicing, and it provides clearer messaging to users that removing a product from their library is reversible.

app/javascript/pages/Library · high confidence

Login page migrated to Inertia with passkey authentication support

The login page has been rewritten as a new Inertia/React component (New.tsx), replacing the previous implementation. This change introduces native passkey (WebAuthn) login capabilities, including conditional UI autofill for supported browsers, and updates the form handling to use Inertia's request utilities. The page now manages passkey state, handles authentication options via API calls, and provides specific error messaging for passkey failures, while maintaining standard email/password and social login flows.

app/javascript/pages/Logins · high confidence

Mail delivery reliability, security, and routing improvements

This update hardens email delivery by routing recipients from United Internet domains (web.de, GMX, mail.com) through SendGrid to prevent silent bounces, and replaces insecure external IDs with secure, scoped, expiring tokens in unsubscribe and dispute-evidence links. It also introduces new internal notification and support-contact mailers, splits bank-account rejection emails by specific error type to give sellers accurate remediation steps, and adds new finance-report and payout-failure alerts. Additionally, it fixes nil-reference crashes in several mailers, ensures refund emails show the buyer's local currency, and caps grouped receipts to prevent timeouts.

app/mailers · high confidence

Migrate Audience page to Inertia.js

The Audience page has been rewritten as a client-side Inertia.js component, replacing the previous server-rendered approach. This change introduces client-side data fetching for audience metrics via the \useAnalyticsDateRange\ hook and \router.reload\, enabling smoother interactions without full page reloads. The UI now uses Tailwind CSS classes for styling, Boxicons for the export icon, and typia for runtime type assertion of page props, ensuring type safety and consistent styling across the dashboard.

app/javascript/pages/Audience · high confidence

Migrate EmailsPage to Inertia and add image-upload guard tests

The EmailsPage components have been migrated from React Router to Inertia.js, replacing direct navigation with Inertia's Link and router utilities. This change includes a new test suite for the EmailForm that verifies an image-upload guard: the Save button remains disabled until an uploaded image's CDN URL resolves, preventing the editor from saving a body with broken blob: previews. The migration also introduces new layout, empty-state, and search components, and updates the EmailForm to accept props directly instead of reading loader data.

app/javascript/components/EmailsPage · high confidence

Migrate Products pages to Inertia.js

The Products index, archived, edit, new, show, and affiliated pages have been migrated from the legacy rendering stack to Inertia.js. This change introduces client-side navigation for the product list and edit flows, enabling faster page transitions without full reloads. The new pages use Inertia's \usePage\ hook to receive server-side props and \typia\ for runtime type validation, ensuring type safety for the data passed to React components. The edit page now uses a keyed component to ensure the editor state resets correctly when switching between products, and the index page utilizes deferred data loading to improve initial render performance.

app/javascript/pages/Products · high confidence

Migrate Purchase Product Show page to Inertia

The Purchase Product Show page has been converted to use Inertia.js with React. The new component retrieves page props using Inertia's usePage hook and validates them with typia, replacing the previous casting mechanism. It renders the Product component with selection state derived from the URL and conditionally injects custom styles via the Head component.

app/javascript/pages/Purchases/Product · high confidence

Migrate Secure Redirect page to React with Tailwind CSS

The Secure Redirect page has been rewritten as a new React component (New.tsx) using Inertia.js for form handling and Tailwind CSS for styling. This change replaces the previous implementation with a modern UI that includes a confirmation form, input fields for field names and error messages, and a 'Continue' button, while also integrating the typia library for runtime type assertion of page props.

app/javascript/pages/SecureRedirect · high confidence

Migrate Settings Main page to Inertia.js and React

The Settings Main page has been rebuilt as a new React component (Show.tsx) using Inertia.js, replacing the previous implementation. This change introduces a modern, type-safe interface for managing user details, notifications, and refund policies, leveraging the typia library for runtime validation of server props and standard Inertia form handling for updates.

app/javascript/pages/Settings/Main · high confidence

Migrate Subscription Management page to Inertia with updated pricing logic

The Subscription Management page has been rebuilt as a new Inertia/React component (Manage.tsx), replacing the previous implementation. This change introduces stricter validation for subscription props using typia and updates the pricing calculation logic in price.ts to correctly handle fixed, once-per-cart discount codes by applying them to the cart total rather than the unit price, while preserving legacy per-item discount behavior. The migration also includes new unit tests for the pricing module to ensure accuracy across various discount and installment plan scenarios.

app/javascript/pages/Subscriptions · high confidence

Migrate URL Redirect pages to Inertia with typia validation

The URL Redirect pages (Confirm, Download, Read, Stream, Expired, RentalExpired, MembershipInactive) have been migrated to Inertia.js, replacing the previous rendering approach. This change introduces runtime prop validation using typia to ensure type safety across the client-server boundary. The migration also includes updated test coverage for the new Inertia-based components and the typia assertions.

app/javascript/pages/UrlRedirects · high confidence

The UTM Links page has been migrated from a client-side React Router setup to Inertia. This removes the local route definitions and static server-side router configuration in favor of Inertia's request handling, changing how the UtmLinkList and UtmLinkForm components receive data and manage navigation.

app/javascript/components/server-components/UtmLinksPage · high confidence

The UTM Links Index, New, and Edit pages have been rewritten as React components using Inertia.js, replacing the previous rendering approach. This change introduces client-side navigation for the UTM Links section, enabling smoother transitions between listing, creating, and editing links without full page reloads, while leveraging shared UI components for the interface.

app/javascript/pages/UtmLinks · high confidence

Migrate affiliate and analytics pages to Inertia

The Affiliate, Analytics, Audience, Balance, and related dashboard pages have been migrated from the legacy React-on-Rails server-component system to Inertia. This removes the old \register\ and \createCast\ boilerplate, replaces the custom \StaticRouterProvider\ with Inertia's client-side routing, and updates the pages to use Inertia's data-fetching patterns. The migration also includes adding an Export Subscribers popover for the Followers page and introducing a warning for email delivery issues when a user's name contains a colon.

app/javascript/components/server-components · high confidence

Migrate affiliate management pages to Inertia.js and React

The Affiliates dashboard, including the Index, New, Edit, and Onboarding pages, has been rewritten as React components using Inertia.js for navigation and form handling. This migration replaces the previous server-rendered views, introducing client-side state management for features like affiliate request approval, commission percentage validation (enforcing a 1%–75% range), and dynamic product assignment. The change also updates the UI to use Tailwind CSS and Boxicons, and improves error handling with inline form validation and toast notifications.

app/javascript/pages/Affiliates · high confidence

Migrate build tooling from Sprockets to Vite and upgrade Node.js to 22

The project replaces the legacy Sprockets asset pipeline with Vite for JavaScript and CSS bundling, introducing new configuration files (vite.config.ts, vitest.config.ts) and a Typia-based type-checking plugin. This migration is accompanied by an upgrade of the Node.js runtime from version 20 to 22 LTS. The change also includes the removal of the old Tailwind configuration file in favor of the new Vite-integrated setup and updates to environment variables to support the new build and test infrastructure.

(repo-wide) · high confidence

Migrate legacy SCSS styles to Tailwind CSS

The application's styling system has been migrated from legacy SCSS to Tailwind CSS. This change removes dozens of custom SCSS partials (including \_alert, \_button, \_card, \_forms, \_grid, \_modal, \_nav, and \_product) and replaces them with Tailwind utility classes. A new build pipeline (pages\_tailwind.css) is introduced to pre-compile Tailwind styles for AI-generated landing pages, avoiding the browser-side JIT flicker previously caused by the Play CDN. Users will see consistent styling across the interface as the visual design is now driven by the Tailwind framework.

app/javascript/stylesheets · high confidence

Migrate password reset and forgot password pages to Inertia/React

The password reset (Edit) and forgot password (New) pages in the User section have been rewritten as React components using Inertia.js. Users will now experience these flows with client-side form handling and state management via Inertia's \useForm\ hook, replacing the previous server-rendered or non-Inertia implementation. This change includes the new \Edit.tsx\ component for setting a new password after a reset request and \New.tsx\ for initiating the password reset via email, both integrated with the existing authentication layout and alert components.

app/javascript/pages/User · high confidence

Migrate user-facing pages to Inertia with enhanced analytics and type safety

The user profile and subscription pages (Show, Subscribe, SubscribePreview, Coffee) have been migrated to Inertia.js, replacing the previous rendering approach. This migration introduces strict prop validation using typia to ensure data integrity across these components. A key behavioral change is the activation of seller analytics on all profile pages; the Show page now explicitly tracks profile page views and initializes third-party analytics pixels, ensuring creators receive accurate engagement data. Additionally, the Coffee page now records product view events for seller analytics, including attribution to the recommending product when available, and the SubscribePreview page has been updated to display a redesigned share card centered around the creator's profile.

app/javascript/pages/Users · high confidence

Migrate wishlist following and products endpoints to Inertia and public access

The wishlist following index now renders via Inertia with server-side meta tags instead of a legacy layout, and the feature flag gating for following has been removed. Additionally, the wishlist products endpoint is now publicly accessible (no authentication required) and returns paginated JSON data, enabling external or unauthenticated clients to retrieve wishlist items.

app/controllers/wishlists · high confidence

New Inertia-based Discounts page with Black Friday support

The Discounts section in the Checkout flow has been replaced with a new Inertia-based component (app/javascript/pages/Checkout/Discounts/Index.tsx). This page now uses typia for runtime type assertion of its props and passes data including offer codes, pagination, and specific Black Friday fields (show\_black\_friday\_banner, black\_friday\_code, black\_friday\_code\_name) to the underlying DiscountsPage component.

app/javascript/pages/Checkout/Discounts · high confidence

New Inertia-based Two-Factor Authentication page with numeric input and resend cooldown

The Two-Factor Authentication view has been migrated to a new Inertia/React component (Show.tsx). Users now benefit from a dedicated numeric keyboard on mobile devices for TOTP and email codes, automatic form submission upon entering a 6-digit code, and a 60-second cooldown timer on the 'Resend' button to prevent spam. The page also supports switching between authenticator app, email, and recovery code methods within the same flow.

app/javascript/pages/TwoFactorAuthentication · high confidence

New Inertia-based bundle editor controllers

Sellers can now edit bundle details using a new set of controllers (Base, Content, Product, Share) that render Inertia views. This migration introduces specific editing capabilities: the Product controller allows changing the bundle's display currency and managing default discount codes, while the Content controller handles product selection and publishing status. The Share controller manages taxonomy, tags, and review visibility settings.

app/controllers/bundles · high confidence

New Payouts Index page with detailed period breakdowns and CSV export

The Payouts Index page has been replaced with a new React component that provides a detailed breakdown of each payout period, including sales, credits, affiliate fees, specific fee types (Discover and Direct), and refunds. Users can now export transaction data for completed periods as a CSV file via a dedicated Export button. The page also displays status indicators for current payouts (processing, payable, paused, completed) and highlights instant payouts with a specific pill badge.

app/javascript/pages/Payouts · high confidence

New React-based Team Settings page with Tailwind styling

The Team settings page has been rewritten as a new React component (Show.tsx) using Inertia.js and Tailwind CSS. This change introduces a modern UI for managing team members, including adding new members via email and role selection, and viewing existing team members. The implementation uses typia for type assertion and integrates with the new LinkButton and Alert components.

app/javascript/pages/Settings/Team · high confidence

New affiliate request submission page built with Inertia and Tailwind

The affiliate request interface has been replaced with a new React component (\New.tsx\) that uses Inertia.js for form handling and Tailwind CSS for styling. Users can now submit affiliate applications via a modern form that pre-fills name and email fields for logged-in users, includes a promotion text area, and displays a success alert with instructions to create a Gumroad account if the user does not already have one.

app/javascript/pages/AffiliateRequests · high confidence

New compliance, security, and accessibility utilities in lib/utilities

This change introduces several new utility modules and refactors existing ones to improve compliance, security, and accessibility. A new \Compliance::ColombiaIdNumber\ module validates Colombian ID lengths (6-10 digits) and provides a clear error message for sellers. The \Compliance::Countries\ module has been extracted to its own file, updating the list of comprehensively sanctioned countries (removing Syria, Afghanistan, etc.) and adding logic to handle US territories like Puerto Rico as states for Stripe Connect. Security is enhanced with \CsvSafe\ to prevent CSV formula injection and \LogRedactor\ to redact sensitive fields (like tokens and keys) from logs. Accessibility is improved via \ContrastColor\, which uses WCAG contrast ratios and APCA to ensure text is readable on seller-chosen storefront colors. Additionally, \Mp4Id3Tag\ repairs M4A files with leading ID3v2 tags, \PtOscLeftovers\ detects and prevents deployment issues from abandoned database migrations, and \CardType\ now records non-card payment methods (Link, UPI, Pix, Bancontact, Klarna, Alipay) for accurate purchase tracking.

lib/utilities · high confidence

New deployment and QA utility tasks with Bugsnag removal

This change introduces several new Rake tasks to support deployment, quality assurance, and asset building, while removing the legacy Bugsnag deployment notification. For deployments, a new \taxonomy:seed\ task ensures category taxonomies are applied, and a \db:schema\_parity\ task detects and reports schema drift between the codebase and the live database. For QA on preview apps, \preview\_qa\ tasks allow developers to backdate purchases, clear Stripe mandates, seed dead Sidekiq jobs, and inspect subscriptions in a safe, guarded environment. Asset building now includes a \pages\_tailwind:build\ task for AI-generated page iframes and a \vite:build\_widget\ task that correctly injects environment-specific domain constants for widget bundles. Additionally, the \bugsnag:deployments\ task has been removed, reflecting the migration away from Bugsnag.

lib/tasks · high confidence

New email and ISBN validation rules for signups and uploads

The application now enforces stricter validation for email addresses and ISBNs. Signups are blocked if the email domain is disposable (checked against a list in lib/data/disposable\_email\_domains.txt) or reserved (specifically gumroad.com, gumroad.org, and gumroad.dev). Email format validation now uses a regex aligned with the frontend to reduce invalid entry errors. Additionally, uploaded books must provide a valid ISBN-10 or ISBN-13, with strict digit-only checks to prevent non-numeric strings from passing validation.

app/validators · high confidence

New entrypoint structure and Inertia.js behavioral improvements

The application now uses a new set of entrypoint files (api, base, custom\_html\_analytics, design, email, embed, inertia, mobile\_tracking, overlay) to organize client-side logic. For Inertia.js pages, this introduces a visible progress bar on client-side navigations to provide feedback during slow loads, fixes stale CSRF token issues that could cause POST request failures after navigation, and prevents accidental page reloads from background polling responses on buyer content pages. Additionally, seller analytics are now correctly fired on custom HTML landing pages (both product and profile types) by tracking page views and buy-button clicks within the sandboxed iframe context.

app/javascript/entrypoints · high confidence

New internal admin cursor pagination and tax center access controls

This change introduces two new controller concerns. The \Api::Internal::Admin::CursorPaginated\ concern provides a reusable helper for internal admin APIs to implement cursor-based pagination with configurable limits (default 20, max 100) and invalid cursor handling. The \Api::V2::TaxCenterAccess\ concern adds authorization and validation logic for tax-related endpoints, ensuring the tax center is enabled for the account, validating the requested tax year against available years, and enforcing the \view\_tax\_data\ OAuth scope.

app/controllers/concerns/api · high confidence

New marketing and affiliate management endpoints with Inertia migration for product tabs

This change introduces several new API endpoints for product management: a controller to list available offer codes, and new controllers for managing marketing actions (including abandoned cart recovery) and affiliate removal. It also migrates the Affiliated, Archived, and Collabs product tabs to use Inertia partial reloads instead of separate JSON API calls for pagination, improving page responsiveness. Additionally, the archived products endpoint now sets a purchase disabled timestamp upon archiving, and the mobile tracking endpoint now includes an analytics enabled flag in its response.

app/controllers/products · high confidence

New model concerns for security, payments, and performance

This update introduces several new model concerns and refactors existing ones to improve security, payment handling, and query performance. A new \AttributeBlockable\ concern provides a flexible system for checking if model attributes are blocked via the PlatformBlock system, with support for efficient N+1 query prevention through eager loading. Payment processing is enhanced with \BicCountryValidation\ to reject bank codes from incorrect countries, \IbanBankAccount\ to support cross-country IBAN payouts in the SEPA zone, and \ChargeProcessable\ to standardize charge processor comparisons. Data integrity and performance are improved with \SecureExternalId\ for encrypted, scoped tokens, \HasLaterChargePresentments\ to store fixed buyer-currency amounts, \RecurringLockTtl\ to bound scheduled job lock TTLs, and \TouchesProductForPriceCache\ to bust the profile cache when prices change. Existing concerns are also updated: \JsonData\ now merges writes onto the current row to prevent overwrites, \RichContents\ handles recoverable hidden variant content, \Streamable\ handles missing S3 objects gracefully, \StrippedFields\ removes invisible characters, and \WithFiltering\ adds new audience filters and optimizes post-filter probes.

app/models/concerns · high confidence

New password settings page with 2FA and passkey management

The Password settings page has been rebuilt using Inertia.js and Tailwind CSS, consolidating password changes, two-factor authentication (2FA), and passkey management into a single interface. Users can now change their password, set up or remove an authenticator app (including regenerating recovery codes), and manage passkeys directly from this tab, replacing the previous separate settings views.

app/javascript/pages/Settings/Password · high confidence

New schema parity checks, MySQL2 proxy routing fixes, and stricter bad request handling

This update introduces three distinct capabilities in the lib directory. First, a new DbSchemaParity tool (lib/db\_schema\_parity.rb) compares the declared schema in db/schema.rb against the live database to report missing tables, columns, or indexes, helping detect migration drift during deployment. Second, MySQL2 proxy routing (lib/mysql2\_proxy\_routing.rb) is refined to correctly handle scoped primary routing for worker reads and to clear the query cache when the serving connection pool changes, ensuring data consistency. Third, the bad request error handler (lib/catch\_bad\_request\_errors.rb) now safely handles requests missing an Accept header by using safe navigation, ensuring a 400 response is returned regardless of header presence, while the legacy icon-finding script (lib/findIcons.js) has been removed.

lib · high confidence

PayPal webhook security and Stripe event handling improvements

PayPal webhooks now include signature verification via a new \PaypalWebhookVerifier\ class to ensure incoming events are authentic, while error reporting for unhandled PayPal messages switches from Bugsnag to the \ErrorNotifier\ abstraction. For Stripe, the system now processes \payment\_intent.processing\ and \payment\_intent.succeeded\ events, enabling support for direct-charge sellers on client-confirm checkouts by mirroring the platform branch's lifecycle handling on connected accounts.

app/business/payments/events · high confidence

Post detail page now renders with Inertia and supports right-to-left text

The Post Show page has been rewritten as a new Inertia React component (Show.tsx), replacing the previous implementation. This change introduces proper right-to-left (RTL) text direction handling for post content via the dir="auto" attribute on the rich-text editor, ensuring mixed-language content displays correctly. The page now uses typia for runtime prop validation, imports icons from Boxicons, and integrates with the new Inertia-based layout and comment systems.

app/javascript/pages/Posts · high confidence

Product creation limits, pricing logic, and search reliability improvements

Sellers now face a configurable daily product creation limit (defaulting to 100 for compliant users, 10 otherwise) to manage account activity, with a bypass mechanism for internal use. Pricing behavior has been refined: products now retrieve prices based on the current currency, pay-what-you-want coexists with paid versions on $0-base products, and large price inputs are validated to prevent Elasticsearch overflow errors. Search and discovery reliability is improved by clamping price filters, requiring taxonomy IDs for attribute filtering, and adding safeguards for review stat creation to prevent database deadlocks. Additionally, social share images for products are now correctly generated using cover or thumbnail fallbacks, and bundles are enforced to contain at least one product upon publishing.

app/modules/product · high confidence

Product editor loads instantly with resilient error handling and improved preview accuracy

The product editor now loads significantly faster by prefetching its code from the Products list and displaying a skeleton that shows the product name while the editor initializes, eliminating the previous issue where clicks appeared to do nothing. If the editor code fails to load, a dedicated error boundary provides a clear message and a 'Try again' button instead of a blank page. Additionally, the landing page preview now correctly handles navigation and checkout actions from custom HTML, and the receipt preview fetches the subject line from the server to ensure it matches the rendered body.

app/javascript/components/ProductEdit · high confidence

Product file editor and purchase error handling improvements

The product editor now supports collaborative file uploads, allows omitting files without triggering accidental deletions, and preserves the original byte count for newly uploaded files. Video analysis is more robust, detecting unplayable M4A files with leading ID3 tags and failing gracefully when no video stream is present. Purchase error codes have been expanded to include specific handling for Pix, UPI Autopay, Indian card mandates, and duplicate purchase confirmations, while the money formatter now soft-fails on unknown currencies instead of raising errors. Additionally, a 'Recently viewed' recommendation type has been added to the Discover page.

app/modules · high confidence

Product page component suite and tests migrated to TypeScript and Tailwind CSS

The product page components have been rewritten in TypeScript and migrated from SCSS to Tailwind CSS classes. This update introduces new components such as CollapsibleDescription for mobile-friendly long descriptions, SubscriptionChoiceModal for managing recurring billing, and CoffeeProduct for donation-style purchases. It also adds comprehensive test coverage for the CardGrid, ConfigurationSelector, and CtaButton logic, while ensuring accessibility improvements like screen-reader operability for price inputs and version selectors.

app/javascript/components/Product · high confidence

Product refund policy data model updated with max refund period

The data structure for other refund policies now includes a \max\_refund\_period\_in\_days\ field, allowing the system to track the maximum number of days a product is eligible for a refund. The previous implementation that fetched these policies via an API endpoint has been removed, indicating a shift in how this data is sourced or managed within the application.

app/javascript/data/products · high confidence

Products controller now inherits from Settings::BaseController

The Settings::Profile::ProductsController now inherits from Settings::BaseController instead of ApplicationController. This change aligns the controller with the settings-specific base class, likely ensuring it uses the correct authentication, authorization, or layout conventions defined in the settings namespace.

app/controllers/settings/profile · high confidence

Products page re-architected for Inertia.js partial reloads and Tailwind CSS

The Products page now uses Inertia.js partial reloads to update only the products and memberships data sections, replacing the previous full-page or client-side fetch approach. This change improves performance and keeps the URL query parameter in sync with the search state. The UI has been migrated from custom SCSS to Tailwind CSS, and the table components now receive their data (entries, pagination, sort state) as props rather than managing it locally, ensuring consistent state across the page. Additionally, the product action menu has been updated to use Boxicons and a new Menu component, and archiving a published product now explicitly displays an 'unpublished' status message.

app/javascript/components/ProductsPage · high confidence

Profile editor overhaul with native pages-and-sections management and CAPTCHA-protected subscriptions

The profile editing experience has been rebuilt around a native pages-and-sections editor, allowing sellers to create, duplicate, and reorder profile pages and sections with a stable UI that correctly handles rich-text upsell cards and section naming. Public-facing profiles now render the bio as body text instead of a headline, support a Top Creator badge, and display a seller-level reputation summary. The subscribe form now requires a CAPTCHA for unreviewed sellers to prevent spam, and sellers can optionally hide the subscribe form entirely. The layout has been migrated to Tailwind CSS, icons have been replaced with Boxicons, and the editor now uses Inertia for navigation.

app/javascript/components/Profile · high confidence

Profile logo upload renamed to avatar with improved Retina display guidance

The profile settings component now refers to the uploaded image as an 'avatar' instead of a 'logo' in both the fieldset title and help text. The help text has been updated to recommend uploading images at 400x400px or larger to ensure sharpness on high-resolution (Retina) screens, while maintaining the minimum 200x200px requirement. The image display is now rendered in a circular shape, and the component uses new UI primitives (Fieldset, FieldsetTitle, Label) for consistent styling.

app/javascript/components/Profile/Settings · high confidence

Profile settings page migrated to Inertia with improved state management

The Profile settings page has been rebuilt using Inertia.js, replacing the previous implementation to provide a more robust editing experience. This change introduces a new unsaved-changes confirmation dialog that intelligently handles rapid navigation attempts to prevent accidental data loss, and implements a 'rebase' strategy for form state that preserves local edits when server-side updates occur concurrently. The UI now supports custom font selection, background and highlight color theming, and allows sellers to hide the profile subscribe form, with all changes reflected in a live preview pane.

app/javascript/pages/Settings/Profile · high confidence

Purchase model refactoring: PayPal support, async audience updates, and fraud detection improvements

This change introduces PayPal-specific purchase handling (scopes, email, and fee calculations) and significantly refines fraud and risk management by expanding blockable identifiers to include PayPal and gifter emails, refining card-testing velocity rules to ignore processor-side failures, and ensuring unblocks apply to the buyer across all purchases rather than a single row. It also shifts audience member updates to an asynchronous, commit-based job system to prevent checkout locking, adds support for client-confirmed payment intents (including ACH and Cash App Pay) with proper error persistence, and improves tax reporting by attributing refunds and chargebacks to their event dates using new cutover logic.

app/models/concerns/purchase · high confidence

Rebuilt API documentation with structured, component-based rendering

The API documentation page has been rewritten using a new set of React components (ApiEndpoint, ApiResource, ApiResponseFields, etc.) that enforce a consistent, structured layout for endpoints, parameters, and response fields. This change introduces a standardized visual style for API references, including collapsible response field details, explicit method/path pills, and dedicated sections for authentication, scopes, and error codes, making the documentation easier to scan and navigate for developers.

app/javascript/components/ApiDocumentation · high confidence

Rebuilt signup page with Inertia.js and React

The signup page has been migrated from the previous implementation to a new React component powered by Inertia.js. This change introduces a modern form handling approach using the \useForm\ hook for email and password inputs, integrates social authentication options, and displays dynamic header text based on referrer or application context. The layout now utilizes shared authentication components and Tailwind CSS classes for styling.

app/javascript/pages/Signup · high confidence

Redesigned download page with Inertia.js and new audio player

The download page has been migrated to Inertia.js, introducing a new compact sticky header and a dedicated AudioPlayerContainer that tracks media consumption and resume locations. The layout now features a redesigned review form, updated membership and installment plan details, and improved mobile table of contents scrolling, while also removing the previous entity info box.

app/javascript/components/DownloadPage · high confidence

Redesigns Email Action layout with Tailwind and Inertia components

The Email Action layout has been updated to use a responsive, full-height flex layout powered by Tailwind CSS classes, replacing the previous static structure. The content is now wrapped in reusable Card components, and the footer has been migrated from inline styles to Tailwind utility classes while integrating the new Logo component via Inertia's Link for navigation.

app/javascript/components/EmailAction · high confidence

Refactor email delivery tracking and error reporting

The email delivery observer now ignores incoming emails that lack the internal provider header, preventing authentication or system emails (such as Devise notifications) from triggering parse errors or creating invalid records. Additionally, the system has switched its error reporting backend from Bugsnag to Sentry, updating the relevant context and notifier calls in the customer email info handler. The logic for creating customer email info records has also been refactored to use a build-only pattern instead of find-or-initialize, ensuring that new records are created without side-effects from existing database states.

app/observers · high confidence

Refactor product serialization and add structured data generation

The product model now uses a dedicated \Product::AsJson\ concern to centralize JSON serialization, introducing distinct output modes for the admin interface, public API (including purchasing power parity pricing and bundle details), and mobile clients. A new \Product::StructuredData\ concern automatically generates Schema.org JSON-LD markup for product pages, supporting both generic Product and Book types with aggregate ratings and merchant-center-compatible USD pricing. Additionally, taxonomy attributes are now automatically classified via an \after\_commit\ hook when a product's taxonomy changes.

app/models/concerns/product · high confidence

Refactored OAuth callbacks and password reset to use Inertia and standardized flows

The user authentication experience has been updated to use Inertia for the password reset UI and standardized logic for OAuth callbacks. Password reset pages now render via Inertia components, and the flow redirects to the login page after sending a reset email. OAuth handling for Google, Twitter, Stripe, and the new YouTube integration now uses a shared \sign\_in\_with\_oauth\ method, removing redundant per-provider login logic. Additionally, linking social accounts (Twitter, YouTube) now requires the user to be logged in first, and sensitive data in Stripe Connect logs is redacted for security.

app/controllers/user · high confidence

Refactored cache key generation to support dual engagement data sources

The caching module now generates distinct cache keys for email engagement data depending on whether the source is DynamoDB or the legacy system, appending a '\_ddb' suffix for DynamoDB reads. This change allows the application to maintain separate cached aggregates for the new primary store and the old MongoDB-based counts, facilitating a smoother transition and enabling specific cache invalidation for either source without cross-contamination.

app/modules/post · high confidence

Refactored page meta tags into modular concerns for improved SEO and analytics control

The page meta tag generation logic has been reorganized into specific concerns (Base, Analytics, Favicon, Post, Product, User, Wishlist) to provide more granular control over search engine optimization and third-party integrations. This change introduces structured data and canonical URL handling for product and wishlist pages, ensures seller-branded favicons are used on profile surfaces, and adds support for third-party analytics flags (Google Analytics, Facebook Pixel, TikTok Pixel) via meta tags. It also fixes Open Graph and Twitter card rendering for posts and products, including proper handling of custom domains and zero-decimal currencies.

_app/controllers/concerns/page\meta · high confidence

Refined Indian card mandate handling and setup intent flow

The Stripe setup intent controller now uses a dedicated \mandate\_options\_for\_stripe\ method to manage payment mandate details, introducing logic that respects a new \india\_card\_mandate\_reliability\_enabled?\ flag on subscriptions to apply specific terms and rates for Indian card mandates. The flow also includes a new check to skip the setup intent entirely for new registrations under specific reliability conditions, and adds robust authentication verification for existing subscriptions to ensure the user is authorized to modify them. Additionally, error logging has been sanitized to remove raw parameter data, improving privacy in logs.

app/controllers/stripe · high confidence

Refined US state sales tax reporting with separate refund transactions and improved error handling

The US state sales tax upload logic now distinguishes between pre- and post-cutover refunds: purchases created on or after the cutover date are uploaded at their gross amounts, while their corresponding refunds are reported as separate, date-stamped refund transactions to TaxJar, preventing double-tax relief. Pre-cutover purchases continue to have refunds netted into the original order upload. Additionally, the system now explicitly handles TaxJar's 'already imported' errors to avoid duplicate reporting and suppresses expected NotFound and BadRequest errors from Sentry notifications, reducing noise in error monitoring.

_app/business/sales\tax/taxjar · high confidence

Refined instant payout limits and cross-currency payout logic

Instant payouts now enforce explicit minimum ($1) and maximum ($9,999) balance thresholds, replacing the previous generic checks. The processor also introduces a 25-hour delay for cross-border payouts to prevent balance-insufficient errors, and implements a cache for supported payout currencies to ensure funds are only paid out in currencies the connected Stripe account can actually receive, avoiding stranded balances or rejected transfers.

app/business/payments/payouts/processor/stripe · high confidence

Refinements to user authentication, fraud prevention, and dashboard navigation

This update introduces several behavioral changes to the user model. Google OAuth now sets the user's email only during initial account creation, preventing login failures when a Google account is linked to a different email than the existing Gumroad account, and adds retry logic for database deadlocks during sign-in. Apple OAuth is expanded to support account linking and purchase history attachment for new sign-ups. Email normalization is strengthened to block abusive Gmail variants at signup, and expected fraud-gate rejections are filtered out of Sentry alerts. The dashboard navigation system now uses a dedicated database table to track earned items, avoiding race conditions and deadlocks that previously occurred with JSON column updates. Additionally, sellers with low balances are automatically placed on probation with refunds disabled, and probation is automatically lifted once the balance recovers. The 1099-K eligibility criteria for 2025 now require both a minimum sale amount and a minimum sale count, and the tax center is explicitly enabled for all US-based sellers.

app/models/concerns/user · high confidence

Refund statistics now account for fee write-offs

The payment stats module has been updated to include revenue adjustments for unrecoverable non-US refund fees. Previously, the calculation only considered waived fees; the new logic explicitly adds back amounts from \BalanceTransaction.refund\_fee\_write\_offs\ to the revenue by link, ensuring that statistics accurately reflect the net financial impact when fees are written off rather than simply waived.

app/modules/payment · high confidence

Removal of React on Rails server components and legacy SCSS packs

The application has removed the \React on Rails\ integration for server-side rendered components, deleting the corresponding JavaScript entry points (e.g., \admin.ts\, \dashboard.ts\, \product.ts\) that previously registered these components. Additionally, the legacy SCSS pack files (\admin.scss\, \design.scss\, \email.scss\) have been significantly cleaned up by removing imports for individual component stylesheets (such as \button\, \card\, \modal\) that are now handled by Tailwind, leaving only global and utility imports.

app/javascript/packs · high confidence

Removal of React on Rails server-side rendering infrastructure

The application has removed the \React on Rails\ integration for server-side rendering. The \ssr.ts\ entry point, which previously registered dozens of server-side React components (such as Dashboard, Analytics, and Settings pages) for server rendering, has been deleted. Corresponding server-component files (e.g., \server-components/ReviewReminders/\*\) have been removed, and new Inertia.js page wrappers (e.g., \pages/Analytics/Index.tsx\, \pages/Dashboard/Index.tsx\) have been added to handle client-side rendering instead. This change eliminates the server-rendered React bundle for these pages, shifting the rendering responsibility entirely to the client via Inertia.

app/javascript · high confidence

Removal of dispute evidence submission logic from frontend data layer

The \app/javascript/data/purchase/dispute\_evidence\_data.ts\ file has been refactored to remove the \SellerDisputeEvidence\ type definition and the \submitForm\ function, which previously handled the API request to submit dispute evidence. While the constant definitions for cancellation rebuttal options and their corresponding labels remain available for type safety, the actual mechanism for sending the form data to the server has been stripped from this module, likely as part of the broader migration to Inertia.

app/javascript/data/purchase · high confidence

Removal of internal API controllers for community chat and notifications

The internal API endpoints for managing community chat messages, tracking last-read messages, and updating notification settings have been removed. Specifically, the \ChatMessagesController\, \LastReadChatMessagesController\, and \NotificationSettingsController\ are deleted, indicating that these functionalities are no longer served via the legacy internal API structure and are likely handled by the new Inertia-based implementation.

app/controllers/api/internal/communities · high confidence

Removal of legacy Sprockets JavaScript pipeline and Facebook SDK integration

The application has removed the legacy Sprockets JavaScript pipeline, specifically deleting the main application.js manifest and the facebook\_sdk.js.erb file. This change eliminates the server-side rendering of the Facebook SDK initialization logic (including the Facebook App ID injection) and the bundling of older dependencies like jQuery 1.8.3 and jQuery UI custom builds via Sprockets directives, indicating a shift away from this specific asset management approach.

app/assets/javascripts · high confidence

Removal of legacy Sprockets asset manifest

The Sprockets JavaScript pipeline has been removed by deleting the \app/assets/config/manifest.js\ file. This change eliminates the legacy asset manifest that previously managed the linking of images, fonts, and JavaScript files, marking the end of support for the Sprockets-based asset pipeline in this area of the application.

app/assets/config · high confidence

Remove Bugsnag, Mongoer, and Makara Sidekiq middleware

The application no longer integrates with Bugsnag for error tracking, as the dedicated Sidekiq retry callback handler has been removed. Support for MongoDB has been eliminated by deleting the Mongoer utility class, which previously handled safe writes, updates, and async operations. Additionally, the Sidekiq middleware that reset database contexts via Makara has been removed, reflecting the removal of the Makara dependency.

lib/extras · high confidence

Remove legacy jQuery 1.8.3 and add TikTok Pixel vendor script

The vendor JavaScript assets have been updated to remove the legacy jQuery 1.8.3 library and introduce a new TikTok Pixel integration script. This change removes the old jQuery file from the vendor assets, likely reflecting a shift away from this specific version for frontend dependencies, while adding a new \tiktok\_pixel.js\ file that loads the TikTok analytics SDK. This supports the broader migration away from the legacy Sprockets pipeline and aligns with the removal of jQuery-dependent upload mechanisms.

vendor · high confidence

Removed legacy ProductTab component from BundleEdit

The \ProductTab\ component located at \app/javascript/components/BundleEdit/ProductTab/index.tsx\ has been deleted. This removal eliminates the legacy React implementation that previously handled the product details, pricing, and settings forms within the bundle editing interface, marking a step in the ongoing migration of the bundle edit UI.

app/javascript/components/BundleEdit/ProductTab · high confidence

Resilient feature flag reads during Redis failures

The Flipper Redis adapter now includes a fail-open mechanism that caches feature flag states locally to ensure reads remain available even when the Redis connection stalls or fails. If a read operation encounters a Redis error, the adapter falls back to the last known good state for known flags, preventing application crashes or degraded user experiences due to temporary infrastructure issues. This change introduces a new \RedisFailOpen\ adapter class that wraps the standard Redis adapter to provide this resilience.

lib/flipper · high confidence

Users who receive review reminder emails (often dormant accounts) can now subscribe or unsubscribe directly from the email links without needing to log in. This is enabled by a new \Users::ReviewRemindersController\ that resolves users via a secure token rather than a session, and gracefully handles validation failures for dormant accounts. Additionally, the \Users::OauthController\ has been cleaned up by removing the now-unused Facebook login and token storage methods (\async\_facebook\_create\, \async\_facebook\_store\_token\), which were previously removed from the UI in an earlier change.

app/controllers/users · high confidence

Review reminder subscription pages migrated to Inertia

The Review Reminders subscription and unsubscription interfaces have been rebuilt as Inertia.js React components (Subscribe.tsx and Unsubscribe.tsx). Users can now manage their review reminder preferences through these new pages, which include a resubscribe link on the unsubscription confirmation screen and a confirmation message on the subscription confirmation screen.

app/javascript/pages/Users/ReviewReminders · high confidence

Reviews page migrated to Inertia.js with new React components

The Reviews index page has been rebuilt as a new Inertia.js React component (Index.tsx), replacing the previous implementation. This change introduces a modern UI using Tailwind CSS classes and Boxicons for icons, and implements Inertia's client-side data handling for displaying reviews and purchases. The page now supports editing reviews via a popover interface and allows buyers to publish reviews as themselves or anonymously, with specific handling for bundle products and deleted items.

app/javascript/pages/Emails, app/javascript/pages/Reviews · high confidence

Rich text editor stability and accessibility improvements

The rich text editor now handles image and audio file uploads more reliably by taking a snapshot of the picked file before resetting the input, preventing uploads from getting stuck at 0% in Chromium. YouTube embed lookups are now normalized to canonical URLs and retried with a fallback spelling to avoid failures caused by poisoned caches. Accessibility is improved by labeling the media embed removal control with text instead of relying on a bare icon, and the license key settings are now always visible in the editor rather than hidden behind an expand button.

app/javascript/components/TiptapExtensions · high confidence

Sales tax calculation fixes and EU VAT logic updates

This change addresses a buyer-currency quote mismatch by rounding sales tax amounts to whole cents at the calculation boundary, ensuring consistency between checkout quotes and charge-time persistence. It also refines EU VAT handling by excluding the UK from the EU-27 destination list, introducing logic to stop collecting EU VAT on physical shipments that cannot be remitted (to avoid double-charging at the border), and adding support for exempting Canary Islands, Ceuta, and Melilla buyers based on postal codes. Additionally, the code simplifies regional VAT ID validation by consolidating multiple country-specific services into a single RegionalVatIdValidationService and updates product tax code mapping to use TaxJar codes.

_app/business/sales\tax · high confidence

Seller reputation rollup, payout info consolidation, and payout scheduling overhaul

This change introduces a new cached seller reputation summary (User::ReputationSummary) that aggregates product review stats into a single rating, served via a Redis-keyed SQL aggregate to prevent database timeouts on large catalogues. It adds a new User::PayoutInfo module to consolidate payout status, manual payout eligibility, and balance breakdowns into a single API response. The User::PayoutSchedule module is significantly refactored to support daily payouts, calculate payout dates based on the seller's specific rail weekday, and expose upcoming payouts with their associated balances. Additionally, the User::FeatureStatus module updates PayPal Connect eligibility to require only payout information, adds warnings for disconnecting the only payout rail, and enforces mandatory payout method setup for publishing. The User::Risk module lowers the automatic chargeback-rate payout hold threshold to 1.5% over a trailing year, introduces automatic refund policy enforcement for high dispute rates, and records Stripe suspension reasons. Finally, the User::Compliance module adds Gambia to supported countries, fixes P.O. Box address history checks, and updates country-specific logic for Mauritius, El Salvador, and Cote d'Ivoire.

app/modules/user · high confidence

Settings layout migrated to Inertia and supports mobile app WebView embedding

The Settings layout component has been refactored to use Inertia.js for navigation (replacing direct anchor tags with Inertia Links) and modern UI primitives (PageHeader, Tabs). This change introduces support for embedding the Settings interface within a mobile app WebView: the layout now detects the mobile environment via page props, suppresses the standard header/tabs UI in that context, and establishes two-way communication with the host app to report update capability and trigger save actions. Additionally, new settings pages for 'Billing' and 'Social connections' have been added to the navigation structure.

app/javascript/components/Settings · high confidence

Settings pages migrate to Inertia and introduce new management sections

The Settings area has been migrated from a legacy rendering approach to Inertia, with all controllers inheriting from a new \Settings::BaseController\ that sets the \inertia\ layout and shares page data. This change introduces dedicated controllers for managing beneficial owners, billing details, legal guardians (for sellers aged 13–17), passkeys, and social connections. Additionally, the update flow for the main account settings now supports product-level support emails and allows sellers to disable affiliate requests, while the profile editor now includes optimistic concurrency checks to prevent layout conflicts.

app/controllers/settings · high confidence

Settings pages migrated to Inertia server components

The Settings interface (Main, Password, Payments, Team, Authorized Applications, and Third-Party Analytics pages) has been refactored from client-side React components to Inertia server components. This migration removes the need for client-side hydration for these pages, resulting in faster initial load times and improved performance. Users will experience the same functionality with no changes to the interface, but the underlying rendering is now handled on the server.

app/javascript/components/server-components/Settings · high confidence

Share tab migrated to Inertia and UI components updated

The Bundle Edit Share tab has been refactored to use Inertia for navigation and modern UI components. The MarketingEmailStatus component now accepts explicit props instead of relying on the global bundle context, uses the new Routes helper for email draft links, and replaces legacy form elements with the new Alert, Fieldset, Label, and Radio components. The main ShareTab component file was removed, indicating a structural shift in how this tab is rendered or integrated within the Inertia migration.

app/javascript/components/BundleEdit/ShareTab · high confidence

Stricter hex color validation and normalization in profile settings

The hex color validator now enforces stricter input validation to prevent CSS injection via trailing newlines, ensuring that only valid hex color codes are accepted for profile font and color controls. It also introduces support for shorthand hex colors (e.g., \#fff) by normalizing them to their full 6-digit equivalents (\#ffffff) and provides a new method to validate colors specifically for safe CSS usage.

lib/validators · high confidence

The Subscription Manager Magic Link page has been rewritten as a React component using Inertia.js, replacing the previous implementation. Users will now experience this flow through the new Inertia-based architecture, which includes type-safe prop validation via typia and updated UI components for sending or resending magic links to manage subscriptions.

app/javascript/pages/Subscriptions/MagicLinks · high confidence

The subscription magic link interface has been migrated to use Inertia for rendering the new page, providing a more modern client-side experience. Additionally, the system now preserves the selected email source when a request is invalid, ensuring users do not lose their input context during the magic link generation process.

app/controllers/subscriptions · high confidence

Subscription restart and active-state lookup logic

The subscription module now includes a \Restartable\ concern that provides methods to identify eligible subscriptions for restart based on product and buyer or email, ensuring only valid, non-test, non-admin-cancelled recurring subscriptions are considered. It also defines methods to check for active subscriptions by buyer or email, filtering out failed or cancelled ones. This change introduces the core logic for handling subscription restarts and active state verification within the subscription module.

app/modules/subscription · high confidence

Support for new payment methods and client-confirm checkout flow

This change introduces support for UPI Autopay for fixed-INR memberships and adds Alipay, Klarna, Bancontact, and Pix as launch-flagged checkout payment methods. It implements the Payment Element client-confirm checkout path, allowing buyers to confirm payments directly in the browser, and updates the system to record the actual Stripe payment method type (e.g., UPI, iDEAL, Pix) on purchases for accurate reporting. Additionally, it fixes several issues including NoMethodErrors on failed destination charges and incomplete Stripe Capital deductions, and improves handling of Indian card mandates and refund fee retention.

app/business/payments/charging/implementations/stripe · high confidence

Test suite performance and local environment modernization

The CI test workflow is significantly faster because the prepared test database is now baked into the test image, allowing shards to restore a snapshot in seconds instead of running \db:prepare\ from scratch. Local development and testing environments have been modernized by replacing MongoDB with DynamoDB Local and S3 with MinIO, and by switching the base OS from Debian Bullseye to Bookworm. Additionally, the test runner now uses isolated Redis databases to prevent concurrency conflicts, and the local Nginx container is now opt-out.

docker · high confidence

Third-party analytics settings page rewritten in React with Tailwind CSS

The Third-party analytics settings page has been rebuilt as a new React component (Show.tsx) using Inertia.js and Tailwind CSS, replacing the previous implementation. This update introduces a modern UI for managing tracking configurations, including dedicated input fields for Google Analytics, Facebook Pixel, and TikTok Pixel, as well as controls for domain verification and free-sale analytics events. The migration also standardizes the interface with new design system components like Switch, Checkbox, and Details, ensuring consistent styling and behavior across the settings area.

app/javascript/pages/Settings/ThirdPartyAnalytics · high confidence

US LLC business types now distinguish single vs. multi-member structures

The US business type selection now offers separate options for 'LLC (single member)' and 'LLC (multi-member)' in addition to the generic LLC. This change aligns with Stripe's requirement to specify LLC member count. For tax reporting purposes, both new types continue to map to the legacy 'LLC\_PARTNER' classification to maintain compatibility with existing 1099 export formats, ensuring that sellers previously using the generic LLC option can reselect the appropriate specific type without breaking historical data.

_app/modules/user\_compliance\info · high confidence

Update supported currencies for payouts and buyer selection

The list of currencies available for creating Stripe Connect accounts and making payouts has been updated: several currencies (including BGN, DKK, SEK, MXN, NOK, VND, and others) have been removed from this specific payout-only list, while Gambia (GMD) has been added. This change affects the backend currency configuration used for payout eligibility and account creation, distinct from the general buyer currency picker.

app/business/payments · high confidence

Upsell product search and pause management

Sellers can now pause and unpause individual upsells via a new pauses controller, and the product picker for upsells supports server-side search by product or variant name to ensure older catalog items are selectable. The product index and show endpoints also include related data (prices, variants, images) upfront to improve performance and reliability.

app/controllers/checkout/upsells · high confidence

Wishlist page now supports infinite scroll and redesigned item cards

The Wishlist page now loads items in batches using infinite scroll (triggered by an IntersectionObserver) instead of loading all items at once, with pagination state managed in the frontend. The individual wishlist item cards have been redesigned to use the shared ProductCard component, featuring new Boxicons for actions like 'Add to cart', 'Gift', and 'Remove', and a cleaner layout for product details and pricing. The WishlistEditor modal has also been simplified to focus on name and description, removing the inline item list.

app/javascript/components/Wishlist · high confidence

Wishlists page rewritten in React with Inertia and Tailwind

The Wishlists Index and Show pages have been completely rewritten as new React components (Index.tsx and Show.tsx) using Inertia.js for navigation and Tailwind CSS for styling. The Index page now uses a table layout to display wishlists with a toggleable 'Discoverable' switch and a delete confirmation modal, while the Show page dynamically selects between a Profile layout and a Discover layout based on the current context. This migration introduces the typia library for runtime type assertion and replaces legacy icon implementations with Boxicons.

app/javascript/pages/Wishlists · high confidence

Workflows page migrated to React Router

The Workflows page has been refactored to use React Router for client-side navigation, replacing the previous routing implementation. This change updates the WorkflowList, WorkflowForm, and WorkflowEmails components to integrate with the new router, enabling smoother transitions between the workflow list, creation, editing, and email configuration views without full page reloads.

app/javascript/components/server-components/WorkflowsPage · high confidence

Workflows page restructured with email preview and publish options

The Workflows page now features a dedicated layout that supports an email preview sidebar, displaying the actual sender line for workflow emails rather than generic browser chrome. A new Publish button component allows users to publish workflows immediately or send them to past customers via a popover toggle. The page structure is split into Details and Emails tabs for navigation, and the workflow list now includes a confirmation modal for deleting workflows.

app/javascript/components/WorkflowsPage · high confidence

Workflows pages migrated to Inertia.js with runtime type validation

The Workflows pages (Index, New, Edit, and Emails Index) have been rewritten to use Inertia.js for rendering, replacing the previous implementation. These new page components utilize the typia library to perform runtime validation on the props received from the server (such as workflow lists, workflow objects, and form contexts) before passing them to the underlying React components, ensuring data integrity and enabling the Vite migration.

app/javascript/pages/Workflows · high confidence

Test coverage

Add tests for data-layer modules and introduce marketing action data module; Added comprehensive test suite for the Payments Settings page; Added tests for Tailwind utility compilation in custom pages; Added tests for User::FeatureStatus module; Added tests for checkout payment lane mapping and post-purchase cart save cancellation; Added tests for product creation limits; Added tests for product creation limits, search, and caching; Added tests for purchase risk, accounting, and review logic; Added tests for subscription restart eligibility logic; Added tests for user payout rails, reputation rollups, and risk suspension logic; Migrate test suite to Minitest and fixtures; Minitest migration and CI infrastructure updates; New and updated component tests for Affiliated, Churn, and Payout features.

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Score

  • CAI 32 → 43 (+11.5)
  • Rubric changed (rubric-2026.08.15 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 59 → 75 (+15.5)
  • Architecture 54 → 59 (+4.5)
  • Maturity 60 → 64 (+3.5)
  • Readiness 17 → 37 (+20.5)
  • Security 34 → 48 (+14.3)
  • Domain Modelling 51 (new)
  • Accessibility 43 (new)

Resolved (140)

  • (anonymous) (cognitive 19) (qa-media/pr-6738-capture.mjs)
  • Change coupling: ProductPreview.tsx ↔ product.ts (app/javascript/components/ProductEdit/ProductPreview.tsx)
  • Change coupling: index.tsx ↔ offer_code.ts (app/javascript/components/Product/index.tsx)
  • Coverage not measured — test suite did not build
  • Critical CVE: [GHSA redacted] (package-lock.json)
  • Critical CVE: [GHSA redacted] (Gemfile.lock)
  • Critical IaC: DS-0031 (docker/web/Dockerfile)
  • Critical IaC: DS-0031 (docker/web/Dockerfile.test)
  • Dimension evaluation failed
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (Gemfile.lock)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (Gemfile.lock)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • …and 120 more

New (1725)

  • AbandonedCartProducts.abandoned_cart_products (cognitive 17) (app/models/concerns/workflow/abandoned_cart_products.rb)
  • AbandonedCartProducts.abandoned_cart_products (cyclomatic 19) (app/models/concerns/workflow/abandoned_cart_products.rb)
  • AccountDetailsSection.AccountDetailsSection (cognitive 250) (app/javascript/components/Settings/PaymentsPage/AccountDetailsSection.tsx)
  • AccountDetailsSection.AccountDetailsSection (cyclomatic 174) (app/javascript/components/Settings/PaymentsPage/AccountDetailsSection.tsx)
  • AccountStatusSection.AccountStatusSection (cognitive 62) (app/javascript/components/Settings/PaymentsPage/AccountStatusSection.tsx)
  • AccountStatusSection.AccountStatusSection (cyclomatic 31) (app/javascript/components/Settings/PaymentsPage/AccountStatusSection.tsx)
  • ActionsPopover.ActionsPopover (cognitive 26) (app/javascript/components/ProductsPage/ActionsPopover.tsx)
  • ActionsPopover.ActionsPopover (cyclomatic 22) (app/javascript/components/ProductsPage/ActionsPopover.tsx)
  • AdminSearchService.search_purchases (cognitive 44) (app/services/admin_search_service.rb)
  • AdminSearchService.search_purchases (cyclomatic 29) (app/services/admin_search_service.rb)
  • AffiliatesController.process_affiliate_params (cognitive 26) (app/controllers/affiliates_controller.rb)
  • AffiliatesController.process_affiliate_params (cyclomatic 25) (app/controllers/affiliates_controller.rb)
  • AgentChat.AgentChat (cognitive 181) (app/javascript/components/Agent/AgentChat.tsx)
  • AgentChat.AgentChat (cyclomatic 135) (app/javascript/components/Agent/AgentChat.tsx)
  • AgentChat.ProposedActionCard (cognitive 38) (app/javascript/components/Agent/AgentChat.tsx)
  • AgentChat.ProposedActionCard (cyclomatic 22) (app/javascript/components/Agent/AgentChat.tsx)
  • AgentController.create (cognitive 17) (app/controllers/api/mobile/agent_controller.rb)
  • AgentController.create (cyclomatic 17) (app/controllers/api/mobile/agent_controller.rb)
  • AgentConversationPersistence.action_payload_values_match? (cyclomatic 16) (app/controllers/concerns/agent_conversation_persistence.rb)
  • AgentConversationPersistence.claim_agent_action (cognitive 19) (app/controllers/concerns/agent_conversation_persistence.rb)
  • …and 1705 more

Changes since last survey

  • 300 commits — 278 feature/other, 22 fixes

By area

  • app/javascript — 76 commits
  • app/models — 37 commits
  • app/controllers — 34 commits
  • app/services — 34 commits
  • app/business — 18 commits
  • app/sidekiq — 10 commits
  • app/views — 10 commits
  • app/mailers — 8 commits
  • spec/controllers — 8 commits
  • config/initializers — 6 commits
  • (root) — 5 commits
  • app/modules — 4 commits
  • docker/web — 4 commits
  • spec/lib — 4 commits
  • .agents/skills — 3 commits
  • bin/branch-specs — 3 commits
  • public/images — 3 commits
  • spec/business — 3 commits
  • spec/requests — 3 commits
  • spec/services — 3 commits

Notable commits

  • fix: Fix 500 on refund when the purchase was never marked successful (#7861)
  • fix: Fix Claude MCP OAuth discovery scope mismatch (#7992)
  • fix: Fix Kindle help article 208: real approved sender address and the formats we actually send (#7955)
  • fix: Fix NoMethodError on the second transfer page in non-US refund fee retention (#7733)
  • fix: Fix flaky public file tests in LinksController (#7969)
  • fix: Fix help center article 292: drop the removed Facebook login, list the current methods (#7772)
  • fix: Fix incomplete Stripe Capital deductions (#7722)
  • fix: Fix the Stripe balance alert's all-clear, cutoff and sweep line (#7701)
  • fix: Fix unplayable M4A uploads with a leading ID3v2 tag, and tell the buyer when a file can't play (#7959)
  • fix: Floor commission completions at the balance the deposit fixed (#7747)
  • fix: Trim bug-history narration from the archived products redirect comment (#7831)
  • fix: fix(download): keep the Read button while a stamped PDF is being prepared (#7820)
  • fix: fix(download): make the Open in app subtitle store-neutral (#7798)
  • fix: fix(download): pass the store badge color through Button in the Open in app popup (#7797)
  • fix: fix(download): restamp an expired stamped PDF when the page renders (#7821)
  • fix: fix(mailers): read the review notification's purchase from the primary (#7825)
  • fix: fix(marketing): fail closed when the auto marketing flag read stalls (#7800)
  • fix: fix(payouts): season only the destinations a payout can select (#7823)
  • fix: fix(payouts): treat "No such external account" as a stale bank-account reference (#7758)
  • fix: fix(paypal): route refunds that fail after acceptance to the failed-refund queue (#7819)
  • …and 280 more

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

antiwork/gumroad was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 27 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit f7826abc99d7ac796397516d4ec631f0dae2aeb4 — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-7c1cb6328e11.