Skip to content

Releases: rameerez/profitable

v0.6.0

Choose a tag to compare

@rameerez rameerez released this 23 Jun 02:37
c321316

profitable v0.6.0 is an accuracy-focused production release for the Pay-powered metric layer. Every metric was re-audited against the data Pay 7.x-11.x actually stores, with regression coverage for the bugs found along the way.

This release intentionally changes user-visible numbers where previous calculations were wrong. Apps with meaningful trial volume, paused subscriptions, SQLite charge payloads, or Braintree/Lemon Squeezy subscription statuses should review the behavior notes below.

Highlights

  • Canceled trials that never converted no longer count as subscribers, customers, new MRR, churned MRR, churn, or dashboard summary activity.
  • Monthly churn rates no longer suffer from survivor bias: denominators now include subscribers who churn later inside the reporting window.
  • Monthly and daily summaries no longer count future trial conversions before they actually happen.
  • SQLite charge filtering now treats JSON booleans consistently with PostgreSQL/MySQL, so paid: false charges do not count as revenue on SQLite.
  • Pay 7-9 data-only charge schemas are supported again; revenue queries no longer reference pay_charges.object unless that column exists.
  • Processor status handling is stricter: expired now churns at ends_at, and pending is never billable.
  • Paused subscriptions now preserve their historical subscriber/customer lifecycle while staying out of current MRR when paused.
  • Profitable.time_to_next_mrr_milestone now returns a Profitable::NumericResult, so the documented .to_readable API works.
  • Added Profitable.mrr_at(date) as the public historical MRR snapshot API.

Metric Correctness Fixes

  • Fixed canceled trials polluting total_subscribers, total_customers, new_customers, new_subscribers, new_mrr, churned_customers, churned_mrr, churn, monthly_summary, and daily_summary.
  • Fixed churned subscriptions being removed from earlier monthly churn denominators when they churned mid-window.
  • Fixed future trial conversions appearing early in current-month/current-day summaries.
  • Fixed paid: false charge payloads being counted on SQLite because SQLite returns JSON booleans as 0/1 instead of text.
  • Fixed Pay 7-9 compatibility for apps whose pay_charges table only has data and not object.
  • Fixed paused lifecycle semantics so historical customer/subscriber counts and current MRR answer different questions correctly.
  • Fixed sub-dollar positive MRR being treated as “No MRR yet” in milestone messaging.
  • Fixed monthly churn denominator boundary behavior to match the inclusive period-start semantics used by churn.
  • Fixed existing Profitable::Error messages being double-wrapped during MRR snapshot delegation.

API And Documentation

  • Added Profitable.mrr_at(date) for historical MRR snapshots.
  • Kept raw calculate_mrr_at private so public metric methods consistently return Profitable::NumericResult.
  • Documented that Stripe is the only processor with subscription amount payloads stored locally by Pay out of the box.
  • Clarified that Braintree/Paddle subscriptions contribute 0 to amount-derived MRR metrics unless apps backfill processor subscription payloads into pay_subscriptions.object.
  • Corrected the stale README reference to Profitable.valuation_estimate.

Internal Cleanup

  • Consolidated churn-event queries into one helper.
  • Consolidated MRR “now” and MRR “at date” paths so current MRR and growth-rate snapshots cannot drift.
  • Centralized subscription payload lookup in Processors::Base.subscription_data.
  • Added schema-aware and memoized charge payload column detection.
  • Changed raw SQL subscription joins to Active Record association joins where appropriate.
  • Added direct delegate / actionview requirements and declared actionview as a gem dependency.
  • Removed the full top-level require "rails"; the gem now uses narrower direct dependency requires.

Behavior Notes

This release is expected to change metric outputs for some apps. These changes are corrections, not cosmetic formatting updates:

  • Trial-only cancellations disappear from paid subscriber/customer and churn metrics.
  • expired subscriptions no longer inflate active/billable metrics forever.
  • pending subscriptions no longer contribute to MRR-style or active subscriber metrics.
  • Paused subscriptions can still count historically after they became billable, but they are excluded from current MRR while paused.
  • Charge-based metrics are portable across Pay processors because Pay stores real charge amounts locally.
  • Amount-derived subscription metrics are fully supported out of the box for Stripe. Braintree/Paddle amount parsing requires local subscription payload backfills.

