Cargando…

Esto está tardando más de lo esperado.

Volver al centro de ayuda

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.
help:stamp --check --pushed El mismo reporte, limitado a los documentos de ayuda que cambia un push, tal como quedan en los commits que envía. El hook pre-push lo corre con las referencias que Git le pasa por la entrada estándar.
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 --pushed

Juzga lo que el push envía, no lo que hay en tu carpeta de trabajo. Solo se revisan los documentos de ayuda que el push agrega, cambia, mueve o borra, junto con su par (la traducción de un documento en inglés, el inglés de una traducción), tal como quedan en los commits que se suben. Un push se rechaza cuando a uno de ellos le falta traducción, tiene una traducción más vieja que su inglés, tiene una traducción cuyo inglés ya no existe, o no tiene front matter. La tabla que imprime nombra cada archivo y el problema.

  • Lo que no está en un commit no cuenta: los cambios sin commit y los archivos sin trackear ni frenan un push ni lo rescatan.
  • Un documento que ya venía roto en la rama no frena un push que no lo toca.
  • Un push que no toca ningún documento de ayuda no revisa nada. Una rama nueva se compara con lo que el remoto aún no tiene, varias ramas en un mismo push se revisan juntas, y borrar una rama o subir una etiqueta no revisan nada.

php artisan help:stamp --check por sí solo sigue revisando todos los documentos de la carpeta de trabajo, que es la revisión que conviene correr mientras escribes. 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> y el reproductor de audio; los componentes de diseño (<x-design::sidebar-menu>, <x-design::records-table>, <x-design::loading-overlay>, <x-design::system-warnings> y los demás) viven en weblabor-base/. 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.