Speeding Up Laravel Tests with tmpfs (MySQL in RAM)
If your Laravel test suite is painfully slow and does a lot of database work (multi-tenancy, migrations, seeding), the bottleneck is almost…
I recently investigated whether I should (or needed to) add soft deletes to my Laravel Spark-based billing system.
Laravel Spark for Paddle is a higher-level layer on top of Laravel Cashier Paddle.
Spark provides a billing portal out of the box, while Cashier handles most of the underlying payment logic and Eloquent models.
When you look at Spark’s codebase, you’ll see migrations for tables such as:
customerssubscriptionssubscription_itemstransactionsBut you won’t see Eloquent models named Customer, Subscription, etc. That’s because Spark defers to the actual Eloquent models defined in Laravel Cashier Paddle. Specifically:
Laravel\Paddle\Customer maps to the customers table.Laravel\Paddle\Subscription maps to subscriptions.Laravel\Paddle\Transaction maps to transactions.Laravel\Paddle\SubscriptionItem maps to subscription_items.Spark simply publishes and references the same migrations that Cashier needs. That explains why Spark’s repository lacks explicit model files even though migrations exist: they live in the Cashier Paddle package.
Billable Trait
Typically, your User model uses the Laravel\Paddle\Billable trait. This trait ties your user to the Customer, Subscription, Transaction, and SubscriptionItem models. You get methods like $user->subscriptions() or $user->transactions() for free.
Database Tables
Cashier’s Eloquent models store all billing and subscription data in a standard set of tables (customers, subscriptions, etc.). Each row includes status columns like status, timestamps for trial_ends_at, paused_at, ends_at, and so on.
Webhook Synchronization
When a user subscribes or completes a checkout, Paddle sends webhook events. The WebhookController in Cashier processes these events, updates local Eloquent models, and fires events like SubscriptionCreated, SubscriptionCanceled, etc.
By default, neither Spark nor Cashier Paddle implements soft deletes—there is no deleted_at column in the migrations, and the Eloquent models don’t include SoftDeletes.
In subscription/payment systems, the common practice is to keep a permanent ledger of historical data for regulatory and compliance reasons. Even if someone cancels a subscription or if a user is “removed,” the subscription and transaction records remain in the database.
Instead of soft deleting, the code uses status fields such as status = 'canceled' and timestamps like ends_at or paused_at. This allows your app to cleanly check if a subscription is active, canceled, trialing, or paused, without actually removing any record from storage.
Transactions in particular are almost always kept forever so that you can reference them for tax calculations, auditing, invoice lookups, or user support.
So the answer is, no we don't need soft deletes here as the system is already set up to keep historical data, just not using soft deletes for this.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com