Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Cashier Overview Laravel Package

limedeck/nova-cashier-overview

A Laravel Nova tool that adds a Cashier overview dashboard to your admin panel, surfacing subscription metrics, revenue, and billing status at a glance. Track recurring payments, customers, and plan performance without leaving Nova, so you can keep an eye on your SaaS finances.

View on GitHub
Deep Wiki
Context7

Getting Started

Prerequisites (all four, or don't bother): Laravel + Laravel Nova (licensed) + Laravel Cashier + Stripe, with a populated subscriptions table. If any one is missing, the cost of adding it outweighs a single dashboard card.

Install:

composer require limedeck/nova-cashier-overview

The package was last tagged in September 2022, so expect a constraint fight on modern stacks. If Composer refuses to resolve, do not immediately --ignore-platform-reqs; check the package's composer.json first:

cat vendor/limedeck/nova-cashier-overview/composer.json

That file is your compatibility map for laravel/framework, laravel/nova, laravel/cashier, and php constraints.

Register the card in app/Providers/NovaServiceProvider.php:

use Laravel\Nova\Http\Requests\NovaRequest;

public function cards(NovaRequest $request)
{
    return [
        // class name/namespace may differ — confirm in vendor/limedeck/.../src
        (new \Limedeck\NovaCashierOverview\CashierOverview)
            ->width('1/2'),
    ];
}

Publish and build assets (if the package ships config/JS/CSS):

php artisan vendor:publish --provider="Limedeck\NovaCashierOverview\CardServiceProvider"
php artisan nova:publish
php artisan optimize:clear

If the provider name in that command errors, run php artisan vendor:publish with no arguments and pick the package from the list.

Where to look first — in this order:

  1. vendor/limedeck/nova-cashier-overview/src/ — the card class, its component(), and any metric/resolver classes. This is the entire documentation for a package this size.
  2. The config file (if published) — caching, currency, and which models are queried.
  3. Any dist/js/card.js — confirms whether metrics come from the server (/nova-api/...) or the browser calls Stripe directly.

First use case — the one that justifies the install: put the card on a dedicated "Billing" dashboard visible only to support/finance, and use it as a triage surface. Support opens it, sees MRR and active/trialing/canceled counts, then clicks through to the actual Nova Subscription/User resource for the specific account. The card answers "how is the business doing," the resource answers "what about this customer." Don't try to make the card do both.


Implementation Patterns

Give it its own dashboard, not the main one. A Nova Main dashboard mixed with system health metrics trains people to ignore the card. Create a scoped dashboard instead:

// NovaServiceProvider
public function dashboards(NovaRequest $request)
{
    return [
        \App\Nova\Dashboards\Billing::make()
            ->canSee(fn ($request) => $request->user()->isBillingStaff()),
    ];
}

Gate the card, don't rely on dashboard hiding alone. Cards render through Nova's API endpoints; a hidden dashboard is not authorization. Use canSee on the card and, if the package exposes a route, wrap it with your own middleware.

(new CashierOverview)->canSee(fn ($request) => $request->user()->can('viewBillingMetrics'))

Seed realistic local data before you evaluate it. An empty card tells you nothing. Use Stripe test clocks or seed the subscriptions table directly with a spread of states — you need at minimum: active, trialing (with trial_ends_at in the future), active with ends_at set (cancel-at-period-end), past_due, and canceled. Reconcile every number on the card against the Stripe Dashboard for the same test account before you show it to anyone.

Pair the card with a Cashier-backed Nova Resource. The card is an aggregate; the workflow needs a detail view. A minimal Subscription resource on Laravel\Cashier\Subscription (or your own model) with stripe_status, stripe_price, quantity, trial_ends_at, ends_at, and a stripe_id link out to https://dashboard.stripe.com/subscriptions/{id} is what turns the card into a usable tool.

Cache deliberately, and know what you're caching. For day-to-day support use, a 5–15 minute TTL is fine. For a finance reconciliation workflow it is not. If the config exposes a TTL, set it explicitly in config/nova-cashier-overview.php rather than accepting the default, and prefer a short TTL over a fast dashboard — stale MRR shown to a CFO is worse than a spinner.

Read-only is the expectation, verify it anyway. Before production, grep the source for ->cancel(, ->resume(, ->swap(, or any Stripe\ client call used for mutation. If any exist, gate them behind a policy plus audit logging, and confirm which Stripe key each environment is using (STRIPE_KEY vs STRIPE_SECRET and test vs live).

Fork-and-vendor rather than patch in place if constraints don't resolve. Clone it, widen composer.json, and require it via a VCS path repository. That converts a 2022 abandoned dependency into code you own — which is the honest end state for a package with zero dependents and no release in three years.


Gotchas and Tips

MRR definitions will not match your finance team's. Check whether the package normalizes annual plans to monthly, includes trialing subscriptions, applies coupons/discounts, or accounts for proration. Whatever it does, document it next to the card. Two different MRR numbers in one company destroys trust in the tool faster than no tool.

ends_at is not "canceled." Cashier sets ends_at when a user cancels at period end — the subscription is still active and still billing until that date. A card that counts ends_at IS NOT NULL as churn will overstate churn every single month. Similarly, trialing with trial_ends_at in the past but no webhook processed yet is a webhook-lag artifact, not a live trial.

Webhook lag is the dangerous failure mode. Local Cashier tables are eventually consistent with Stripe. The card can show "active" for a subscription Stripe already canceled — and it looks like success, so nobody investigates. Keep the Stripe Dashboard as the documented tiebreaker and put that in the support runbook.

Assets go stale silently. After any composer update, Nova upgrade, or JS rebuild, re-run php artisan nova:publish and hard-refresh. A card that renders an empty white box after a deploy is almost always a stale mix-manifest / dist asset, not a backend error.

Debugging an empty or erroring card, in order:

  1. storage/logs/laravel.log and Nova's network tab — is the card's API request 200, 403, or 500?
  2. Stripe keys present and correct mode for the environment (sk_test_ in staging)?
  3. Is it reading local tables or hitting the Stripe API? Rate limits and expired API versions both produce empty results rather than loud errors.
  4. Multi-billable-model setups (Billable on User and Team) — confirm which model the card queries. A card showing zero on a tenant-scoped app usually means it's querying a model with no rows.
  5. Timezone: whereDate-style filters on created_at in UTC vs app timezone shift month boundaries and quietly break growth/churn trend charts.

Nova authorization is per-resource by default, not per-card. Adding the card to a dashboard does not inherit any policy. Explicitly canSee it, and check whether the card leaks customer names/emails/revenue into the browser payload for users who shouldn't see them — inspect the network response, not just the rendered UI.

Upgrade checklist entry. Add this card to your Nova/Laravel upgrade regression list. It is the single most likely thing to break during a Nova major upgrade, and because it's a dashboard card rather than a route, breakage is discovered by a human noticing a blank box rather than by a failing test.

Plan the exit on day one. Keep the feature-flagged registration (if (config('features.billing_card'))) so you can switch it off without a deploy, and tell support the fallback is the Stripe Dashboard. If the card ever sits on the critical path of a billing operation, remove it — it's a visibility accelerator, not a billing engine.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource