Trabajar en el código
Los comandos que corres a diario, las pruebas, las revisiones antes de un push y dónde vive cada cosa.
Esta guía es la referencia diaria del desarrollador: cómo arrancar la aplicación, qué comandos Artisan agrega el kit, cómo corren las dos suites de pruebas, qué detiene un push y qué carpetas vas a tocar de verdad. Léela una vez después de /help/get-it-running y vuelve cuando se te escape el nombre de un comando.
Arranca todo
Un comando inicia los cuatro procesos que necesita una copia de trabajo:
composer dev
Es un script de Composer que corre npx concurrently con, en este orden y cada uno con su color: php artisan serve (server), php artisan queue:listen --tries=1 (queue), php artisan pail --timeout=0 (logs) y npm run dev (vite). Detener uno detiene los cuatro (--kill-others).
Si sirves el sitio con Herd o Valet, el servidor de PHP sobra: abre la APP_URL de tu .env (por ejemplo http://your-project.test) y corre los otros tres tú mismo en terminales separadas.
npm run dev # Vite con recarga en caliente
php artisan queue:listen --tries=1
php artisan pail
La cola importa incluso en desarrollo: las notificaciones, el web push y el trabajo de cobros son jobs, y nada ocurre hasta que un worker los toma. Cuando prefieras no correr uno, pon QUEUE_CONNECTION=sync en .env y los jobs corren en línea dentro de la petición. Ambas opciones se explican en /help/queues-and-scheduled-work.
El resto del conjunto diario es Laravel puro:
| Comando | Cuándo |
|---|---|
php artisan migrate |
Después de jalar una migración. |
php artisan db:seed |
Una vez, después de la primera migración, para crear las cuentas, roles y permisos sembrados. --class=UserSeeder o --class=AdminSeeder resiembra un grupo; los seeders usan firstOrCreate, así que una cuenta existente conserva su contraseña. |
php artisan tinker |
Para inspeccionar o corregir un registro desde la consola con los modelos de la aplicación. |
npm run build |
Para compilar los assets una vez, sin vigilar cambios. |
php artisan schedule:work |
Para correr los comandos programados en local, cada minuto, mientras siga abierto. |
Las cuentas sembradas salen de config/app.php: los correos en sudo se vuelven administradores, los de default_users se vuelven usuarios normales. Cada contraseña es la parte del correo antes de la @, invertida y en minúsculas, así que [email protected] inicia sesión con tset. A un administrador sembrado se le pide cambiar esa contraseña en su primer inicio de sesión.
Los comandos Artisan que agrega el kit
Estos son los comandos propios del kit, en app/Console/Commands:
| Comando | Qué hace |
|---|---|
help:stamp |
Reescribe el comentario de huella en cada documento de ayuda traducido para que registre de qué versión en inglés se escribió. Sólo lee y hashea archivos; nunca llama a la red. |
help:stamp --check |
No escribe nada. Imprime una tabla de los documentos de ayuda a los que les falta traducción, cuya versión en inglés cambió después de escribir la traducción, cuya versión en inglés ya no existe, o que no tienen front matter, y sale con código de fallo cuando la tabla no está vacía. |
lang:search |
Recorre app/, resources/views/ y routes/ buscando __(), @lang(), trans(), Lang::get(), etiquetas de inputs de Laravel Front, ->setTitle() y títulos de acciones, y agrega a lang/en.json toda llave que falte. |
lang:sync |
Hace que cada archivo de idioma tenga las mismas llaves que el inglés, en el mismo orden. Una llave que sólo existe en otro idioma se agrega al inglés; una llave que falta en un idioma se traduce con el proveedor de IA configurado, o se deja en inglés cuando no hay ninguno configurado. Cubre lang/*.json y lang/{locale}/*.php. |
lang:delete |
Quita de todo archivo lang/*.json las llaves que ningún archivo del proyecto usa ya. Nunca toca los archivos PHP de traducción. |
lang:update |
Corre lang:sync, luego lang:search y luego lang:sync otra vez: la ronda completa de traducción en un comando. |
pwa:generate-assets |
Pide un icono base cuadrado de al menos 512 px y dos colores de fondo, y luego escribe todos los tamaños de icono y pantalla de inicio que lista config/laravelpwa.php en public/images/icons. |
stats:compute-daily |
Cuenta los usuarios que iniciaron sesión ayer y guarda el número en la tabla stats bajo daily_logged_users. Programado en routes/console.php para correr a diario a las 00:00. |
El paquete weblabormx/billing-core en packages/ agrega uno más:
| Comando | Qué hace |
|---|---|
billing:sync-exchange-rates {--date=} |
Obtiene y guarda los tipos de cambio para las fechas de suscripciones pagadas que necesitan conversión de moneda. Programado a diario a las 12:00, y sólo mientras los planes o los complementos estén habilitados. |
Los paquetes instalados agregan los comandos que también vas a buscar: clean:code del paquete de estándares de código de Weblabor (--no-commit omite el commit que hace), webpush:vapid del canal de web push, dusk y dusk:chrome-driver de Laravel Dusk, ide-helper:generate e ide-helper:models del IDE helper (sus archivos de salida están ignorados por Git), y make:agent, make:tool, make:agent-middleware y agent:chat del paquete Laravel AI, descritos en /help/connect-an-ai-provider. php artisan list los imprime todos.
Las pruebas
Hay dos suites y corren de forma distinta.
Pruebas de funcionalidad
phpunit.xml declara una suite, WeblaborBase, sobre tests/WeblaborBase. Sus carpetas son Admin, Auth, BillingCore, Categories y Help, una por área del kit. La suite corre sobre una base de datos SQLite en memoria, así que no necesita servidor de base de datos y deja intactos tus datos de desarrollo:
Ajuste forzado por phpunit.xml |
Valor |
|---|---|
APP_ENV |
testing |
DB_CONNECTION / DB_DATABASE |
sqlite / :memory: |
QUEUE_CONNECTION |
sync |
MAIL_MAILER |
array |
CACHE_DRIVER, SESSION_DRIVER |
array |
tests/TestCase.php va más lejos antes de que arranque la aplicación: borra bootstrap/cache/config.php para que una configuración de MySQL en caché no se filtre a la corrida, carga .env y encima .env.testing, y fuerza SQLite una vez más. .env.testing está committeado y trae una APP_KEY más los ajustes de SQLite, y por eso una copia recién clonada puede correr las pruebas antes de tener .env.
Extiende Tests\FeatureTestCase para una prueba que toque la base de datos. Agrega RefreshDatabase y siembra PermissionSeeder y RoleSeeder antes de cada prueba, así que config('app.admin_role') existe y se le puede asignar a un usuario. Tests\TestCase es la base desnuda para una prueba que no necesita ninguna de las dos cosas.
php artisan test # toda la suite
php artisan test tests/WeblaborBase/Admin/DevZoneTest.php # un archivo
php artisan test --filter=test_user_can_login # un método
composer test # config:clear y luego la suite
composer test-without-billing-core corre scripts/ci/test-without-billing-core.sh: copia el proyecto a una carpeta temporal, ahí quita el paquete weblabormx/billing-core, migra y siembra un archivo SQLite desechable, verifica que no sobreviva ninguna ruta de cobros y corre dos pruebas de funcionalidad. Demuestra que el kit sigue arrancando cuando un proyecto se entrega sin cobros. Tu copia de trabajo no se modifica.
Pruebas de navegador
tests/Browser/WeblaborBase guarda las pruebas de Laravel Dusk, en las carpetas Auth y App. Manejan un Chrome real a través de ChromeDriver, contra la aplicación tal como la sirve tu .env, así que el sitio debe ser alcanzable en APP_URL y la base de datos que configuraste es la que usan. No forman parte de php artisan test.
php artisan dusk:chrome-driver --detect # una vez, y después de que Chrome se actualice
php artisan dusk # todas las pruebas de navegador
php artisan dusk tests/Browser/WeblaborBase/Auth/LoginTest.php
tests/DuskTestCase.php inicia ChromeDriver en el puerto 9515 a menos que corras dentro de Sail, y abre Chrome sin ventana a 1920×1080. Tres variables de entorno cambian eso, leídas del shell o de .env:
| Variable | Efecto |
|---|---|
DUSK_DRIVER_URL |
Dónde escucha ChromeDriver. Valor por omisión http://localhost:9515. |
DUSK_HEADLESS_DISABLED |
Ponle cualquier valor para ver el navegador. php artisan dusk --browse la pone por ti. |
DUSK_START_MAXIMIZED |
Ponle cualquier valor para maximizar la ventana en lugar del tamaño fijo. |
Cuando existe un archivo llamado .env.dusk.local (.env.dusk.{APP_ENV}), Dusk lo intercambia por .env mientras corren las pruebas y restaura .env al terminar. Úsalo para apuntar las pruebas de navegador a una base de datos separada.
Extiende Tests\Browser\WeblaborBase\WeblaborBaseDuskTestCase. Te da makeVerifiedUser() (una cuenta verificada cuya contraseña es password), makeAdminUser() (lo mismo, con el rol admin después de sembrar permisos y roles), ensureActiveSubscription() para un flujo detrás del muro de pago, fillWireModel() para escribir en un campo wire:model, clickFirstSubmitButton(), assertBrowserPageLoaded() y latestVerificationCodeFromLog(), que lee el último código de verificación escrito en el log y por lo tanto necesita MAIL_MAILER=log. Toda cuenta creada con estos helpers se elimina definitivamente en tearDown(). Las pruebas fallidas dejan una captura en tests/Browser/screenshots, la salida de consola en tests/Browser/console y el código fuente de la página en tests/Browser/source; las tres carpetas están ignoradas por Git.
Playwright está presente en package.json como dependencia de desarrollo, pero ninguna prueba del repositorio lo usa; la suite de navegador corre con Dusk y ChromeDriver.
Análisis estático y estilo
vendor/bin/phpstan analyze
php artisan clean:code --no-commit
Larastan está instalado para el primero. No hay un phpstan.neon committeado, así que pasa las rutas y el nivel que quieras en la línea de comandos o agrega el archivo a tu proyecto. El segundo aplica los estándares de código de Weblabor a todo el proyecto; sin --no-commit hace commit del resultado. Ese es también el único trabajo que corre el pipeline de GitLab committeado: .gitlab-ci.yml instala las dependencias con scripts/ci/prepare-clean-code.sh, corre clean:code --no-commit y sube un commit "Code Style Fixes" cuando algo cambió. Sus otros trabajos hacen merge de master en staging y de staging en develop después de cada push a esas ramas. El pipeline no corre las pruebas.
composer install-locally-repo es para quien desarrolla los paquetes de Weblabor mismos: reemplaza vendor/weblabormx/weblabor-cs, laravel-front y tall-utils con enlaces simbólicos a copias hermanas. Déjalo en paz a menos que seas tú.
Depurar mientras trabajas
En el entorno local con APP_DEBUG=true la Debugbar muestra las consultas, vistas, eventos y tiempos de cada página, y el detector de consultas reporta consultas N+1 dentro de ella. DEBUGBAR_ENABLED, QUERY_DETECTOR_ENABLED, QUERY_DETECTOR_THRESHOLD y las demás variables que los ajustan, los canales de log incluido Slack, y el límite de excepciones están todos en /help/logs-and-debugging. php artisan pail sigue el log en la terminal y /logs lo muestra en el navegador.
Para recibir webhooks de Stripe en tu máquina, reenvíalos con la CLI de Stripe a la ruta que el kit expone en routes/api.php, y luego pon en .env el secreto que imprime:
stripe listen --forward-to your-project.test/api/stripe/webhook
STRIPE_WEBHOOK_SECRET=whsec_xxxxx
Qué detiene un push
composer install corre git config core.hooksPath scripts/git-hooks al final de cada volcado de autoload, así que los hooks de esa carpeta están activos en cada clon, incluidos los proyectos que derives del kit. Hay uno, pre-push, y corre:
php artisan help:stamp --check
Un push se rechaza mientras a algún documento de ayuda le falte traducción, tenga una traducción más vieja que su inglés, tenga una traducción cuyo inglés ya no existe, o no tenga front matter. La tabla que imprime nombra cada archivo y el problema. Corrige los documentos, corre php artisan help:stamp para volver a sellar las traducciones y vuelve a hacer push. Para la única vez que necesites hacer push de todos modos:
git push --no-verify
El hook necesita PHP y una aplicación que arranque en el shell que hace el push; desde un cliente de Git que no puede correr php artisan, falla, y --no-verify es la salida.
Dónde vive cada cosa
| Carpeta | Qué pones ahí |
|---|---|
app/Livewire/Admin, App, Auth, Web, Shared |
Toda pantalla interactiva. Admin es el panel de administración, App el área con sesión iniciada, Auth el inicio de sesión, perfil y cuenta, Web las páginas públicas, Shared componentes que usa más de un área. |
app/Front/Resources |
Los CRUDs del panel de administración, una clase por modelo, con su política en app/Policies. app/Front/Inputs, Filters, Actions y Pages guardan sus piezas personalizadas. |
app/Models |
Modelos Eloquent, todos extendiendo App\Models\Model, con $guarded y nunca $fillable. Los casts, enums, traits y observers están en /help/models-casts-and-building-blocks. |
app/Helpers |
Funciones globales, un archivo por capa (base.php para el kit); cada función está protegida con function_exists para que un proyecto derivado pueda agregar su propio archivo. |
app/Console/Commands |
Comandos Artisan. Las programaciones van en routes/console.php. |
app/Services, app/Jobs, app/Notifications, app/Mail |
Aquello a lo que un método de modelo delega. |
routes/web.php, auth.php, app.php, admin.php, api.php |
Rutas públicas, de autenticación, de /app, de /admin y de API. Qué middleware envuelve cada grupo está en /help/routes-layouts-and-middleware. |
resources/views/components |
Componentes Blade: <x-date-input>, <x-phone-input>, <x-email-input>, <x-domain-input>, <x-categories-input>, <x-language-switcher>, <x-sidebar-menu>, <x-loading-overlay>, <x-system-warnings> y el reproductor de audio. Busca aquí antes de escribir el mismo marcado dos veces. |
resources/views/livewire, layouts, landing, pages, emails |
Vistas de componentes, layouts de página, la landing, páginas estáticas y plantillas de correo. |
lang/en.json, lang/es.json, lang/{locale}/*.php |
Toda cadena que una persona lee, escrita en inglés en el código y traducida aquí. |
docs/{project}/help/guides, docs/{project}/help/changelog |
El centro de ayuda que estás leyendo, con las traducciones en una carpeta de idioma junto a cada archivo en inglés. |
stubs/ |
Las plantillas que usa php artisan make:*, ajustadas a las convenciones del kit. |
packages/ |
Paquetes que viajan dentro del repositorio, hoy billing-core. |