Verification

  • Default suite on the merged release commit: 338 runs, 520 assertions, 0 failures.
  • Local appraisal matrix green: Pay 7.3, 8.3, 9.0, 10.0, 11.0; Rails 7.2, 8.1.
  • GitHub Actions test matrix green across Ruby 3.3, 3.4, and 4.0 combinations.
  • Line coverage: ~97.75%; branch coverage: ~89.9%.
  • bundle exec rake build succeeds and builds pkg/profitable-0.6.0.gem locally.

GitHub Generated Notes

What's Changed

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@rameerez rameerez released this 19 Mar 18:11

What's New

  • Add Profitable.ttm_revenue for trailing twelve-month revenue
  • Add Profitable.ttm as a founder-friendly alias for ttm_revenue
  • Add Profitable.revenue_run_rate, estimated_arr_valuation, estimated_ttm_revenue_valuation, and estimated_revenue_run_rate_valuation
  • Make revenue metrics net of refunds when amount_refunded is present
  • Make subscriber and MRR metrics distinguish between current billable subscriptions and historical period events
  • Count new_customers from first monetization date rather than signup date
  • Count new_subscribers / new_mrr from when a subscription becomes billable, not when a free trial starts
  • Handle additional Pay status variants like on_trial, cancelled, and deleted
  • Keep grace-period subscriptions billable until ends_at
  • Exclude metered Stripe items from fixed run-rate MRR calculations
  • Surface TTM revenue in the built-in dashboard
  • Extract shared metric logic to lib/profitable/metrics.rb for cleaner architecture

Full Changelog: v0.4.0...v0.5.0

What's Changed

  • Add TTM revenue and tighten metric semantics by @rameerez in #9

Full Changelog: v0.4.0...v0.5.0

v0.4.0

Choose a tag to compare

@rameerez rameerez released this 10 Feb 00:06

What's New

Monthly & Daily Summary Tables — The dashboard now shows a 12-month summary table (new/churned subscribers, MRR, churn rate per month) and a 30-day daily summary table. Available via Profitable.monthly_summary and Profitable.daily_summary.

period_data method — New Profitable.period_data(in_the_last:) returns all period metrics (new_customers, churned_customers, churn, new_mrr, churned_mrr, mrr_growth, revenue) in a single efficient call.

Bug Fixes

  • new_mrr was counting incomplete, incomplete_expired, and unpaid subscriptions — now only counts active
  • new_subscribers wasn't filtering out trialing/paused subscriptions
  • Status constants moved to module level so MrrCalculator can reference them

Performance

Dashboard optimized from ~176 queries to 38 per page load:

  • Monthly summary: 72 → 5 queries (bulk load + Ruby grouping)
  • Daily summary: 60 → 2 queries
  • Period cards: 27 → 18 queries (via period_data)
  • Controller precomputation eliminates redundant calls from the view

Code Quality

  • 5 period methods DRY'd via _in_period delegation
  • subscriptions_with_processor helper eliminates repeated join/select/include chains
  • Test helper fully synced with production code
  • 249 tests, 382 assertions, 94.64% coverage

What's Changed

  • Add Claude Code GitHub Workflow by @rameerez in #7
  • Fix bugs, DRY up code, add monthly/daily summaries, and optimize dashboard (~176 → 38 queries) by @rameerez in #8

Full Changelog: v0.3.0...v0.4.0

v0.3.0

Choose a tag to compare

@rameerez rameerez released this 01 Jan 18:40

What's Changed

  • Add Pay v10+ support, comprehensive test suite, and critical bugfixes by @rameerez in #6

Full Changelog: v0.2.2...v0.3.0

v0.2.2

Choose a tag to compare

@rameerez rameerez released this 01 Sep 01:16

Fix bad calculations; add syntactic sugar:

  • Improve MRR calculations with prorated churned and new MRR (hopefully fixes bad churned MRR calculations)
  • Only consider paid charges for all revenue calculations (hopefully fixes bad ARPC calculations)
  • Add at: parameter as a named parameter option for estimated_valuation, like (estimated_valuation(at: "3x")
  • Add multiple: parameter as another option for estimated_valuation (same as at:, just syntactic sugar)
  • Now estimated_valuation also supports Numeric-only inputs like estimated_valuation(3)

🎉 Initial release!

Choose a tag to compare

@rameerez rameerez released this 31 Aug 16:29

Provides essential methods to calculate SaaS metrics like MRR, ARR, LTV, ARPC, estimated valuation, churn, etc. – with a simple dashboard to display them.