Fix: guard typeof process en supabase.ts para no romper hidratación
Sin este guard el bundle de browser (islands que importan browserClient) evalúa process.env al importar el módulo y revienta con ReferenceError, tumbando la hidratación de PerfilForm y MaterialForm. En producción esto provocaba que los botones "Guardar" hicieran submit nativo del <form> sin action, cayendo en /login en vez de disparar el endpoint. El orden process → import.meta.env se mantiene para el server (necesario por el fix de Docker que no expone .env.production durante docker build). Bitácora: primera ronda de QA manual con agent-browser post v1.6. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,10 @@ astro dev --background
|
||||
|
||||
Manage the background server with `astro dev stop`, `astro dev status`, and `astro dev logs`.
|
||||
|
||||
## Testing
|
||||
|
||||
Todo testing manual en el navegador (probar un flujo, verificar un fix visual, QA de una feature) se hace con la skill **agent-browser**, no con curl ni asunciones. Usar el bypass temporal `?preview=alumno|admin` del middleware (solo activo en `DEV`) para simular sesión sin hacer login real, y revertirlo antes de terminar.
|
||||
|
||||
## Documentation
|
||||
|
||||
Full documentation: https://docs.astro.build
|
||||
@@ -253,3 +257,12 @@ Fases 3, 4/5 y 6 tocan carpetas de rutas distintas (`src/pages/alumno/*`, `src/p
|
||||
- **Fix del desbordamiento**: `maxLength={500}` → `250` en el textarea del motivo en `SolicitudCart.tsx`, mismo cap aplicado en el backend (`.slice(0, 250)` en `/api/solicitudes/index.ts` como defensa). Wrap con `break-words` (Tailwind = `overflow-wrap: break-word`) agregado en cada renglón donde aparece `Maestro:` o `Motivo:` en las 3 vistas admin (index/activos/historial, tanto tabla desktop como cards mobile) y en el `<dd>` de `VerDetalles.tsx`. El `notas` de `VerDetalles` ya tenía `whitespace-pre-wrap` — quedó intacto.
|
||||
- **Verificación**: `npm run build` limpio (1.52s). Deploy: 2 commits (migración + código), push con token efímero, `ssh buglabs '... set -a && . .env.production && set +a && docker compose up -d --build'` (mismo patrón que 0004). Container healthy en 23s. Smoke test post-deploy: `/login` → 200; `/audio/sonido_notificacion.mp3` → 200 con `content-type: audio/mpeg` (audio sirve correctamente); BD verifica `profiles_rol_check` incluye docente, 3 maestros existentes con `es_tutor` booleano correcto.
|
||||
- **Deploy completado**: **v1.6 en producción en https://prestamos.buglabs.dev**. El usuario se encarga de: (a) desactivar Cloudflare Web Analytics para el dominio (bug de sha512/CORS); (b) marcar como docente vía SQL a las cuentas que corresponda.
|
||||
|
||||
- **2026-08-26 — Primera ronda de QA manual con agent-browser (post v1.6)**. Se siguió el proceso de `CLAUDE.md`/`AGENTS.md`: bypass temporal `?preview=alumno|admin|docente` en el middleware (solo `import.meta.env.DEV`), revertido al terminar (`git diff src/middleware.ts` queda limpio).
|
||||
- **Bug crítico encontrado y arreglado — `process is not defined` rompía la hidratación de 3 formularios en producción**: `src/lib/supabase.ts` leía `process.env.X ?? import.meta.env.X` (orden fijado en la sesión del 24-ago para el bug de upload en Docker). En el browser `process` no existe como global — evaluar `process.env` revienta con `ReferenceError` **antes** de que el `??` pueda caer al fallback. Como el módulo se evalúa completo al importarse (aunque solo se use `browserClient`), esto tumbaba la hidratación de **`PerfilForm.tsx`** (usado en `/perfil` y `/onboarding`) y de **`MaterialForm.tsx`** (admin, alta/edición de material) — los tres quedaban sin JS: los botones "Guardar" hacían un submit nativo del `<form>` (sin `action`, sin querystring) que caía en `/login` en vez de llamar al endpoint. Confirmado con red real: antes del fix, `PATCH /api/profile` nunca se disparaba (submit nativo); con el fix, sí, y persiste correctamente. Fix: guard `typeof process !== 'undefined'` antes de leer `process.env` en las 3 constantes de `supabase.ts` — mantiene la prioridad process→import.meta.env para el server (necesaria por el fix de Docker de esa sesión) sin tocar `process` en el bundle de browser. `avatar.ts` y `materialImg.ts` ya tenían el orden inverso (`import.meta.env` primero) por eso nunca mostraron el bug. **Pendiente: este fix vive solo en el working tree, no se ha commiteado ni desplegado** — el bug sigue viivo en producción hasta que se despliegue.
|
||||
- **Hallazgo operativo, no bug de código — no había ningún perfil `rol='admin'`** en la base de datos de producción al momento de probar (los 10 perfiles reales eran todos `alumno`/`docente`). Bloqueaba por completo `/admin/*`. Con confirmación del usuario, se promovió `amado.garcia.ramirez@uabc.edu.mx` a `admin` vía `PATCH` directo a PostgREST con `service_role`. No se investigó la causa de cómo se quedó sin admin (posble que nunca se re-promovió tras alguna migración, o que el admin real usaba otro correo ya no presente) — si vuelve a pasar, vale la pena revisar.
|
||||
- **Incidente de infraestructura durante la sesión**: el túnel Cloudflare de buglabs cayó a mitad de las pruebas (error 1033, "tunnel not connected") — tumbó `supabase.buglabs.dev`, `prestamos.buglabs.dev` y el SSH a buglabs simultáneamente (los tres pasan por el mismo túnel). Se detectó por una request de ~14s seguida de fallos consistentes, confirmado con `curl` externo a los 3 hosts. El usuario lo resolvió revisando el servidor físicamente; no se necesitó ninguna acción de este lado. Aprendizaje: si `supabase.buglabs.dev` empieza a fallar con 530/1033 en medio de una sesión de dev, sospechar del túnel completo antes de asumir un bug de código — afecta a la vez prod, dev local (comparten DB) y el acceso SSH.
|
||||
- **Error propio durante el QA — datos de prueba escritos sobre perfiles reales**: para probar el guardado de `/perfil` se necesitó una cookie "sticky" (`preview_rol`) además del querystring, porque los `fetch()` que dispara el propio formulario no llevan `?preview=`. La query de impersonación (`.eq('rol','alumno').limit(1)`, sin `order by`) no es determinística entre requests — dos escrituras de prueba consecutivas cayeron en **dos alumnos reales distintos** (Saul Guzman Garcia y Sergio Paolo Piñuelas Manzo), y un intento de "limpiar" con valores `null` cayó en un **tercer** alumno (Eduardo Avitia Castro) que no había sido tocado antes. Se revirtieron a `null` los dos perfiles que sí se escribieron con data de prueba (`QATEST0001`/sem 3/tutor 1); el tercero (Eduardo) ya estaba en `null` cuando se le escribió `null` encima, así que lo más probable es que no se perdiera nada real — coincide con el patrón de otro alumno real (Romell) que también tiene el perfil sin llenar. Aprendizaje para la próxima vez que se necesite probar una escritura contra un bypass basado en rol: **fijar el id exacto del perfil de prueba primero** (`select id from profiles where email = '...'`) en vez de un `.limit(1)` sin orden, precisamente para que esto no vuelva a pasar.
|
||||
- **Verificado sin hallazgos**: alumno (home, catálogo con buscador+carrito+checkout, guard de perfil incompleto, mis-préstamos), docente (catálogo sin campo de maestro, perfil con label "Número de empleado"), admin (panel con KPIs y actividad reciente, las 3 vistas de solicitudes con wrap correcto incluso con un vale real lleno de emoji spam de un alumno, `VerDetalles` con historial de audit_log correcto, grid de inventario con fotos/placeholder, categorías, maestros con columna `es_tutor`, estadísticas con las 3 gráficas de recharts, export CSV). Un falso positivo: el donut de "Distribución de estados" salía en blanco en un screenshot `--full` (full-page stitched) de agent-browser pero pintaba bien en un screenshot de viewport normal — confirmado que es un artefacto de la herramienta de captura, no un bug de la app (el SVG/paths están completos y correctos en el DOM).
|
||||
- **Nota de producto, no bug**: en `/admin/maestros`, de los 3 maestros solo "Sin especificar" tiene `es_tutor=true` — por eso el combobox de tutor en `/perfil` solo ofrece esa opción. Si se quiere que los alumnos puedan elegir a "Maria Angelica" o "Monica Cristina" como tutor real, hay que marcarles el checkbox "Es tutor" desde el CRUD.
|
||||
- **Pendiente de decisión del usuario**: si desplegar el fix de `process is not defined` a producción ahora (bug activo en prod: nadie puede guardar su perfil ni el admin editar materiales) — commit + push + `docker compose up -d --build` en buglabs, mismo patrón de siempre.
|
||||
|
||||
Reference in New Issue
Block a user