# AGENTS.md — enterfarmaplus-cuba-porto (feat/cuba-porto-admin)

Este worktree es la migración de shell Cuba -> Porto. Se trabaja acá en paralelo
con Claude Code, misma carpeta, sesiones distintas -- lo que sigue es para no
pisarnos.

## Servidor local
- URL: http://demo.enterfarmaplus.test:8080/ -- Apache, vhost fijo en
  `C:\laragon\etc\apache2\sites-enabled\porto-worktree-8080.conf`.
- NO uses `php artisan serve`. Es single-thread: si una request se cuelga
  (ej. un browser de test que crashea a medio request), el server entero
  muere y deja de responder para siempre hasta reiniciarlo a mano. Ya pasó.
- El tenant se resuelve por match EXACTO de hostname contra `hostnames.fqdn`
  en BD (`app/Tenancy/TenancyManager.php::identify()`), el puerto no cuenta
  para nada. Hoy solo existe la fila `demo.enterfarmaplus.test -> website_id 1`.
  No inventes otro dominio (tipo `porto.enterfarmaplus.test`) sin agregar esa
  fila -- si no, el tenant resuelve null y no vas a ver datos reales.
- Login local: `admin@gmail.com` / `PortoLocal123!`

## Git -- regla dura (viene de CLAUDE.md del repo, no es opcional)
- Antes de cualquier `checkout`/`reset`/`restore`/`clean`: corré `git status`.
  Si hay cambios que no son tuyos, no los toques -- puede ser la otra sesión
  a mitad de algo.
- Commiteá WIP seguido, aunque esté a medias: `git commit -m "wip: ..."`.
  Un commit feo en esta rama es infinitamente mejor que un diff gigante sin
  guardar que la otra sesión puede pisar, o que alguien puede confundir con
  "esto se puede descartar".
- Agregá archivos por path explícito (`git add <archivo>`), nunca `git add -A`
  ni `git add .` -- puede haber cambios sueltos de la otra sesión en el árbol.
- Si necesitás descartar algo tuyo para volver a un estado estable, usá
  `git stash push -u -m "..."`, nunca `reset --hard` / `checkout -- .` en seco.

## Trabajo simultáneo (mismo árbol, al mismo tiempo -- no por turnos)
Se decidió explícitamente NO separar en worktrees. Vos y Claude Code editan
esta misma carpeta en paralelo. Para que no se pisen los cambios en caliente:

