Releases: rameerez/profitable
Release list
v0.6.0
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: falsecharges do not count as revenue on SQLite. - Pay 7-9 data-only charge schemas are supported again; revenue queries no longer reference
pay_charges.objectunless that column exists. - Processor status handling is stricter:
expirednow churns atends_at, andpendingis never billable. - Paused subscriptions now preserve their historical subscriber/customer lifecycle while staying out of current MRR when paused.
Profitable.time_to_next_mrr_milestonenow returns aProfitable::NumericResult, so the documented.to_readableAPI 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, anddaily_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: falsecharge payloads being counted on SQLite because SQLite returns JSON booleans as0/1instead of text. - Fixed Pay 7-9 compatibility for apps whose
pay_chargestable only hasdataand notobject. - 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::Errormessages being double-wrapped during MRR snapshot delegation.
API And Documentation
- Added
Profitable.mrr_at(date)for historical MRR snapshots. - Kept raw
calculate_mrr_atprivate so public metric methods consistently returnProfitable::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
0to amount-derived MRR metrics unless apps backfill processor subscription payloads intopay_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/actionviewrequirements and declaredactionviewas 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.
expiredsubscriptions no longer inflate active/billable metrics forever.pendingsubscriptions 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 buildsucceeds and buildspkg/profitable-0.6.0.gemlocally.
GitHub Generated Notes
What's Changed
Full Changelog: v0.5.0...v0.6.0
v0.5.0
What's New
- Add
Profitable.ttm_revenuefor trailing twelve-month revenue - Add
Profitable.ttmas a founder-friendly alias forttm_revenue - Add
Profitable.revenue_run_rate,estimated_arr_valuation,estimated_ttm_revenue_valuation, andestimated_revenue_run_rate_valuation - Make revenue metrics net of refunds when
amount_refundedis present - Make subscriber and MRR metrics distinguish between current billable subscriptions and historical period events
- Count
new_customersfrom first monetization date rather than signup date - Count
new_subscribers/new_mrrfrom when a subscription becomes billable, not when a free trial starts - Handle additional Pay status variants like
on_trial,cancelled, anddeleted - 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.rbfor cleaner architecture
Full Changelog: v0.4.0...v0.5.0
What's Changed
Full Changelog: v0.4.0...v0.5.0
v0.4.0
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_mrrwas countingincomplete,incomplete_expired, andunpaidsubscriptions — now only countsactivenew_subscriberswasn't filtering outtrialing/pausedsubscriptions- Status constants moved to module level so
MrrCalculatorcan 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_perioddelegation subscriptions_with_processorhelper 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
v0.2.2
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 forestimated_valuation, like (estimated_valuation(at: "3x") - Add
multiple:parameter as another option forestimated_valuation(same asat:, just syntactic sugar) - Now
estimated_valuationalso supportsNumeric-only inputs likeestimated_valuation(3)
🎉 Initial release!
Provides essential methods to calculate SaaS metrics like MRR, ARR, LTV, ARPC, estimated valuation, churn, etc. – with a simple dashboard to display them.