nafiswatsiq/subbase
Advanced subscription management for Laravel with a Filament admin panel. Build plans with multi-currency pricing and features, manage full subscription lifecycles, add promo codes and discounts, plus optional Spatie roles and custom models. Built on laravelcm/laravel-subscriptions.
Architecture fit. Subbase is a thin, opinionated presentation-and-extras layer sitting on top of laravelcm/laravel-subscriptions. The upstream package owns the domain: subscribing, canceling, swapping plans, feature checks, and usage counters. Subbase adds three things of real value — a Filament v5 admin surface, a multi-currency price resolver, and a discount/promo engine — plus translatable plan content and config-driven model swapping.
That means the architectural decision is really two decisions: do we accept laravelcm/laravel-subscriptions as our subscription domain model, and are we on Filament v5. If either answer is no, this package is not a candidate.
The most important scoping point for a TPM: this is not a billing system. There is no payment provider integration, no invoicing, no proration, no dunning, no tax handling, no webhook reconciliation. It manages plan catalog, entitlements, and subscription state — money movement is your problem. If the roadmap says "subscriptions," clarify whether it means "entitlement gating for a SaaS" (good fit) or "charge customers recurringly" (this is at most 30% of the build).
Integration feasibility. Mechanically easy: one composer require, php artisan subbase:install, migrate, a trait on User, and one ->plugin(SubbasePlugin::make()) line in the panel provider. A pricing page ships as <x-subbase::plan-list /> on day one. A competent Laravel dev gets a working demo in under a day on a greenfield app. The config surface (config/subbase.php) is genuinely well-chosen for a TPM's concerns — table names, model bindings, currency/locale mapping, and permission strings are all externalized rather than hardcoded.
Technical risk — rated High. Concretely:
| Signal | Reading |
|---|---|
| 6 stars, 0 dependents | No production user base to shake out bugs; you are an early adopter |
| Maturity: readme + releases only | No visible test suite, CI, or static analysis in the provided materials |
| Single maintainer | Bus factor of 1 |
| Version floors: PHP 8.2+, Laravel 13.7+, Filament 5.0+, laravelcm 1.8+ | The Laravel and Filament floors sit beyond the current stable release line — verify installability before anything else; this may be aspirational or a typo |
subbase:upgrade --force existing |
Author anticipates breaking-ish changes across releases; API is not frozen |
| Discount engine is homegrown | This is money-adjacent code written by the same single maintainer — the highest-risk surface in the package |
Risk also compounds transitively: you inherit the maintenance posture of laravelcm/laravel-subscriptions, which is itself a small package. Two small dependencies in series is not one small dependency.
Key questions to resolve before committing:
max_uses)?Stack fit. This is a Laravel + Filament shop package, full stop. It presupposes a Filament admin panel already exists and that you're willing to adopt Filament v5. Teams on Filament v3/v4, or on Livewire/Nova/custom admin, get dramatically less value — the Blade pricing component and models alone are not worth the upstream dependency. Teams not on Filament should evaluate laravelcm/laravel-subscriptions directly plus 2–3 weeks of custom UI.
Migration path. Two very different projects:
trial/active/canceled/expired; a currency backfill strategy for the multi-currency columns (base price → default currency); feature-name normalization between your current entitlement checks and Subbase features; and a reconciliation report proving no subscriber lost or gained access post-cutover. Budget 1–2 weeks including a dual-run period.Compatibility posture. Pin exact versions of Subbase, laravelcm/laravel-subscriptions, Filament, and Laravel in composer.json; do not float these. Add a CI job that installs the locked set on a clean image — this catches the "upstream released and we can't install" failure mode before it reaches a deploy. Track Filament major upgrades as explicit roadmap items, since Filament majors are where this package will break first.
Exit strategy is a design requirement, not a nice-to-have. Because the license is MIT and the package is small, forking is realistic. To keep the fork cheap: put every call into the subscription domain behind your own thin service interface (EntitlementService, PlanCatalog) rather than calling $user->subscribeTo() or PlanPriceHelper::resolveWithDiscounts() from controllers and views. If you later swap to Cashier, Stripe Billing, or a hardened fork, you rewrite one adapter instead of every call site. This costs about two days upfront and is the single highest-leverage architectural decision in this evaluation.
Sequencing with gates:
discounts / discount_plan / discount_subscription. Confirm column types for money (decimal precision, currency code storage), uniqueness on promo code, and indexes on discount lookup paths. Do not skip this.max_uses consumption. This is our code now regardless of who wrote it.plan-list.blade.php or build our own against PlanPriceHelper; wire the subscribe-route into our actual checkout.Maintenance. Assume we will contribute upstream or fork within 12–18 months. Plan for a named owner and a recurring monthly review of upstream releases — the subbase:upgrade command existing at all tells you the author expects churn. Budget roughly 0.1–0.2 FTE ongoing for dependency tracking and occasional patch porting. This is not a "install and forget" package given 6 stars and 0 dependents; there is no crowd absorbing the breakage for us.
Support. GitHub issues, discussions, and a wiki. No SLA, no commercial support, no security disclosure process documented in the provided materials. Escalation path is "we fix it." The wiki is referenced repeatedly but its contents aren't in the materials we have — validate that the docs actually exist and are current before the spike, because the README leans on the wiki and on the upstream package's README for core usage. Two hops to find out how to cancel a subscription is a real ramp-up tax.
Scaling. The admin panel is low-traffic; the frontend is not.
Plan::active() with features and currency prices, invalidate on admin write. Without this, the Blade component's "fetch active plans and features sorted by sort_order" pattern is an N+1 waiting to happen on a marketing page.spatie/laravel-translatable stores translations as JSON per column. Fine at plan-catalog scale (tens to low hundreds of rows); do not let it creep onto high-cardinality models.findByCode → isValid → appliesToPlan) needs a unique index on code and a composite index on is_active/starts_at/expires_at. Promo-code redemption is a classic race: two concurrent checkouts both read uses < max_uses and both pass. Enforce with a transactional decrement or a DB constraint, not markUsed() called by application code after the fact.Failure modes to instrument and alarm on:
getPriceForLocale() "returns the base price if the currency is not set." That's a reasonable default and a dangerous one — a EUR customer quietly charged a USD figure. Log every fallback and alert if fallback rate exceeds a threshold.trial → active → canceled → expired transitions are only as reliable as the scheduler that drives them. Without a cron/scheduled job, subscriptions sit in active past their end date and entitlements leak. Verify a scheduled transition command exists; if not, write one.config('subbase.permissions.*') when Spatie is present, falls back to Shield-style ViewAny:Plan names when the config is empty, and is ignored entirely when Spatie is absent. Three behaviors behind one switch is a privilege-escalation shape — test all three branches and make the intended one explicit in config.currency field), and min_amount interplay are the most likely place to ship a wrong number. Add a pricing regression test suite before the first promo goes live.laravelcm/laravel-subscriptions stops receiving Laravel compat bumps → we can't upgrade Laravel → we're pinned. Detect via the monthly dependency review; respond by forking.Ramp-up. For a mid-level dev already fluent in Laravel and Filament: ~2 days to productive, ~1 week to confident including the discount engine edge cases. For a dev without Filament experience: add 3–5 days, and the admin panel becomes a learning vehicle rather than a shortcut. TPM-level onboarding cost is the wiki-and-upstream-README archaeology described above — assign one person to write an internal "how we actually use this" page in week one, because it won't exist anywhere else.
Bottom line for the roadmap conversation: the opportunity score (39) is meaningfully higher than the overall score (20.5) — the idea of a batteries-included Filament subscription panel is valuable; this specific implementation is early-stage. Treat it as a credible accelerator for a greenfield Filament SaaS with entitlement-only needs, gated on a half-day install spike, behind an internal adapter interface, with a funded hardening sprint for the discount engine and a standing fork option. For payment-critical or brownfield-with-live-subscribers scenarios, budget the extra weeks or evaluate laravelcm/laravel-subscriptions + custom Filament resources directly.
How can I help you explore Laravel packages today?