- **Carriles por área, no por archivo suelto.** Si los dos están activos a la
  vez, repartirse por zona (ej. "vos backend/rutas/controllers, yo CSS del
  shell") en vez de que ambos toquen el mismo archivo en la misma ventana de
  tiempo -- un archivo pisado a mitad de escritura no es un conflicto de git,
  es pérdida de datos silenciosa (nadie avisa).
- **Antes de arrancar, mirá qué dejó la otra sesión:** `git log --oneline -5`
  y `git status --short`. Si hay diffs sin commitear que no son tuyos, no
  sigas editando esos archivos a ciegas -- puede estar a mitad de un cambio.
- **Recompilá apenas termines un bloque de SCSS/JS** (`npx mix`), no lo dejes
  pendiente. `public/css/porto-app.css` es un archivo compilado que se sirve
  en vivo por Apache -- si lo dejás a medio compilar (o sin compilar) mientras
  la otra sesión está probando en el navegador, ve un estado roto que no es
  el tuyo ni el suyo.
- **No mates ni reinicies el proceso de Apache** (`httpd.exe`, puerto 8080)
  mientras la otra sesión puede estar con el navegador abierto contra
  `demo.enterfarmaplus.test:8080` -- coordiná antes si hace falta.
- **Commits chicos y frecuentes son el mecanismo de "guardado".** No hay
  isolation de worktree que te salve si dejás dos horas de cambios sin
  commitear: eso es exactamente lo que casi se pierde la vez pasada.

## Lo que rompió la app la última vez (no repetir)
- `$isPortoAdmin = true;` hardcodeado en `resources/views/tenant/layouts/app.blade.php`
  -- bypasea el flag real (`Configuration::isPortoAdmin()`). Nunca hardcodear
  esto, siempre pasar por el flag del tenant.
- Un `<script>` con `MutationObserver` que le sacaba las clases
  `sidebar-left-floating` / `sidebar-left-big-icons` al `<html>` apenas se
  agregaban. Esas clases son la base de TODO el CSS del shell (ver bloque
  "Shell Porto (parity con pro9)" en `resources/sass/porto-app.scss`).
  Sacarlas en loop mete al sidebar y al `MutationObserver` a pelear entre sí
  y cuelga/crashea el navegador. Si el sidebar no colapsa/expande bien, el
  fix va en el SCSS o en el JS del theme (`theme.js`) -- nunca en un observer
  que fightea contra la clase desde afuera.

## Build
- Cambios en `.scss` / `.js` no se ven hasta correr `npx mix` (dev, sin
  minificar -- esta rama no es main/prod, no hace falta `mix --production`).

## Nota de sesión (2026-08-12/13) -- header.blade.php clonado 1:1 contra pro9

**Estado: cerrado y verificado.** El header Porto (rama `@if`) ahora es
literalmente el `header.blade.php` de `C:\laragon\www\pro9` (encoding limpio,
sin el mojibake que había quedado antes), con 3 desviaciones deliberadas
contra lo que enterfarmaplus SÍ tiene y pro9 no:

1. **`<tenant-hotel-sucursale>` (Hotel module de pro9, no existe acá) ->
   reemplazado por el selector de sucursal REAL** (`$vc_can_switch_establishment`
   + `$vc_allowed_establishments` + el script de confirm/POST a
   `tenant.establishment_context.switch`, portado tal cual de la rama Cuba/main).
   Vive dentro de `.dropdown-menu-desktop`, mismo lugar que pro9 usaba para su
   selector.
2. **`<tenant-dedicated-group-selector>` (feature "grupo dedicado" de pro9,
   series por equipo) -> eliminado**, enterfarmaplus no tiene ese concepto.
   No inventar un backend para esto sin que el usuario lo pida.
3. **`<tenant-notifications-header>` -> portado de verdad**: nuevo componente
   Vue3 `resources/js/views/tenant/layouts/partials/notifications_header.vue`
   (clon de `NotificationHeader.vue` de pro9, adaptado a Element Plus 2 /
   `#dropdown` slot / `beforeUnmount`), registrado en `app.js`. Necesita un
   endpoint que pro9 sí tenía y enterfarmaplus no: `GET documents/not-sent/count`
   -> agregado en `modules/Document/Routes/web.php` +
   `DocumentController::notSentCount()` (reusa `Document::whereNotSent()`).

Bugs reales que NO son de este header -- vienen de que la copia vendorizada
de `public/porto-light/` en este repo es una version mas vieja que la de
pro9 y le faltan reglas que pro9 sí trae en su propio `theme.css`/`custom.css`
(ver "Riesgo a vigilar" en el plan de migración). Las repliqué a mano en
`porto-app.scss`, bajo `html.fixed.sidebar-left-floating .header`:
- `.btn-sunat` sin `display:flex;flex-direction:column` -> el badge SUNAT se
  aplastaba en desktop (el override viejo de la tablet-only media query se
  filtraba a todos los anchos, ya limpiado).
- `.dropdown-menu-desktop` sin `position:absolute`/`visibility:hidden` base ->
  el dropdown de perfil nunca se podía abrir. Y faltaba el JS que le pone
  `.active` al click (`.check-double` -> tomado de `dom-fixes.js` de pro9,
  agregado a mano en `resources/js/app.js`, ver comentario ahí).

**Si tocás este header de nuevo:** ojo con escribir la palabra `@else` (o
`@if`/`@endif`) suelta en un comentario `//` de JS -- Blade no sabe que está
dentro de un comentario y lo compila como directiva real. Me pasó armando el
script del selector de sucursal, rompió TODO el archivo con un
"unexpected token else" bien confuso de debuggear. Si necesitás nombrar el
otro branch en un comentario, escribí "el bloque Cuba" en vez de "@else".

Verificado con Playwright: desktop (1440px), tablet (900px), mobile (390px)
+ drawer, campana de notificaciones (dato real vía polling), dropdown de
perfil, cambio de sucursal (dialogo confirm completo, cancelado a propósito
para no mutar la sesión de prueba), consola limpia (los 2 errores que quedan
son el logo `logo_00000000000.png` faltante en storage de ESTE tenant demo,
dato preexistente, no del header). Rama Cuba (`@else`) verificada
byte-idéntica a `enterfarmaplus/resources/views/tenant/layouts/partials/header.blade.php`
(main) con `diff --strip-trailing-cr`.

## Último estado verificado y estable
- Commit `ba94b898` -- shell del sidebar/header reconstruido desde cero,
  verificado en vivo con Playwright: 7 ciclos toggle, hover-expand, 10 anchos
  de viewport, mobile, árbol de menú completo, logo visible, sin drift de
  scroll. Si algo se rompe feo y no se puede arreglar rápido, la salida
  segura es volver acá (`git stash push -u` para no perder el WIP propio, no
  `reset --hard`) en vez de seguir parchando sobre un estado roto.
