tomatophp/tomato-ecommerce
Tomato Ecommerce is a Laravel package for TomatoPHP that adds product catalogs, carts, checkout, and order management to your app, with Filament admin integration for handling products, orders, and store settings.
Architecture fit. The package is an admin-panel-first commerce module, not a headless commerce engine. Its models, migrations, and resources are shaped around Filament and the TomatoPHP module loader. That is a strong fit only if our monolith already runs Filament and we are prepared to keep running it — the package borrows our admin panel rather than shipping its own. If our roadmap implies an API-first storefront, a multi-vendor marketplace, or multi-tenant commerce, this is a mismatch and should be closed out early rather than carried as a "maybe."
Where it fits, it fits a specific slot: catalog, cart persistence, order records, and back-office CRUD in weeks instead of quarters. The description claims products/categories, cart and checkout flow, order management, and Filament integration. Treat every one of those as vendor-claimed, needs verification. The release history provides no evidence of what is genuinely implemented — payments, tax, shipping rates, refunds, and inventory reservation are almost certainly ours to build, and the package itself frames the boundary as "extensible architecture for custom pricing, payments, and workflows."
Integration feasibility. Technically straightforward in a Laravel/Filament host: Composer install, publish config and migrations, run migrations, walk the golden path in Filament. Integration risk is not in the install; it is in (a) brownfield schema collisions if we already own products, carts, or orders tables, and (b) version lockstep across the tomatophp/* family against a shared Filament constraint.
Technical risk. Ranked by expected cost:
tomatophp/* package to exact tags, and rehearse family upgrades on a branch with the panel clicked through.git diff on src and database, and a two-second git show <tag> -- composer.json to catch hidden constraint bumps. This is a recurring, non-zero time tax we must budget as a line item.Key questions (answerable in a one-week timeboxed spike in a throwaway app, producing a capability matrix plus a schema diff — not a demo):
php, laravel/framework, and filament/filament ranges, and do they intersect with ours?Stack fit. Laravel + Filament + TomatoPHP admin. Keep the package's models as persistence and put a thin application-level service (App\Services\CheckoutService) between our controllers and the vendor models. That service is the blast radius absorber for upstream patches — cheap insurance given the release cadence.
Migration path. Two viable paths, and we pick one explicitly and write it down:
HasOne order profile) rather than editing published files. Never edit a published migration — the next upgrade silently reverts it.orders, the honest recommendation is often to close this evaluation rather than reconcile two sources of truth.Compatibility. Pin tomatophp/tomato-ecommerce:1.0.8 exactly — no caret range. Commit the lockfile change on its own branch so a Filament/Laravel constraint conflict fails in isolation instead of inside a feature PR.
Sequencing. Back office first, storefront second. Phase one is operational and low-risk: catalog management, order visibility, manual fulfillment, internal tooling. Phase two is customer-facing checkout, gated on the payment/tax/shipping adapters being real. That order matches both the package's architecture and the risk profile — the expensive unknowns are all on the customer-facing side.
Boundary we own, not the package. Payment gateway calls, tax calculation, shipping rates, webhook handling, refunds, inventory reservation, and any non-Filament storefront UI. Build payments behind a single PaymentGateway contract (charge, refund, verifyWebhook); create orders in pending, redirect, and let a queued webhook job confirm. Idempotency key on order creation, unique index on the provider's transaction ID. Do not let a stakeholder read "full e-commerce system" as "Stripe is included."
State machine. Add a small enum plus a guard method that rejects illegal transitions (pending → paid → fulfilled; refund as a branch, not a rollback). Log every transition with actor and timestamp. Cheap now; prevents the refunded-after-shipment dead-end later.
Feature flag and shadow mode. Wire routes and checkout behind config('features.new_checkout'). If this replaces an existing flow, run shadow mode: real orders continue through the old path while parallel records are written through the new one, diffed daily for a week. That is the only reliable catch for total-calculation drift before it costs money.
Testing. One feature test per golden-path step under RefreshDatabase. Build factories for the package's models on day one if none ship — we will need them constantly.
Maintenance. This is the dominant ongoing cost and it is not zero. Ownership model must be explicit: we own the published migrations, the diff-review ritual for every upgrade, and the service layer around payments and totals. Allocate recurring capacity — roughly a half-day per upgrade cycle plus a full-family rehearsal per quarter — and name an individual accountable for reading git diff v0.x..v0.y -- src database before each bump. Without a named owner, this package degrades quietly: it works until an unrelated TomatoPHP patch white-screens the admin panel.
Support. Effectively none. Single maintainer, 3 stars, 0 dependents, no changelog. We cannot file a support ticket; we can read source, fork, or absorb. Set that expectation with stakeholders explicitly and early — this is an adopt-the-source decision, not a vendor relationship. MIT license means forking is legally clean, which is a genuine mitigation, but a fork converts maintenance cost from "review diffs" to "own the module," and that should be a conscious choice rather than an accident.
Scaling. Two distinct concerns:
lockForUpdate() around stock decrement inside a transaction, or a reservation table with expiry, and test with a real concurrency harness — not a unit test. This is the difference between a launch and an oversell incident.Failure modes to monitor, in the order they'll bite:
migrate:rollback behavior in a disposable app. If the down path leaves orphaned tables or drops data we believed was ours, we need a documented restore procedure before production, not after.Ramp-up. Low for any engineer already fluent in Laravel and Filament — a day to walk the golden path, a week to a documented capability matrix. The learning curve is not the framework; it is discovering the implemented/stubbed boundary, which only the spike reveals. Documentation is thin and release notes are uninformative, so institutional knowledge lives in the spike artifact and the diff-review habit, not in upstream docs. Budget onboarding accordingly: the second engineer learns from our notes, not from the package.
Decision framing. The scores are telling us two different things and both are true: opportunity 8.32 (high leverage if the capability set is real) against 0.445 overall (thin assurance that it is). The proportionate response is a timeboxed, throwaway-app spike producing a capability matrix and a schema diff, with a go/no-go gate based on that artifact. Green-light internal tooling, B2B reorder flows, event or merch stores, and pilot programs — use cases where a 1.0.x single-maintainer module is a proportionate bet. Red-light anything where checkout correctness carries revenue on day one without budget for the payment, tax, inventory, and idempotency work above.
How can I help you explore Laravel packages today?