Skip to content

Qué se genera y dónde va tu código

Un modelo produce unas 58 piezas: la API completa, sus tests y, si lo pides, su módulo de interfaz. Esta página es el mapa: qué archivo sale y cuándo, dónde escribes tú, qué no se toca y qué no se reescribe nunca.

Las rutas son las de un paquete. En una aplicación, src/ pasa a ser app/ y el namespace, App\; el resto de diferencias están al final.

En los nombres, <Model> es el modelo (OrderLine), <Plural> su plural (OrderLines), <snake> su snake_case (order_line), <tabla> el plural en snake_case (order_lines) y <kebab> su kebab-case (order-line).

Por modelo

Modelo, traits y filtros

ArchivoCuándoQué es
src/Models/<Model>.phpSiempreEl modelo: $fillable, $hidden, $creatable, $updatable, $protected_metas, $editable_metas, $export_cols, $loadable_relations, $loadable_counts y casts(), sacados del contrato. Enlaza su observer, su política y su factory con #[ObservedBy], #[UsePolicy] y #[UseFactory].
src/Models/<Model>Meta.phpCon metas: trueUna fila key/value de <snake>_metas.
src/Models/Traits/Relations/<Model>Relations.phpSi no existeHueco. Las relaciones declaradas y, con metas, metas().
src/Models/Traits/Operations/<Model>Operations.phpSi no existeHueco. La lógica de negocio. Con metas, buildPayload() y updatePayload().
src/Models/Traits/Storage/<Model>Storage.phpSi no existeHueco. createModel(), updateModel(), deleteModel(), restoreModel() (con restore), forceDeleteModel() y, con metas, updateModelMetas().
src/Models/Traits/Mutators/<Model>Mutators.phpSi no existeHueco. Accessors y mutators.
src/Models/Traits/Assignments/<Model>Assignment.phpSi no existeUn ejemplo comentado de asignación a través de una pivote.
src/Models/Filters/<Model>/ManagedFilter.phpSiempreHueco. canView(): quién ve qué.
src/Models/Filters/<Model>/IdFilter.php, CreationFilter.php, UpdatedFilter.php, EagerLoadingFilter.phpSiempreLos filtros fijos de search-surge.

HTTP

ArchivoCuándoQué es
src/Http/Controllers/<Model>Controller.phpCon alguna acciónUn método por acción que delega en su request, con el middleware auth:sanctum.
src/Http/Controllers/Controller.phpEn un paquete, una vezEl controlador base.
src/Http/Requests/<Model>/<Acción>Request.phpUno por acción declaradaPoliciesRequest, PolicyRequest, IndexRequest, ShowRequest, CreateRequest, UpdateRequest, DeleteRequest, RestoreRequest, ForceDeleteRequest, ExportRequest, BulkUpdateRequest y BulkDeleteRequest. Autorizan, validan y hacen el trabajo en handle().
src/Http/Resources/Models/<Model>Resource.phpSiempreHueco. La respuesta: parent::toArray() más el array actions de la fila.
src/Http/Events/<Model>/Events/<Acción>Event.phpCon create, update, delete, restore, forceDelete o exportEl evento, con el idioma de la petición.
src/Http/Events/<Model>/Listeners/<Acción>Event/DefaultOperation.phpUno por eventoHueco. Los efectos secundarios.
src/Http/Events/<Model>/Listeners/ExportEvent/SendExportNotification.phpCon exportManda la notificación que crea el archivo.
routes/api/models/<snake>.phpCon alguna acciónUna ruta por acción.

Autorización, ciclo de vida y exportación

ArchivoCuándoQué es
src/Policies/<Model>Policy.phpSiempreHueco. Una habilidad por acción. Nace cerrada.
src/Observers/<Model>Observer.phpSiempreHueco. created y un handler por escritura declarada.
src/Exports/<Plural>Exports.phpCon exportLa consulta y la vista de la hoja.
resources/views/excel/<snake>.blade.phpCon exportLa tabla que se convierte en hoja.
src/Notifications/<Model>/ExportNotification.phpCon exportCrea el archivo y avisa con el enlace.

