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

Tomato Saas Module Laravel Package

tomatophp/tomato-saas-module

A SaaS subscription module for TomatoPHP that adds plan management, tenant subscriptions, and billing scaffolding to Laravel apps, letting you define plans, attach them to accounts, and manage recurring access from a ready-made admin panel.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a Laravel-native TomatoPHP module that supplies the "undifferentiated middle" of a subscription SaaS: tenant records, a plan catalog, subscription state, and entitlement scaffolding, surfaced through Filament admin resources. Architecturally it presumes two prior commitments: a Laravel app on the TomatoPHP/Filament admin stack, and the package's own tenancy model (its published migrations are the de facto decision between shared-database-with-discriminator and database-per-tenant). This is therefore an architecture decision disguised as a dependency — it should be evaluated and signed off as such, not merged as a library. Fit is strong for a greenfield or lightly customized Laravel app with no incumbent tenant model; fit is poor for anything already carrying tenant scoping, and near-zero for non-Filament front ends (Inertia/Vue, bespoke admin, API-only), where the shipped value is concentrated in the UI we would discard.

Integration feasibility. Mechanically trivial: composer require, publish config and migrations via --provider=, migrate. The real work is not installation but the boundary design around it — a single entitlement gate (Gate::define or a FeatureGate service), a tenant-context service injected from the container rather than read ad hoc from the request, a BillingProvider contract that keeps our PSP, dunning, tax, and invoicing entirely out of the module, and explicit tenant binding at the top of every queued job and artisan command. Plans should be seeded and referenced by slug, never by ID, so dev/staging/prod converge. None of this is hard, but all of it is ours to build; the package does not supply the enforcement layer that ties its records to our domain models.

Technical risk. The dominant risk is not functionality but provenance. v1.0.0 shipped with no changelog beyond a commit-list link, no migration notes, no backward-compatibility commitments, one GitHub star, zero dependents, a single maintainer, and a last release of March 2024. In a component whose failure mode is cross-tenant data exposure, that is not a foundation to put customer data behind absent a deliberate, resourced bet. Specific failure modes we are underwriting: global-scope defects that silently return another tenant's rows (or, more often, silently return null and present as a 404); tenant context lost in queues and console commands, causing writes to the default tenant; cache and session keys colliding across tenants, invisible in development and surfacing in production as wrong data; and middleware ordering regressions after Filament/Livewire majors that disable or double-apply scopes. Secondary risks: upgrade surprises (pin the exact version — no caret), and our own test suite being the only documentation we can rely on.

Key questions.

  • Is our admin surface actually Filament/TomatoPHP today, or aspirational? If aspirational, the value proposition collapses.
  • Do we have an incumbent tenant model or scoping anywhere in the codebase? If yes, this is likely disqualified by dual ownership of the highest-risk boundary.
  • What tenancy strategy does the migration schema actually commit us to, and does that match the product's isolation, compliance, and per-tenant cost model?
  • Who owns the adversarial tenancy test suite, and is that headcount available before — not after — customer data lands?
  • Does our procurement or compliance posture require vendor support, an SLA, or a security disclosure policy? A community-only, single-maintainer project fails all three.
  • Is the 4–8 weeks of tenancy/plan/entitlement groundwork genuinely undifferentiated for our business, or is it a competitive asset we would rather own?

Integration Approach

Stack fit. Adopt only if the target app is Laravel + TomatoPHP/Filament and tenancy does not yet exist. The bundled plan, tenant, and subscription resources are real back-office CRUD surface we would otherwise spec, design, and build — that is the bulk of the shipped value and the reason "adopt the migrations, drop the UI" is the worst available cost/benefit ratio. Where the admin surface is Inertia/Vue or API-only, prefer stancl/tenancy or spatie/laravel-multitenancy: larger install bases, documented tenancy strategies, and years of production exposure on a security boundary.

Migration path. Greenfield is the clean path: publish config and migrations, run them, and treat the resulting schema as our contract. Read migrations first, then config (model bindings, feature/limit definitions, middleware aliases, billing hooks), then the tenant-resolution middleware, then the Filament resources. Seed plans via a PlanSeeder and reference by slug. For single-database tenancy, ensure domain models carry the package's global scope and reserve withoutGlobalScope for genuinely cross-tenant code (admin reports, exports, backfills). For multi-database tenancy, wrap artisan migrate in a loop over tenants inside the deploy script and never assume one run covers everyone. Publish tags should be confirmed via --provider= rather than guessed, since a wrong tag is a silent no-op that leaves a stale config in place.

