Product Decisions This Supports
- Build vs. buy for repeatable admin form UX. The package supplies an "add another row" field group — addresses, contacts, line items, opening hours, FAQ entries, schedule slots — composed from standard Nova field types and persisted as a single JSON column on the parent record. The buy case rests on saving custom Blade/Vue view work for a well-understood interaction, not on delivering capability we cannot otherwise get. If repeatable admin content is on the roadmap, this is a legitimate candidate to adopt (MIT) or vendor.
- Schema scope: JSON blob vs. child table. The package is a live argument for the cheaper data model. Adopting it is effectively deciding "this content is a document, not a record." That decision should be made deliberately in the PRD, because the constraint surfaces later as a reporting problem rather than as a field problem — JSON path queries are awkward pre-MySQL 8.0 and unpleasant even after. If any stakeholder will ever ask "show me every Monday opening row across all stores," the answer is a child table and this package is the wrong tool.
- Form ergonomics scoping (v1.3.0). The
heading option adds auto-incrementing block titles ("Day 1", "Day 2") purely for scanability on long repeaters. Zero data-model impact, zero new capability. Treat it as a usability acceptance criterion — do we want visual block boundaries on long forms? — and evaluate it on that basis alone.
- Maintainer-health signal, and its expiry. v1.3.0 was a community contribution, which reads as healthy in isolation. But the repo is archived, last released 2019-06-10, 132 stars, zero dependents. Contributor activity here is a historical data point, not evidence of ongoing support. Any roadmap entry depending on this package needs an owner named at the same time as the ticket.
- The gap between opportunity (15.25) and composite (1.38) is itself the useful finding. It says "repeater fields are worth having," not "this is the repeater to have." That is a valid build-vs-buy prompt for our admin tooling even if we reject this specific implementation — and it should trigger a check of whether our Nova version already ships a native repeater, which would make the package moot.
- Low-risk, reversible adoption where already in use. v1.3.0 has no breaking changes, deprecations, or migrations. If we already depend on it, pulling within the existing minor constraint is routine and fully reversible — the option can be switched off per form with no data impact.
When to Consider This Package
Consider it when:
- We already run Laravel Nova (a licence and install are mandatory — this is a Nova field class, not a general Laravel package, and there is nothing usable without it).
- We need grouped, repeatable field rendering with add/remove/reorder and no appetite for bespoke Nova view work.
- The content is admin-facing, low-traffic, and low-stakes — opening hours, FAQ lists, contact blocks — rather than anything with reporting, aggregation, or cross-record search requirements.
- We are willing to treat adoption as a fork decision rather than a dependency decision: copy
src/ and resources/js/ in-house under MIT, tag it, and name an owner. Leaving it as an unowned third-party package in composer.json is the failure mode.
- We can cap row counts (roughly 30–50 before the form goes sluggish and the payload gets fat) and can accept that validation, normalization, and derived values live on the parent model, not in the field.
Look elsewhere when:
- Maintenance continuity matters. Archived, 2019, zero dependents, no support policy, no patch cadence. Every Nova major is an unbounded break with no upstream remedy — the Vue 2 → 3 transition is the concrete example. Anything long-lived or security-sensitive should not sit on this.
- Our Nova version ships a native repeater or a maintained community alternative. A first-party option beats an archived third-party dependency almost every time; run this check before any evaluation work.
- We are not on Nova. Without it the package scores zero and the question moves to whichever admin layer we actually run.
- The form needs conditional logic. No
dependsOn, no hideWhen between subfields, no per-row conditional behaviour. That requirement forces a child relationship with a real Nova resource.
- Subfield coverage must be broad. The field
type maps to a fixed set of Nova field types; BelongsTo, File, and anything with async or modal behaviour are the usual failures. Each type we intend to use needs testing.
- Accessibility, localization, or heading guarantees are hard requirements. Auto-generated titles may render as non-semantic markup and may not be translatable; the counter is client-side and renumbers after add/remove/reorder, so nothing user-facing — anchors, exports, copy — can depend on those numbers. None of this is evidenced in the release note and must be verified against our standards.
- We need a predictable migration path in either direction. Moving from a child table to this blob is a one-way content migration best done in two deploys with a scratch column and a count comparison — plan it as a project, not a ticket.
How to Pitch It (Stakeholders)
For executives: This is a small, free (MIT) add-on for our Nova admin panel that gives editors a "add another row" control for things like opening hours, address lists, and FAQ entries, storing the rows as JSON on the existing record instead of requiring a new database table. It saves us custom view development for a familiar interaction. The catch is that the project was archived in 2019 and has no maintainer and no downstream users — so we should not take it as a dependency. The recommendation is to adopt it as an internal fork with a named owner, or skip it if our Nova version already provides an equivalent. Either way, the exercise has told us something useful: repeatable admin fields are worth having, and we should decide deliberately whether to build, buy, or use the platform's own.
For engineering: Pin exactly at 1.3.0; do not float the constraint. The package owns no table — add a nullable json column and an array cast on the model. Validation, wildcard rules, and derived values all live on the parent model, not the field; the field stores a blob and enforces no shape. The single most important line in any integration is array_values() in a saving normalizer, because deleted rows leave null holes that serialize as a JSON object and silently fail to render — that is the number-one bug report. Recompute derived values (totals, hours-per-week) on read with accessors, never persist them. Cap row counts in validation. Feature-test the resource endpoints, and add one Dusk test for add/remove/reorder since those interactions live in Vue and HTTP tests will not catch them. Test every subfield type you use, one resource at a time. And write the one-page internal field guide — column type and cast, wildcard rules, the normalizer, the row cap, the fork owner — because the package is trivial to use and easy to misuse, and the next developer will hit all of these within a week.