# Evidencias y Normativa

Los modulos `Evidencias` y `Normativa` comparten la capa global de usuarios para que informes, clientes, Charlie y otros modulos puedan leer o escribir documentacion sin duplicar roles.

## Evidencias

`Evidencias` guarda archivos, fotos y documentos trazables en `data/evidence/` y registra los metadatos en SQLite. Cada evidencia puede enlazarse a un informe con `report_id`, etiquetas y notas operativas.

Las fotos recibidas desde el formulario publico de alta de cliente se copian automaticamente a `data/evidence/` y quedan etiquetadas como `alta-cliente`, `cliente:{id}` e `invitacion:{id}`. La copia de Evidencias es independiente de la miniatura/archivo usado por `Clientes > Documentos`, por lo que borrar una evidencia no rompe `onboardingPhotos`.

| Ruta | Metodo | Permiso | Descripcion |
| --- | --- | --- | --- |
| `/api/evidence` | `GET` | `evidence.read` o `evidence.write` | Lista evidencias, opcionalmente por `reportId` o `tag`. |
| `/api/evidence` | `POST` | `evidence.write` | Sube archivo en base64 con nombre, tipo, etiquetas, notas e informe asociado. |
| `/api/evidence/{id}` | `GET` | `evidence.read` o `evidence.write` | Descarga la evidencia usando la sesion actual. |
| `/api/evidence/{id}` | `DELETE` | `evidence.write` | Borra el archivo fisico y su fila de metadatos. |

La UI oculta las acciones destructivas y deshabilita la seleccion de archivo si el usuario solo tiene lectura. Las descargas usan `apiRequest()` para enviar `Authorization: Bearer <token>`.

La interfaz usa `master-detail` y empieza en `Evidencias`. El índice ofrece una
búsqueda única por nombre, etiqueta, nota, autor o informe, pagina los resultados
de 25 en 25 y convierte cada registro en una fila seleccionable. Las filas no
repiten botones: seleccionar una abre `Ficha`, donde aparecen una sola vez
`Abrir archivo` y, si existe `evidence.write`, `Borrar`.

`Nueva evidencia` abre un modo de subida exclusivo. El informe asociado,
etiquetas y notas se aplican a uno o varios archivos y se conservan los IDs
`evidenceReportSelect`, `evidenceTagsInput`, `evidenceNotesInput`,
`selectEvidenceBtn` y `evidenceUpload`. Tras subir, la ficha selecciona el último
archivo creado. Cancelar o borrar devuelve al índice. Los usuarios con solo
lectura conservan búsqueda, paginación, ficha y descarga, pero no ven creación ni
borrado.

El mismo modo ofrece `Desde biblioteca` mediante
`AnimalCharlieAssetLibrary.mountFileInput(...)`. La selección común respeta
`evidence.write` y entra por `uploadEvidence(...)`, por lo que mantiene informe,
etiquetas, notas, autoría y auditoría sin duplicar la lógica de Evidencias.

`tools/verify_evidence_ui.py` prueba los cuatro dispositivos, dos páginas,
búsqueda, ficha, subida, descarga y borrado. Cuando la copia temporal no contiene
26 evidencias, crea por API las mínimas necesarias para probar la paginación y
elimina tanto esas filas como sus archivos físicos al terminar.

## Normativa

`Normativa` mantiene la biblioteca legal editable por pais, especie, estado, fechas de vigencia y URL oficial. Los informes la consultan como referencia documental, pero la edicion queda separada del editor de informes.

La UI usa `master-detail` exclusivo y entra por `Normas`; no existe una vista
`Ambas`. El directorio muestra búsqueda, contador, diez filas por página y un
plegable `Filtros` cerrado por defecto con país, especie y estado. Cada fila es
completa y activable, sin botones repetidos, y resume país/especie en una sola
línea para no recortar texto en iPad Air vertical. La paginación reserva a la
derecha el carril del botón flotante de Charlie, que nunca puede tapar `Siguiente`.

`Nueva norma` o seleccionar una fila abre `Editor` a ancho completo. Guardar,
abrir fuente y volver viven en la cabecera común; actualizar, documentación y
eliminar permanecen en `Más`. `Vigencia y estado` conserva estado y fechas en un
plegable secundario cerrado inicialmente, y borrar exige confirmación. Los
filtros del directorio son distintos de los campos país/especie del documento.
Al guardar una norma ya seleccionada se envía su `id`, por lo que se actualiza la
entrada existente sin crear duplicados.

La prueba `tools/verify_legal_ui.py` recorre búsqueda, paginación, filtros,
apertura, alta, vuelta y cancelación de borrado en PC, Galaxy Tab A9+ e iPad Air.
Si la biblioteca temporal no llega a once normas, crea las entradas mínimas para
probar dos páginas y las desactiva al terminar.
Cuando recibe `--screenshots`, reutiliza el capturador común y solo acepta
secuencias de viewports reales con `capture-manifest.json` y caché verificada después del
último scroll.

| Ruta | Metodo | Permiso | Descripcion |
| --- | --- | --- | --- |
| `/api/legal` | `GET` | `legal.read` o `legal.write` | Lista normas activas filtrables por `country`, `species` y `status`. |
| `/api/legal` | `POST` | `legal.write` | Crea o actualiza una norma. |
| `/api/legal/{id}` | `DELETE` | `legal.write` | Marca la norma como inactiva. |

La navegacion del modulo acepta `legal.read` o `legal.write`. La UI permite guardar o borrar solo con `legal.write`.

## Adjuntos de informes

Los adjuntos de informes permanecen bajo permisos de Certificacion porque dependen de un `report_id`:

- `GET /api/reports/{id}/attachments` y `GET /api/reports/{id}/attachment/{attachmentId}` usan lectura de informes (`reports.read`, `reports.write` o `reports.review`).
- `POST /api/reports/{id}/attachments` usa `reports.write`.

## Auditoria

Las operaciones dejan eventos normalizados:

- `evidence_upload`, `evidence_download`, `evidence_delete`.
- `legal_save`, `legal_delete`.
- `attachment_upload`, `attachment_download`.

Los historicos de usuario consumen estos eventos desde `/api/users/{username}/history` y `/api/activity`, donde el modulo se deduce como `evidence`, `legal` o `bea` segun entidad y accion.