Compatibility. Pin "tomatophp/tomato-saas-module": "1.0.0" exactly until we have reviewed the commit history ourselves. Mirror the repository internally so an upstream deletion or force-push cannot strand us. Treat Filament/Livewire majors as breaking changes for tenancy: re-run the adversarial suite after every upgrade before deploy. Keep billing behind our own BillingProvider interface (subscribe, cancel, findSubscription, handleWebhook) so PSP swaps and idempotency handling never force a fork, and so webhook events map onto package subscription records inside a service we control.

Sequencing. Run a time-boxed 3–5 day spike, not an adoption decision. Order of work: (1) install in a throwaway branch and confirm publish tags; (2) read migrations, config, and tenant-resolution middleware and write up the tenancy model; (3) prove tenancy before touching billing — seed two tenants, register the middleware on a route group, hit routes under each subdomain, and confirm Model::find($otherTenantId) returns null; (4) stand up the adversarial suite covering cross-tenant reads, job context serialization, cache-key isolation, and unauthenticated routes outside the middleware group; (5) only then design the entitlement gate and billing interface; (6) integrate a real PSP last. If step 3 or 4 fails, we exit the spike having spent a week and having learned our tenancy requirements in detail — which we needed regardless.

Operational Impact

Maintenance. We own the upgrade risk outright. With no changelog and no BC guarantees, the only dependable signal on a version bump is a diff of the migrations directory plus a re-read of the tenant-resolution middleware; the documented process should be "diff, read, re-run adversarial tests, then merge." Because we extend and wrap rather than edit vendor files, composer update will not erase our work, and our own Filament resources can be registered alongside the package's. Budget ongoing engineering time for this — a pinned, internally mirrored, single-maintainer dependency is not a set-and-forget. The offsetting benefit is real: pricing experiments (adding a tier, moving a feature between plans) become config and seed changes routed through one entitlement gate rather than grep-and-replace engineering projects, which materially de-risks the "introduce tiered pricing" roadmap item.

Support. Community-only, single-maintainer, no SLA, no documented security disclosure policy. Our incident response is bounded by our own ability to read the source, which is a reasonable position for a small team that has deliberately resourced the read — and an unacceptable one if procurement, compliance, or an enterprise customer requires vendor accountability. State this boundary explicitly in the PRD so it is a recorded decision rather than a surprise during diligence.

Scaling. The package's scaling characteristics are the tenancy model's characteristics, so the schema review is also the capacity review: shared-database tenancy concentrates noisy-neighbor and per-tenant data-volume risk in one place, while database-per-tenant multiplies migration and connection overhead across the fleet. Neither is disqualifying, but the choice should be made against our expected tenant count, data volume distribution, and isolation commitments. Enforcement at a single gate keeps limit checks cheap and consistent as tier count grows; per-check ad hoc queries are where this degrades.

Failure modes. Ranked by blast radius: (1) cross-tenant data exposure via a missing or misordered global scope — a security incident, not a bug; (2) silent cross-tenant writes from queued jobs and artisan commands that wake without tenant context and fall back to the default tenant; (3) tenant-scoped find() returning null for another tenant's ID, presenting as a 404 and consuming debugging time on phantom "missing data"; (4) cross-tenant cache and session collisions surfacing only in production; (5) middleware-ordering regressions after Filament upgrades that quietly disable scoping. Two debugging moves resolve most of these: log the resolved tenant inside the resolution middleware, and wrap the failing query in DB::listen to confirm the tenant_id = ? predicate is actually present. A TenantScopedModel::find($otherTenantId) returning null is the expected behavior, not evidence of a defect.

Ramp-up. Low for anyone fluent in Laravel and Filament — install and first tenant are hours, not weeks. The non-obvious learning is concentrated in three places: the tenancy model as encoded in migrations, the resolution middleware as the security boundary, and the discipline of explicit tenant context in every job and command. Because upstream publishes no test coverage and no documentation beyond a description, our adversarial suite is the documentation and the onboarding artifact; the first engineer's ramp-up task should be writing it. The pitch that survives scrutiny is not "buy this product" but "avoid spending a quarter reinventing tenancy and plan gating" — conditional on the spike passing and on our owning a test suite around tenant isolation before any customer data is scheduled against it.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels