La DevZone
La página de superadministrador en /admin/dev, cada herramienta que trae y cómo agregar la tuya.
La DevZone es una página del panel de administración, en /admin/dev, que le permite a un superadministrador operar la aplicación instalada desde el navegador: editar el archivo .env, jalar y desplegar el último código, leer los logs, revisar las entregas de webhooks y probar el web push y la detección de plataforma móvil. Léelo cuando quieras saber qué hace cada botón antes de presionarlo en un servidor de producción, o cuando quieras agregar una herramienta tuya.
Es un solo componente Livewire, App\Livewire\Admin\DevZone, con su vista en resources/views/livewire/admin/dev-zone.blade.php. No hay paquete aparte ni archivo de configuración: todo lo que hace está en esos dos archivos.
Quién puede entrar
Dos verificaciones separan a un visitante de la página, y las dos tienen que pasar.
| Verificación | Dónde vive | Qué exige |
|---|---|---|
| El grupo admin | bootstrap/app.php |
Toda ruta de routes/admin.php corre detrás de web, auth, security y role:admin. El visitante debe haber iniciado sesión, no estar bloqueado y tener el rol admin, el que nombra admin_role en config/app.php y el seeder asigna a toda cuenta sudo. |
| El atributo sudo | DevZone::mount() |
auth()->user()->sudo debe ser verdadero. Si no, la petición se aborta con HTTP 405. |
sudo no es un rol ni un permiso. Es un atributo calculado del usuario (en App\Traits\UserBase): verdadero cuando el correo de la cuenta, en minúsculas, aparece en el arreglo sudo de config/app.php. Un administrador cuyo correo no está en esa lista ve el resto del panel de administración pero no esta página, y la entrada "Dev Zone" de la barra lateral en resources/views/layouts/sidebars/admin.blade.php también se le oculta ('show' => auth()->user()->sudo).
La página no está restringida al entorno local. Existe justamente para operar una instalación desplegada, y por eso la lista de correos sudo es un valor committeado y no una variable de entorno. Cómo se siembran las cuentas sudo y qué más pueden hacer está en /help/sudo-and-super-administrators; el rol detrás del panel de administración está en /help/roles-and-permissions.
El encabezado
El título muestra el nombre de la aplicación y el commit que corre el servidor: la salida de git describe --all --dirty seguida del hash corto, por ejemplo heads/master 4f2a9c1. Se lee con un proceso de shell desde la raíz del proyecto y se guarda en caché un minuto bajo la llave currentCommit. Cuando Git no está disponible en el servidor, o la carpeta no es un repositorio, muestra ??.
Junto al título hay tres botones.
Check logs abre /logs en una pestaña nueva. Esa página es el paquete rap2hpoutre/laravel-log-viewer, que lee los archivos de storage/logs y te deja cambiar entre ellos, filtrar por nivel y borrar un archivo. Dos variables de entorno lo ajustan, ninguna presente en .env.example:
| Variable | Valor por omisión | Qué hace |
|---|---|---|
LOGVIEWER_PATTERN |
*.log |
Qué archivos de la ruta de almacenamiento se listan. |
LOGVIEWER_STORAGE_PATH |
storage_path('logs') |
Dónde busca archivos el visor. |
La ruta está declarada en routes/web.php como Route::get('logs', ...) sin middleware propio, así que no comparte las verificaciones auth y role:admin del grupo admin. Agrégaselas a esa línea antes de desplegar si conservas el visor.
Clear Log Cache vacía los contadores detrás del límite de excepciones. Fuera del entorno local la aplicación no registra cada ocurrencia de una excepción: bootstrap/app.php cuenta las ocurrencias de cada firma de excepción en las llaves de caché exception:{firma}:count y exception:{firma}:last_logged y sólo la reporta en ciertos conteos, nunca dos veces en cinco minutos. La regla completa está en /help/logs-and-debugging. El botón borra toda fila de caché cuya llave empiece con exception: y olvida el contador exception_times guardado en la sesión, así que la siguiente ocurrencia se registra otra vez como si fuera la primera. Sólo funciona cuando el almacén de caché es database (CACHE_STORE=database): con cualquier otro almacén muestra una advertencia y no borra nada. En el entorno local toda excepción se registra y estos contadores nunca se consultan.
Webhook Events abre /admin/webhook-events, una lista de los registros WebhookEvent que escribe el middleware log.webhook. El kit adjunta ese middleware a POST /api/stripe/webhook en routes/api.php, así que cada entrega de Stripe se guarda con su origen, tipo de evento, estado (éxito o fallo), el payload JSON, el estado HTTP con que respondió la aplicación, y el mensaje de error y la traza cuando el manejador lanzó una excepción. La página filtra por origen y tipo de evento, muestra 25 filas por página y abre un evento para leer su payload. Úsala cuando un evento de Stripe no hizo lo que esperabas: la fila te dice si llegó siquiera y cómo respondió la aplicación.
Despliegue
La tarjeta tiene un área de texto, "Execute after pull", prellenada con composer install, y un botón, "Run deploy". El botón hace dos cosas en orden, ambas como procesos de shell iniciados desde la raíz del proyecto con un tiempo límite de 10 segundos cada uno.
git pullde la rama actual desde el remoto actual. La rama esgit rev-parse --abbrev-ref HEAD; la URL del remoto se lee congit remote get-urly se reescribe de la forma SSHgit@host:org/repo.gitahttps://host/org/repo, porque la autenticación va por HTTPS con un ayudante de credenciales que responde con dos variables de entorno.- Las líneas del área de texto, recortadas, unidas con
&&y ejecutadas como un solo comando. Un área de texto vacía omite este paso.
El pull necesita estas dos variables en el .env del servidor. Ninguna está en .env.example porque sólo importan en un servidor que se despliega a sí mismo de esta manera.
| Variable | Para qué se usa |
|---|---|
GIT_USER |
El nombre de usuario que se entrega al remoto de Git por HTTPS. |
GIT_PASSWORD |
La contraseña o token de acceso personal de ese usuario. |
Cuando falta cualquiera de las dos, el botón se detiene con la notificación "GIT_USER or GIT_PASSWORD environment variable is not set" y no corre nada. Los procesos también reciben HOME, COMPOSER_HOME y GIT_TERMINAL_PROMPT=0 para que Composer encuentre su caché y Git nunca espere a que alguien escriba.
Cada paso notifica en pantalla si tuvo éxito o falló. La salida estándar y de error combinada de ambos pasos se escribe en el log de la aplicación como una entrada JSON con el prefijo [DevZone Deployment] en caso de éxito o [DevZone Deployment Error] en caso de fallo, así que el botón "Check logs" es donde lees lo que dijo Composer. Un fallo también pasa por el reporte normal de excepciones.
El límite de 10 segundos está fijo en el componente. Un composer install que tiene que descargar muchos paquetes, o un npm run build, puede excederlo; el despliegue entonces reporta un error aunque el proceso quizá siga corriendo en el servidor. Mantén cortos los comandos posteriores al pull, o corre los largos desde la terminal como se describe en /help/deploy-your-project.
Archivo Env
La tarjeta muestra el contenido actual de .env en un editor de código. "Apply changes" pide confirmación, escribe el contenido del editor sobre el archivo y corre php artisan config:clear, y luego te pide recargar la página.
Vale la pena conocer tres consecuencias antes de usarlo en un servidor:
- La escritura es del archivo completo, no una mezcla. Lo que está en el editor es en lo que se convierte el archivo, incluido lo que hayas borrado por accidente.
config:clearelimina la caché de configuración. A partir de esa petición la aplicación lee.envdirectamente, que es lo que quieres para que el nuevo valor surta efecto, pero también significa que una versión que corrióconfig:cacheahora corre sin caché hasta el siguienteconfig:cache.- El cambio ocurre sólo en este servidor. Otro servidor del mismo despliegue, y tu repositorio, no saben nada de él.
Pruebas
Test WebPush Notification envía App\Notifications\TestWebPushNotification a tu propia cuenta únicamente por el WebPushChannel, ignorando tus preferencias de notificación. Es la forma más rápida de probar que el navegador que usas está suscrito y que las llaves VAPID son correctas: si llega la notificación "Notifications are working", lo son. No llega nada cuando este navegador no tiene suscripción; cómo suscribir uno está en /help/web-push-and-the-pwa.
Test as iOS y Test as Android hacen que la aplicación crea, sólo para tu sesión, que la petición viene de la app móvil nativa. Guardan platform_override en la sesión con el valor ios o android; presionar el mismo botón otra vez ("Stop testing as iOS") lo olvida. Los helpers que toda vista puede llamar leen ese valor:
| Helper | Verdadero cuando |
|---|---|
is_ios() |
La petición trae la cookie app-platform, o la anulación de sesión es ios. |
is_android() |
El encabezado Referer de la petición es exactamente android-app://, o la anulación es android. |
is_mobile() |
Cualquiera de los dos anteriores. |
Están definidos en app/Helpers/base.php. En el kit mismo cambian dos cosas: la landing oculta los enlaces de planes y complementos cuando is_ios() es verdadero, y el middleware IsPWABuilder de la página de inicio redirige a un visitante móvil al dashboard de la app cuando APP_PWA=true. Usa la anulación para ver ambos comportamientos desde un navegador de escritorio, y en tus propias vistas para mostrar u ocultar lo que deba ser distinto dentro de la app nativa:
@if(is_ios())
{{-- se muestra sólo dentro de la app de iOS --}}
@endif
Agrega una herramienta tuya
No hay un registro de herramientas. Una herramienta es un método público en el componente y un botón en la vista, exactamente como las que vienen incluidas.
- Agrega el método a
app/Livewire/Admin/DevZone.php. El componente usa el traitWireUiActionsde WireUi, así que$this->notification()->success(),->warning(),->error()y$this->dialog()->confirm()están disponibles para reportar el resultado o preguntar antes de actuar, como hacechangeEnv(). - Agrega un botón a
resources/views/livewire/admin/dev-zone.blade.php, dentro de uno de los bloques<x-card>existentes o de uno nuevo, conwire:click="tuMetodo". Para cualquier cosa destructiva agregawire:confirm="..."como hace el botón "Clear Log Cache". - Mantén toda cadena que una persona lee dentro de
__()y agrégala alang/en.json, como en el resto del kit.
Como mount() ya aborta para cualquiera que no sea sudo, un método que agregues queda protegido por las mismas dos verificaciones que la página. Si tu herramienta es lo bastante grande para merecer su propia página, registra una ruta Livewire en routes/admin.php, verifica auth()->user()->sudo en su mount(), y agrega una entrada al arreglo items de resources/views/layouts/sidebars/admin.blade.php con 'show' => auth()->user()->sudo para que aparezca sólo a las mismas personas.