opcodesio/spike
Spike is a Laravel performance monitoring package that helps you spot bottlenecks by tracking slow requests, queries, and exceptions in a built-in dashboard, making it easier to diagnose issues and keep your application running smoothly.
Spike is a billing/subscription layer for Laravel: you define plans, mark a model as billable, and gate features or meter usage against a subscription. The free edition (opcodesio/spike-free) is the MIT-licensed core, so treat the Pro edition's marketing pages as documentation for concepts, not for API surface — verify every class and config key against src/ in this repo before you design around it.
Day-one sequence:
composer require opcodesio/spike
php artisan vendor:publish --provider="Opcode\\Spike\\SpikeServiceProvider"
php artisan migrate
Then read, in this order:
config/spike.php — this is the contract. Plans, feature list, currency, payment driver and webhook settings live here. If something is missing from config, it usually isn't supported.src/Models and src/Traits — tells you exactly which contract your User model must satisfy and what the billable trait gives you.A good first use case is the smallest one that exercises the whole loop: one paid plan, one gated route, one Stripe test-mode checkout. Get subscribe → webhook → entitlement check working end-to-end before you model tiers or usage. Billing packages fail at the seams (webhook delivery, period boundaries), not in the happy path you can read in the source.
Config-driven plan catalogue. Define plans and their features in config/spike.php rather than in the database. It gives you version control, easy diffing between environments, and no seeding step in CI. Keep the plan identifiers stable strings — they will end up in your database and in Stripe metadata, and renaming them later means a data migration.
Entitlement checks at the boundary, not in views. Wrap feature checks in a single application service (e.g. Billing::can($user, 'exports')) or a Gate definition, then call that from middleware, policies and jobs. Never call the package directly from Blade — when you migrate to Pro or swap providers, you want one seam to change. Cache the resolved entitlement per request; a check inside a loop is a query per iteration.
Middleware for tier-gated areas, policies for object-level rules. Route groups get ->middleware('spike.plan:pro')-style guards; per-record limits (seats, projects, API keys) belong in a policy or a creating model observer that throws a domain exception, not a 403 from a controller.
Usage metering as an event, not an increment. If the package exposes a usage recorder, call it from a queued listener on your domain events (ExportGenerated, ApiCallMade) rather than inline in the request. That decouples the write path, lets you retry, and keeps the meter consistent when the main action is retried or rolled back. Use DB::transaction for the business write and dispatch the metering event after commit.
Webhook handling is the real integration. Point the package's webhook route at an excluded-from-CSRF path, keep the secret in .env (never in config committed to git), and forward to a queue. In local dev, use the Stripe CLI to replay events; in staging, replay a captured fixture set. Treat the webhook as the source of truth for subscription state and treat your checkout redirect as merely cosmetic.
Testing. Fake the gateway at the HTTP layer (Http::fake() on the provider's API host) and assert on your state, not the package's internals. Keep a small set of fixture payloads for customer.subscription.updated and invoice.payment_failed — those two events cover most of the bugs people ship.
src/ for what's actually implemented before promising a feature; if a capability is missing, plan the workaround (a small custom table keyed on the subscription) rather than assuming an upgrade path.composer.json, read the diff of every bump, and avoid extending internal classes — extend via your own wrapper so a refactor upstream doesn't break you.config('app.timezone'). Any "resets on the 1st" logic you write must align with the provider's period fields, or usage will double-count or vanish for a few hours each month.updated_at comparison, and never assume subscription.updated arrives before invoice.paid.users columns or indexes. Run them on a fresh copy of production data early, not the week before release.How can I help you explore Laravel packages today?