yassi/nova-nested-form
A Laravel Nova field that embeds nested relationship forms directly inside a parent resource form, letting you create and edit related models inline without leaving the page. It simplifies complex data entry by keeping nested forms and validation within the main Nova workflow.
Architecture fit. The package is a Nova 3 field extension: one PHP field class (NestedForm) plus one Vue 2 component. It hooks Nova's existing field contract (resolve() for loading children into the edit form, fillAttributeFromRequest() for hydrating the child payload on save) and adds no runtime dependency to the production request path. That is a favorable architectural shape for a TPM: the blast radius is the admin surface, not the customer-facing product. It fits cleanly where a parent genuinely owns an ordered set of children with their own attributes — orders and line items, invoices and charges, quotes, product variants, CMS pages and blocks. It fits poorly where the relation is polymorphic, pivot-heavy, or carries pivot attributes as first-class data, and it has a practical depth ceiling of two levels. If the admin roadmap is mostly flat CRUD, this class of package is not worth the ownership cost.
Integration feasibility. Installation is a single composer require; the real effort is configuration and defensive hardening. A realistic plan is a 1–2 day spike on a throwaway branch with one canonical use case, then 1–2 weeks of hardening: transaction wrapping at the middleware layer, soft deletes on the child table, a deleting observer for audit, explicit child-policy enforcement in model events, an explicit position column, eager loading via $with, and HTTP-level feature tests. Preconditions: confirmed Nova 3 (or a proven compatibility branch), one engineer fluent in Nova custom fields, and a staging environment where deliberate breakage is acceptable.
Technical risk. Ranked by severity, not likelihood:
position column, and weak BelongsToMany/pivot support.Key questions. These are the decision-forcing questions for the go/no-go:
Stack fit. Requires Laravel + Nova 3 + Vue 2, with a team comfortable reading vendor PHP and Vue single-file components. If the org has standardized on Nova 4/5, or is trending toward Livewire/Filament where repeaters are more native, the fit drops to near zero and the honest answer is "do not start."
Migration path. There is no data migration; the relevant "migration" is the exit ramp off the package. Build it on day one, not after the first incident: fork into a private VCS or path repo, extract the child field definitions into an owned class (ItemFields::all()) so the swap Yassilah\NestedForm\NestedForm → App\Nova\Fields\NestedForm is a one-line change, and record that swap procedure in the runbook. The code surface is one PHP class and one Vue component, which makes ownership cheap and un-owned forks expensive.
Compatibility. Confirm laravel/nova and PHP versions before touching anything; verify the exact Packagist identifier with composer show -a rather than trusting the vendor path; pin an explicit constraint and commit composer.lock so a routine composer update cannot pull something unexpected into a four-year-old, single-maintainer dependency. Add this field to the Nova-upgrade checklist as a named gate. On the form itself, use NestedForm for onlyOnForms() and the native HasMany for onlyOnDetail() — running both on the form produces duplicate-attribute collisions and confusing saves.
Sequencing. Five phases with clear gates:
nova-api writes, soft deletes on the child table, deleting observer for audit, child-policy enforcement with a 403 feature test, position column set in a model observer, $with eager loading, and an HTTP-level test suite — including the critical test: an update submitting one of two existing children and asserting what happened to the other. That test is the living specification for the delete semantics.Maintenance. You are the maintainer. The small surface keeps this affordable — one PHP class, one Vue component — but the cost is recurring and upgrade-coupled: budget a named owner (an individual, not a team), a few hours per quarter for dependency drift, and a real work item at every Nova major version. The dominant long-run cost is not bug-fixing; it is the forced decision each time Nova moves.
Support. Two distinct audiences. End users report "it wouldn't save" and, worse, discover missing rows days later; validation errors on child rows surface as generic messages, so support triage must start in the network tab of the nova-api response, not the UI toast. Developers need the debugging checklist and the extraction pattern. The runbook is the highest-ROI artifact in this integration — half a day of reading does not reproduce what the spike engineer learned by deliberately breaking the field.
Scaling. Two axes. Row count: the entire child set is serialized into one parent payload with no pagination inside the nested form, so set an explicit soft cap (e.g., ~50 rows) and enforce a hard cap in validation rather than discovering it through timeouts. Index scaling: lazy-loading children across an index is the classic N+1 — use $with. Depth: hard ceiling at two levels; beyond that, model the data as separate resources. Concurrency is the quiet one: saves are last-write-wins against the parent with no optimistic locking, so two admins editing the same parent can clobber each other's children with no error.
Failure modes. Silent child deletion on omitted rows (detect via audit log and row-count parity tests); partial saves on failed requests (detect via transaction-wrapped 500s leaving an intact parent); child-policy bypass (detect via the 403 feature test); Nova upgrade breakage presenting as successful saves that delete everything (detect via the upgrade gate); file-upload breakage inside nested rows (detect early in the spike); pivot-attribute loss (prevent by modeling pivot data as a first-class child); unstable ordering (prevent with an explicit position column and an ordered relation). Each of these should map to a monitoring signal or a test, not just a paragraph in a document.
Ramp-up. Roughly 1–2 days for an engineer already fluent in Nova custom fields, and effectively zero for anyone else until the runbook exists. Budget one spike engineer plus one reviewer for the initial pass, then a single named owner. The knowledge that matters — delete semantics, policy behavior, transaction wrapping, who to call — is not discoverable from the source alone, so treat the runbook and the HTTP-level test suite, not the README, as the onboarding curriculum.
How can I help you explore Laravel packages today?