# Desarrollo reproducible de LEGAL-CMH

## Preparar otra estación

La aplicación debe funcionar a partir de un clon limpio, sin recuperar código ni
migraciones de otra computadora. Configure únicamente el entorno privado y los
servicios de la estación; no cambie modelos, rutas ni reglas de PHPStan para
adaptarlos a una base de datos local.

Siga primero la [instalación del README](../README.md#instalación-nueva-wsllinux):

1. Compruebe PHP y extensiones con las restricciones de `composer.lock`.
2. Ejecute `composer install --no-plugins --no-scripts --prefer-dist`, nunca
   `composer update` para reproducir una instalación existente.
3. Ejecute `composer check-platform-reqs`.
4. Cree `.env` desde `.env.example` solamente si todavía no existe y configure
   credenciales propias. No copie secretos ni claves de otra estación.
5. Genere `APP_KEY` solo en una instalación nueva con la clave vacía y complete
   `php artisan package:discover` como indica el README.
6. Revise el destino y las migraciones. Aplíquelas únicamente con autorización y
   respaldo cuando corresponda; no use `migrate:fresh` para actualizar datos.

El frontend actual usa Blade y recursos locales. No necesita npm ni compilar Vite,
y el repositorio no incluye `package.json` ni configuración de Vite.

## Archivos que deben viajar con el repositorio

- `composer.json` y `composer.lock`.
- Todo el historial PHP de `database/migrations/`, incluidas las migraciones
  iniciales de Laravel y las cargas controladas de permisos y catálogos.
- Código, configuración, `.env.example`, documentación y recursos frontend
  locales utilizados por la aplicación.

Las pruebas unitarias (`tests/` y `phpunit.xml`) son de uso local: están en
`.gitignore` y no se versionan ni llegan al servidor de producción.

Las migraciones se versionan tanto en Laravel como en Django. Larastan también
utiliza ese historial para inferir columnas y tipos de los modelos. Agregar
anotaciones para ocultar un esquema ausente no hace reproducible una instalación.

No se versionan `.env`, bases SQLite, respaldos SQL con datos reales, secretos,
`vendor/`, cachés, sesiones, logs ni archivos compilados. Las reglas de
`database/.gitignore`, `bootstrap/cache/.gitignore` y `storage/` se conservan.

Si una computadora tiene archivos que no aparecen en un clon nuevo, revise las
exclusiones antes de agregar código sustituto:

```bash
git ls-files -- database/migrations
git ls-files --others --ignored --exclude-standard -- database/migrations docs
git check-ignore -v --no-index database/migrations/0001_01_01_000000_create_users_table.php
```

`git check-ignore` devuelve código 1 si no hay una regla que ignore ese archivo.
Revise también `.git/info/exclude` y las exclusiones globales: no se comparten
mediante Git y pueden ocultar archivos necesarios incluso cuando `.gitignore`
no los menciona. Retire únicamente las reglas incorrectas, manteniendo las que
protegen archivos privados. No use `git add -f` como solución permanente.

## Calidad sin modificar el código

Desde la raíz de la aplicación:

```bash
composer lint
composer build
```

`lint` ejecuta Pint en modo de comprobación y PHPStan/Larastan. `build` agrega la
validación estricta de Composer; no ejecuta migraciones ni compila el frontend.
No hace falta migrar una base de trabajo para corregir errores de inferencia.
No reduzca el nivel del análisis ni agregue exclusiones para ocultar un esquema
incompleto. `composer format` sí modifica el código y es una operación distinta.

`composer audit --locked` es una verificación separada: informe sus avisos aunque
lint y build pasen. No actualice dependencias como efecto secundario de
sanear archivos faltantes.

## Verificar un clon limpio

Con los avances confirmados localmente, puede crear otra copia independiente en
un directorio nuevo y vacío. Sustituya los marcadores por su origen y su rama:

```bash
git clone --single-branch --branch <rama-a-validar> <origen> <directorio-nuevo>
cd <directorio-nuevo>
composer install --no-plugins --no-scripts --prefer-dist
composer check-platform-reqs
composer lint
composer build
git status --short
```

No copie `.env`, migraciones ignoradas ni `vendor/` desde la estación original.
Las comprobaciones de código deben pasar con los archivos versionados y las
dependencias de `composer.lock`, sin editar el código del clon. La instalación
funcional sobre MySQL requiere además el entorno privado y el procedimiento de
migración autorizado del README.

## Correo en desarrollo

El correo local usa el Mailpit de `local_infrastructure` (SMTP `127.0.0.1:1025`,
visor <http://localhost:8025>); consulte el
[servicio de correo](../README.md#servicio-de-correo). Las pruebas automatizadas
usan el mailer `array` o transportes sintéticos y la cola `sync`, `Queue::fake()`
o una cola `database` en SQLite: ninguna envía a un servidor real ni modifica
`legal_db`. Para ver una plantilla en Mailpit use
`php artisan correo:probar <destinatario>`; si necesita una base para esa
comprobación, use una SQLite temporal y no aplique migraciones a una base de
trabajo sin autorización.

Para revisar las plantillas sin enviarlas use
`php artisan correo:previsualizar verificacion-correo` o
`php artisan correo:previsualizar correo-rectificado`. El correo de recuperación
también puede revisarse sin envío con
`php artisan correo:previsualizar recuperacion-contrasena`; usa un token sintético.
La verificación del portal está activa por defecto y las cuentas nuevas no
tienen correo verificado. Sus pruebas cubren, entre otros casos, el reenvío en
cola y los fallos posteriores al commit; usan exclusivamente SQLite aislada.
La rectificación requiere el permiso exclusivo `users.change_email` y un motivo
de auditoría. Las migraciones del correo y la verificación se aplican a una base
de trabajo únicamente con respaldo, destino revisado y autorización.

La recuperación médica usa el broker de contraseñas de Laravel y el mismo
identificador exacto del acceso. El flujo HTTP, el worker, los límites y las
sesiones pueden probarse con SQLite temporal y Mailpit, nunca con `legal_db` ni
cuentas reales. El enlace inicial contiene un token: no lo incluya en informes,
capturas ni logs. Las cabeceras de la aplicación no sustituyen la redacción de
URLs sensibles en servidores, proxies y monitoreo. Para que los límites funcionen
entre procesos se requiere caché compartida con incrementos atómicos; la
concurrencia de tokens y bloqueos debe validarse por separado en MySQL aislado.

## Commits locales

Seleccione explícitamente los archivos de cada avance. `composer commit` prepara
un Conventional Commit en español, requiere staging y confirmación y no publica
cambios. No incluya secretos, datos reales o archivos generados para conseguir que
el estado del repositorio quede limpio.