Base de datos, tests y textos

ArchivoCuándoQué es
database/migrations/<fecha>_create_<tabla>_table.phpSiempreLa creación.
database/migrations/<fecha>_create_<snake>_metas_table.phpCon metas: trueLa tabla de metas.
database/migrations/<fecha>_alter_<tabla>_table.phpAl reimportar con otras columnasLa alteración. Ver Migraciones.
database/factories/<Model>Factory.phpSiempreHueco. Un valor que la base acepta para cada columna.
tests/Feature/Models/<Model>EndpointsTest.phpSi no existeHueco. Un test por acción y, con immutable, los de inmutabilidad.
lang/es.jsonAl generar el recurso y la notificaciónLas claves de las acciones de fila y del correo de exportación que LaraPack sabe traducir.

Por proyecto

ArchivoCuándoQué es
tests/TestCase.phpSi no existeEn un paquete, arranca Testbench con los proveedores de composer.json, Sanctum y Excel, usa tests/User.php, llama a JsonResource::withoutWrapping(), migra y abre la autorización con Gate::before. En una aplicación, el TestCase vacío de Laravel.
tests/User.phpEn un paquete, si no existeEl usuario con que se autentican los tests.
phpunit.xmlSi no hay ni phpunit.xml ni phpunit.xml.dist
composer.jsonEn un paqueteAñade <Namespace>\Database\Factories\ al autoload y <Namespace>\Tests\ al autoload-dev.
.larapack/manifest.jsonSiempreEl registro de lo generado. Se versiona. Ver Regenerar sin destruir.

Los proveedores y la configuración no los genera el importador: están en Proveedores y configuración.

El módulo de interfaz

Sólo con --vue, --react o los dos. <ui> es vue o react, y los componentes son .vue o .jsx.

Por modelo, en resources/<ui>/src/models/<kebab>/

ArchivoNecesitaQué es
index.jsEl contrato del modelo. Es el mismo archivo en Vue y en React.
store/index.jsStore de Pinia (Vue) o de Zustand (React), con la misma superficie.
routes/index.jsindex y policiesLas rutas del modelo.
views/AdminViewindex y policiesEl índice, con la tabla, el drawer de alta y la paleta de comandos.
widgets/DataTableindex y policiesLa tabla.
forms/FilterFormindex y policiesLos filtros.
views/ShowView, widgets/ModelCard, widgets/ModelProfileindex, policies y showLa ficha.
views/CreateView, forms/CreateFormindex, policies y createEl alta.
views/EditView, forms/EditFormindex, policies, show y updateLa edición.

Las vistas cuelgan del índice, y el índice necesita las políticas porque la tabla las consulta para decidir qué acciones ofrece. Sin index o sin policies el módulo sólo trae el contrato y el store.

Del módulo, en resources/<ui>/

