Skip to content

Analytics & Reporting

Tashil's reporting comes in two layers, each for a different question:

  1. AnalyticsService — live aggregate metrics ("what is MRR right now?"). Computed with tpetry/laravel-query-expressions, so they're cross-database and batched, with no raw SQL.
  2. The event log + snapshots + usage logs — append-only history for "what was true on date X?". Used for audit, point-in-time queries, and replay.

Layer 1 — live aggregates

The entry point is Tashil::analytics(). Everything reads directly from the live tables — there are no materialized report tables to keep in sync.

Subscription metrics

MethodReturns
totalSubscriptionCount()All subscriptions, every status.
activeSubscriptionCount()Active + OnTrial.
subscriptionCountByStatus()One count per status.
subscribersByPackage()Active + trial counts grouped by plan.
trialConversionRate()Percentage of trials that reached Active.
subscriptionGrowth(int $months = 12)Monthly new-subscription counts.

Revenue & invoice metrics

MethodReturns
calculateMRR()All active + trial subs, normalized to monthly.
averageRevenuePerUser()MRR ÷ active count.
totalRevenue()Sum of paid invoice amounts.
revenueByPeriod(int $months = 12)Monthly revenue trend from paid invoices.
revenueByPackage()Revenue grouped by plan.
pendingInvoiceCount() / overdueInvoiceCount()Invoice health.

Churn

MethodReturns
churnRate(int $days = 30)Cancelled-in-window ÷ total.
churnTrend(int $months = 12, int $windowDays = 30)Batched — 2 queries total, computed in PHP.

One-shot dashboards

dashboardSummary() and packageAnalytics() consolidate the metrics above into one or two batched queries — use these in admin views to avoid N+1:

use Foysal50x\Tashil\Facades\Tashil;
 
$summary  = Tashil::analytics()->dashboardSummary();
$byPlan   = Tashil::analytics()->packageAnalytics();
 
// Individual metrics are available too:
$mrr      = Tashil::analytics()->calculateMRR();
$churn    = Tashil::analytics()->churnRate(days: 30);
$conv     = Tashil::analytics()->trialConversionRate();
$trend    = Tashil::analytics()->revenueByPeriod(months: 12);

Cached automatically

AnalyticsService reads through the cache decorator, so repeated dashboard loads are cheap. Writes that affect an aggregate invalidate the relevant keys. Turn caching off with TASHIL_CACHE_ENABLED=false — see Configuration.

Layer 2 — audit, replay, and point-in-time

When aggregates aren't enough — "what plan did this customer have on March 3rd, and how much had they used?" — the append-only tables are your source of truth.

The event log

Every transition writes a row to tashil_subscription_events (see Events). Read it per subscription:

$subscription->events()->get();                 // ordered by sequence_num
$subscription->events()->ofType('subscription.switched')->get();
$subscription->events()->upTo(now()->subWeek())->get();

Feature snapshots

Snapshots are immutable, so you can ask what features were in effect at any moment:

app(\Foysal50x\Tashil\Contracts\SubscriptionFeatureRepositoryInterface::class)
    ->asOf($subscription, now()->subDays(30));

Usage logs

Every increment, reset, report, and adjust is captured with previous_usage and new_usage, so you can reconstruct any counter at any moment, build histograms, or drive a usage-based billing system — without modifying Tashil. The trait's dailyUsageFor() is built on exactly this:

$user->dailyUsageFor('api-calls', days: 30);

Composing a point-in-time picture

To answer "what plan, with what features, with what usage did subscription S have at moment T?":

  1. Plan — walk subscription_events for S by sequence_num; take the last subscription.created or subscription.switched with occurred_at <= T. The payload carries the package id.
  2. FeaturesSubscriptionFeatureRepository::asOf($sub, $T).
  3. Usage — sum the usage_logs deltas where created_at <= T for each feature.

What Tashil does not report

These are intentionally out of scope — the event log and invoice rows are sufficient inputs to build them in a downstream tool:

  • Card-level revenue, chargebacks, and refunds executed by the gateway.
  • The MRR movement waterfall (new / expansion / contraction / churn / reactivation).
  • Cohort retention curves.
  • Multi-currency normalization with an FX rate table.
  • Coupon redemption attribution.

Tashil — Subscription management for Laravel. Released under the MIT license.