# Decisiones y deuda técnica

Por qué el sistema es como es, y qué cosas conviene saber antes de tocarlo.

## Decisiones tomadas a propósito

### Migración gradual, sin corte

Conviven el sistema original (archivos en la raíz) y el nuevo (módulos). No hubo una reescritura de golpe.

**Por qué:** el laboratorio opera todos los días. Una reescritura completa implicaba congelar el desarrollo o mantener dos sistemas en paralelo.

**Costo:** hay que saber en cuál de los dos está el código de cada pantalla. Los `lab_*` suelen estar en la raíz; el turnero está en el módulo.

### Sin framework de frontend

Las vistas son PHP que emiten HTML, con JavaScript embebido en la misma vista.

**Por qué:** despliegue por `git pull`, sin build ni compilación. Un archivo se edita y ya está en producción.

**Costo:** hay código repetido entre vistas, y las vistas grandes (el turnero) pasan de las 2.000 líneas.

### Esquemas de formulario en JSON

Los formularios se definen en JSON dentro de `lab_formularios.esquema`, no en tablas normalizadas.

**Por qué:** las fichas clínicas cambian seguido y cada una tiene campos distintos. Normalizarlas obligaba a migrar el esquema con cada formulario nuevo.

**Costo:** no se puede consultar por SQL «todos los pacientes con fiebre». Las respuestas viven dentro de un JSON.

### La identidad de quien firma se resuelve en el servidor

Nunca se acepta del navegador quién firmó algo.

**Por qué:** es un dato con valor legal. Un cliente puede mentir; la sesión no.

### El turno original nunca se modifica

Cuando una muestra pendiente se completa en una visita posterior, el turno original **queda como estaba**. Solo se registra el vínculo.

**Por qué:** el turno cerrado es un registro histórico. Alterarlo retroactivamente falsea los tiempos de atención y la facturación de aquel día.

### Inventarios generados, no escritos

Las tablas de módulos, endpoints, tablas y roles de esta documentación se leen del código y la base en cada carga.

**Por qué:** una lista escrita a mano envejece sin que nadie se entere. Una generada no puede mentir.

## Deuda técnica conocida

### Columnas `can_*` que no hacen nada

`role_modules` tiene `can_view`, `can_create`, `can_edit`, `can_delete`, `can_export` — y **el control de acceso no las lee**. Solo usa `permission` (`read`/`write`).

**Riesgo:** poner `can_edit = 0` da falsa sensación de haber restringido algo. Ya causó confusión.

**Arreglo:** o se usan de verdad, o se eliminan. Mientras tanto, conviene mantenerlas coherentes con `permission`.

### `role` y `role_id` duplicados

Un usuario tiene el rol en dos columnas. La interfaz lee una, los permisos salen de la otra.

**Riesgo:** cambiar solo `role` deja al usuario con permisos que no corresponden.

**Arreglo:** derivar `role` de `role_id` en lugar de almacenarlo.

### Dos vías para el mismo formulario

`turnero_consentimientos` y `lab_form_envios` guardan lo mismo con estructuras distintas y tokens de formato distinto. `ver_formulario_enviado.php` tiene que manejar ambos, y `form_cliente.php` existe solo para redirigir entre ellos.

**Por qué sigue así:** unificarlas obliga a cambiar la plantilla aprobada en Meta y migrar los registros históricos.

### Convenciones de nombre mezcladas

Conviven `creado_at` y `created_at`, `creado_por` y `enviado_por`, español e inglés. Depende de la época de cada tabla.

### Vistas muy grandes

`ver_formulario_enviado.php` supera las 3.000 líneas y mezcla render, lógica de tomas prolongadas y JavaScript. Es el archivo más delicado de tocar del sistema.

### Datos históricos incompletos

Algunas columnas se agregaron después y las filas viejas quedaron en `NULL`, sin forma de recuperarlas:

| Columna | Desde | Antes |
|---|---|---|
| `turnero_consentimientos.creado_por` | 3 ago 2026 | `NULL` |
| Identidad por toma en F-LAB-28 | 3 ago 2026 | No se guardaba |
| `admin_users.cedula` | 3 ago 2026 | Solo enfermeros la tenían |

No hay traza de auditoría que permita reconstruirlos.

### El dominio se deduce de cada petición

`APP_URL` sale del `HTTP_HOST`. Si alguien entra por una IP o un dominio alterno, los enlaces que se generen llevarán esa dirección — y quedan guardados así en el WhatsApp del paciente.

**Arreglo:** fijar `APP_URL` explícitamente.

## Al hacer cambios

- **Cambio de esquema** → deje la migración en `migrations/`, idempotente.
- **Endpoint nuevo** → verifique permisos ahí adentro, no confíes en la vista.
- **Tocar el turnero** → es lo que más gente usa a diario; pruebe con un turno real.
- **Tocar formularios firmados** → tienen valor legal. Un render roto es un documento inválido.