ArchivoQué es
index.jsEl punto de entrada.
src/routes/index.jsReúne las rutas de src/models/*/routes/index.js con un glob de Vite. En React exporta además registerModuleRoutes y routeNamesOf.
src/theme.jsImporta innoboxrr-form-core/styles y deja preparados setTheme y setIcons.
src/i18n.jsExporta translations y tableLabels().
src/locales/en.json, src/locales/es.jsonLos textos, que LaraPack completa cada vez que genera.
src/components/Breadcrumbs, src/components/ActionMenuLas migas y el menú de acciones de un registro.
package.json, vite.config.jsSólo en un paquete. El nombre npm es el namespace en kebab-case: acme-catalogo en Vue y acme-catalogo-react en React. En una aplicación los pone la aplicación.

Lo que exporta el punto de entrada

js
import module, { routes, translations } from 'acme-catalogo'

// routes        las rutas de todos los modelos, para montarlas como hijas
// translations  { en, es }
// module        plugin de Vue, { install(app, options) }, vacío por defecto
js
import routes, { registerModuleRoutes, routeNamesOf, translations } from 'acme-catalogo-react'

// routes                      las rutas de todos los modelos (también como export nombrado)
// registerModuleRoutes(base)  registra los nombres de ruta con el prefijo donde se montan
// routeNamesOf(tree, base)    nombre → ruta completa, recorriendo el árbol
// translations                { en, es }

Cómo se usa cada pieza está en La interfaz generada y cómo se monta, en Montar un paquete en una aplicación.

Dónde va tu código

Estos son los sitios donde se escribe a mano. Si una lógica no cabe en ninguno, falta algo en el laraimport.json: no hay que salirse.

HuecoQué va ahí
Traits/Operations/La lógica de negocio del modelo. Es el sitio por defecto. Con metas, también la forma de payload en buildPayload().
Traits/Relations/Relaciones que el JSON no expresa (through, polimórficas completas, condicionales) y los métodos de las relaciones que declares después de crear el trait.
Traits/Storage/La subida y el borrado de archivos del modelo, y lo que haga falta al crear o actualizar.
Traits/Mutators/Accessors y mutators.
Filters/<Model>/ManagedFilter::canViewQuién puede ver qué. Sin esto el índice lo devuelve todo a quien pase la política.
Policies/<Model>PolicyLa autorización por acción. Nace cerrada: cada método devuelve false, sólo pasa el administrador en before(), y ni él borra para siempre hasta que se quite forceDelete de $exceptAbilities.
Requests/*/rules()Reglas que no vienen del JSON, dentro del array.
Resources/<Model>ResourceLa forma exacta de la respuesta y su array actions.
Events/*/Listeners/Efectos secundarios: notificaciones, colas, integraciones.
Observers/El ciclo de vida del modelo.
database/factories/Datos de prueba realistas. Las generadas ya insertan.
tests/Feature/El comportamiento. Los tests generados pasan recién generados y prueban que cada endpoint responde, con la autorización abierta; la autorización pruébala aparte, contra la política.

El modelo es una fachada, no un almacén de lógica. Un método público en Operations que orquesta, y el trabajo real en la clase que le corresponda.

La autorización no va en el modelo

Si escondes un abort(403) en el modelo, la API de políticas no lo ve y la tabla ofrece un botón que falla. Quién puede hacer qué se decide en la política, que es lo que consulta el front.

Qué no se toca

  • El controlador. Delega en los requests y no tiene lógica. Lo distinto va en el request.
  • El archivo de rutas. Si falta un endpoint, falta en el generador o en routes.
  • Las listas del modelo: $fillable, $creatable, $updatable, $export_cols, $loadable_relations, $loadable_counts, $editable_metas, $protected_metas y casts(). Salen del JSON; editarlas separa el código del contrato.
  • Lo que un request declara fuera de su array de reglas.
  • models/<kebab>/index.js de un solo framework. Es el mismo archivo en Vue y en React; editarlo en uno los separa.
  • Clases de un framework CSS (uk-*, fa-*, Tailwind) en un archivo generado. El aspecto sale del tema.

Un archivo generado que editas queda marcado como customised en larapack:verify y ya no recibe regeneraciones. En un hueco es lo esperado; en el controlador, las rutas o el modelo es deriva.

Los marcadores

Hay dos clases de marcas en las plantillas.

Bloques condicionales. Las plantillas marcan lo que depende de una acción o de una clave del modelo:

php
// @larapack:if update
public function update(UpdateRequest $request) { ... }
// @larapack:endif

Las condiciones son el nombre de una acción, immutable, secret, metas o authenticatable; a|b se cumple si se cumple cualquiera, a&b si se cumplen las dos, y !a si no se cumple a. Las líneas del marcador desaparecen siempre, así que nunca llegan a tu proyecto.

Marcadores de datos. Son el sitio donde el importador escribe lo que sale del contrato:

MarcadorDóndeQué pone
//FILLABLE//, //HIDDEN//, //CREATABLE//, //UPDATABLE//, //EDITABLEMETAS//, //EXPORTCOLS//, //LOADABLERELATIONS//, //LOADABLECOUNTS//, //CASTS//El modeloLas listas y los casts.
//RULES//CreateRequest y UpdateRequestLas reglas de requests.
//IMPORTS// y //EDIT//El trait RelationsLos use y los métodos de relación.
//EDIT//Migración de creación, migración de pivote y factoryLas columnas y los valores de la factory.
//UP// y //DOWN//Migración de alteraciónLos cambios y su reverso.
//DATA_TABLE_COLUMNS//, //DATA_TABLE_SORT// y //BULK_UPDATE_ACTIONS//models/<kebab>/index.jsLas columnas de la tabla, el orden por defecto y una acción masiva por valor de enum.
<!-- Add more inputs --> (Vue), {/* Add more inputs */} (React), //import_more_components//, //form_fields//, //submit_data// y //props//Los formulariosLos campos, sus imports, el estado, lo que se envía y las props.

