tomatophp/tomato-cms
Tomato CMS is a Laravel package from the TomatoPHP ecosystem that adds content management to your app: pages, posts, menus, and media, with a Filament admin panel. It plugs into TomatoPHP's module system for quick setup. Early-stage and lightly adopted, so review before production use.
Architecture fit. This is a component-level decision wearing a platform-level costume. tomatophp/tomato-cms presumes Laravel, Filament, and the broader Tomato PHP admin suite (admin, settings, roles, translations, media). A TPM should reframe the question from "does this package fit?" to "are we committing to the Tomato PHP convention set as a program decision?" If the organization is already inside that ecosystem, the package is a genuine accelerator — page/post/category CRUD, SEO metadata, slugs, publish flags, and localization arrive in day-scale effort. If not, the honest comparison is against a thin custom content model on native Filament resources, not against Strapi or Drupal. Best-fit target: modular-monolith Laravel application, server-rendered Blade/Inertia front end, editors who benefit from in-panel control of URLs and publish state, and content that is a convenience rather than the product core.
Integration feasibility. Mechanically straightforward — Composer install, publish config and migrations, migrate, register Filament resources. The real feasibility gates are non-mechanical: Filament major-version alignment (the last release, May 2024, predates several Filament and Laravel majors, so assume patching on a current stack), migration collisions against existing pages/posts/categories tables, and translation machinery that may be spatie/laravel-translatable or proprietary. A two-to-three-day time-boxed spike — admin creates a page, publishes it, renders it by slug on the front end — is sufficient to convert all three unknowns into facts.
Technical risk. Ranked by program impact rather than code severity:
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Filament major mismatch requiring a fork | High | Sprint-scale | Budget patch/fork time in the estimate before approving |
| Single-maintainer abandonment (bus factor 1) | Medium-high | Program-level | Name an internal owner at approval time, not after |
| Migration/table collision with existing schema | Medium | Contained | Diff migrations and models before migrate |
| Silent locale-fallback regression | Medium | Customer-visible | Fallback test written during the spike, not after |
| Transitive-package security drift | Medium | Slow-burn | Version pinning, periodic audit, vendor-fork posture |
| Scope creep into multi-package Tomato adoption | High | Program-level | Explicit ecosystem decision recorded at the roadmap level |
Adoption signal is the headline risk: 1 star, 0 dependents, one maintainer, no community safety net, no vendor backing, no upgrade roadmap aligned to current majors. GitHub issues will not be answered. Anything the team does not understand by the end of the spike is owned forever.
Key questions.
composer why-not say?Stack fit. The package fits only where the stack already includes Filament. Confirm the Filament major first — it is a hard gate, not a detail — and confirm whether auto-discovery is on before assuming any provider behavior is implicit. Assume the resolved dependency tree pulls in several sibling Tomato packages; the real adoption surface is that tree, not the one line typed into Composer.
Migration path. Publish before migrating. Inspect config keys (route prefix, middleware, locales, slug source) and diff the schema against existing tables before running migrate in any shared environment. Read the Eloquent models for pages, posts, and categories before the Filament resources — the models are the data contract, the resources are generated ergonomics. For front-end routing, use the package's shipped routes only during the spike; for production, register a thin controller of our own that calls a ContentRepository interface, keeping the package's URL conventions from hardening into a contract we cannot change.
Compatibility. Two compatibility axes to track separately: version compatibility (Filament/Laravel majors, PHP version, transitive pins) and behavioral compatibility (translation fallback semantics, slug generation rules, publish-state defaults). The first is discovered in an afternoon via composer show --tree; the second only surfaces through the end-to-end loop and a deliberate no-translation test case.
Sequencing. Structure as four gates, each with a written artifact:
ContentRepository interface, name the maintenance owner with allocated capacity, and schedule a transitive-package security review before any customer-facing exposure.Maintenance. The ongoing obligation is the real cost, and it is not optional. Someone must own Filament major-version patches, Laravel bumps, and periodic security review of transitive packages. Realistically this is a recurring, small-but-nonzero engineering allocation — estimate it explicitly at approval time and revisit it quarterly. If no one signs up, the correct decision is a no-go, and the spike output becomes the requirements baseline for a build or an alternative evaluation. Vendor-forking into our namespace is the honest posture at this adoption level; it converts an unmaintained dependency into a maintained internal one at a known cost.
Support. Assume zero external support. No timely issue responses, no vendor escalation, no security advisories. Internal documentation written during the spike — while context is fresh — is the only support artifact the team will have. Treat it as a deliverable, not an afterthought.
Scaling. The package is not designed for high-traffic public content delivery. Read paths are cache-friendly in principle, but the expensive mistakes are uncached menu trees and settings lookups firing per request, plus N+1 queries across translated fields and media relations. Confirm slug, locale, and publish-status columns are indexed. For an internal back office or MVP demo these concerns are negligible; for a customer-facing content site they are gating. Position the package accordingly and do not let a successful internal pilot quietly become a public-site commitment without a separate scaling review.
Failure modes. Three to plan for explicitly. First, the silent locale fallback — no exception, no log, wrong language served to a user; this is the only failure mode that is both likely and customer-visible, so it gets a test written before launch, not after. Second, the unpatched upgrade cliff — a Filament bump on the host application breaks the admin panel with no upstream fix coming; the fork and pinning plan is the mitigation, and it must exist before the panel is load-bearing. Third, the ecosystem creep failure — one package pulls in four more, and the dependency graph becomes a de facto platform commitment nobody approved; the Gate 1 written decision is the control.
Ramp-up. Low engineering ramp-up — a Laravel-fluent engineer is productive in the spike's first day. The organizational ramp-up is the harder part: stakeholders need to internalize that this is a reversible experiment producing requirements clarity and a de-risked build estimate, not a CMS procurement. Success criteria for the pilot should be stated in those terms — end-to-end loop proven, editor workflow feedback captured, integration cost measured against the build estimate, and a written go/no-go — rather than in adoption metrics. The durable value is the requirements artifact and the build estimate it validates; the code is disposable by design.
How can I help you explore Laravel packages today?