Desde larapack:import cada marcador se sustituye por su contenido y desaparece. Un generador suelto no tiene laraimport y deja los marcadores de datos tal cual, con el archivo vacío de columnas, reglas o campos.

Lo que nunca se reescribe

QuéPor qué
Los cinco traits (Relations, Operations, Storage, Mutators y Assignment)Son tuyos desde que existen: sólo se crean si faltan, ni --force los reescribe y no entran en el manifiesto.
tests/Feature/Models/<Model>EndpointsTest.phpSe crea si falta y no entra en el manifiesto. Para recibir el de una versión nueva, bórralo y vuelve a importar.
tests/TestCase.php, tests/User.php y phpunit.xmlSe copian una vez.
Las migraciones de pivotesSe crean si no hay una migración de creación de esa tabla.
Una migración de creación que no generó LaraPackSe omite. Ver Migraciones.
Una traducción que no está vacía, en src/locales/*.json o en lang/es.jsonAl generar sólo se suman claves nuevas y se rellenan las vacías que LaraPack conoce. Un JSON inválido se deja como está.
Lo que larapack:new escribe fuera de los generadores: README.md, CHANGELOG.md, VERSION, AGENTS.md, los workflows, pint.json, phpstan.neon.dist, phpunit.xml.dist, .gitignore, .gitattributes y LICENSEEs del paquete desde el primer commit: no pasa por el manifiesto, y cambiarlo no es una desviación de la arquitectura.
La skill instaladalarapack:skill sólo la pisa con --force.
Cualquier archivo generado que editaste--force lo conserva y lo dice.

Paquete o aplicación

PaqueteAplicación
Códigosrc/, con el namespace del paqueteapp/, con App\
Rutasapi/<namespace>/<snake>, nombres api.<namespace>.<snake>.*api/app/<snake>, nombres api.app.<snake>.*
Factories<Namespace>\Database\FactoriesDatabase\Factories
Tests<Namespace>\Tests\Feature\Models, con el TestCase de Testbench y tests/User.phpTests\Feature\Models, con el TestCase de la aplicación; inician sesión con la factory del modelo de auth.providers.users.model
Módulo de interfazCon su package.json y su vite.config.jsSin ellos: lo compila la aplicación, que declara sus dependencias
Vista y configuración de la exportación<clave>::excel. y config/<clave>.phpexcel. y config/larapack.php
ProveedoresEn extra.laravel.providers, descubiertos por LaravelRegistrados a mano en bootstrap/providers.php

El detalle está en Paquete o aplicación.

Cómo es el PHP generado

Lo generado sigue las convenciones de Laravel 13, pasa pint --test y Larastan de nivel 5:

  • Modelos: los casts se declaran con el método casts(): array, y el observer, la política y la factory se enlazan con #[ObservedBy], #[UsePolicy] y #[UseFactory], sin descubrirlos por reflexión.
  • Controladores: implementan HasMiddleware con un middleware() estático; el controlador base no extiende Illuminate\Routing\Controller.
  • Rutas: callables [Controlador::class, 'método'], así que el RouteServiceProvider no declara namespace de controladores.
  • Proveedores: extienden Illuminate\Support\ServiceProvider.
  • Migraciones, requests, políticas y recursos: firmas con tipo de retorno (up(): void, rules(): array, toArray(Request $request): array).
  • Eventos: toman el idioma de la petición en un parámetro locale, sin cambiar el idioma de la aplicación.