# Transicion segura a bases por cliente

## Objetivo de esta fase

Esta fase prepara la infraestructura para soportar bases separadas por cliente sin migrar datos vivos. La base actual `mbinvcxp` sigue siendo la base master temporal y tambien la base `legacy_shared` donde continuan operando los clientes actuales.

Regla principal: no destruir datos existentes.

En esta fase no se debe ejecutar `DROP DATABASE mbinvcxp`, `DROP TABLE` sobre tablas existentes, `TRUNCATE`, deletes masivos, updates masivos de datos operativos ni renombres de tablas.

## Arquitectura

`mbinvcxp` contiene:

- Datos vivos actuales.
- Tablas globales/master necesarias para login, seleccion de cliente/sitio y seguridad.
- Nuevas tablas metadata `tenant_*`.
- Configuracion legacy para clientes actuales en `tenant_databases.modo = 'legacy_shared'`.

Para clientes nuevos se prepara `tenant_databases.modo = 'database_per_client'`. En ese modo, la metadata apunta a una base operativa propia y, opcionalmente, a una base de auditoria/temporales propia.

El runtime sigue apagado por defecto:

```dotenv
TENANT_DATABASE_MODE_ENABLED=0
TENANT_PROVISIONING_ENABLED=0
TENANT_DATABASE_LEGACY_FALLBACK=1
```

Con esos valores, el sistema actual sigue usando la conexion Doctrine `default` y el filtro tenant existente.

## Tablas nuevas de metadata

La migracion `Version20260703120000` y el archivo `sql/tenant_metadata.sql` crean, de forma idempotente:

- `tenant_databases`
- `tenant_installation_log`
- `tenant_migration_log`
- `tenant_provisioning_jobs`

El `down()` de la migracion no elimina esas tablas para evitar perdida accidental de metadata.

## legacy_shared

`legacy_shared` significa que el cliente sigue operando en `mbinvcxp`. Esta modalidad conserva el EntityManager actual, el `TenantFilter` activo y la conexion de auditoria actual.

Para inicializar metadata legacy:

```bash
php bin/console doctrine:migrations:migrate
php bin/console app:tenants:init-metadata
```

El comando lee `clientes` e inserta un registro en `tenant_databases` solo si no existe. No toca documentos, pagos, proveedores, impuestos, usuarios ni sitios.

Para refrescar host/puerto/base de metadata legacy existente:

```bash
php bin/console app:tenants:init-metadata --refresh
```

`--refresh` solo actualiza registros existentes en modo `legacy_shared`.

## database_per_client

`database_per_client` significa que un cliente nuevo puede tener:

- Base operativa propia.
- Base de auditoria/temporales propia.
- Catalogos iniciales propios.
- Impuestos propios.

La clase `App\Tenant\TenantDatabaseProvisioner` prepara este flujo, pero solo ejecuta provisioning si:

```dotenv
TENANT_PROVISIONING_ENABLED=1
```

El provisioner valida nombres de base con whitelist `A-Z`, `a-z`, `0-9` y `_`. Nunca permite provisionar una base llamada `mbinvcxp` y no contiene operaciones para borrar bases.

Tambien rechaza `cliente_id` que ya tengan registro en `tenant_databases`; no es una herramienta para convertir clientes vivos de `legacy_shared` a `database_per_client`.

Los archivos SQL usados por defecto son configurables:

```dotenv
TENANT_SCHEMA_FILE=database/schema/mbinvcxp_schema.sql
TENANT_SEED_FILE=sql/tenant_base_seed.sql
TENANT_AUDIT_SCHEMA_FILE=sql/audit/001_create_audit_events.sql
```

El provisioner omite `CREATE DATABASE`/`USE mbinvcxp` al aplicar el esquema base dentro de la base tenant ya seleccionada.

## Validar conexion

Para validar un cliente:

```bash
php bin/console app:tenant:check --cliente=1
```

Tambien acepta valores no numericos cuando existan columnas aplicables en `clientes`, como `codigo`, `dominio`, `nit`, `nombre` o `nombre_comercial`.

El comando:

- Lee `tenant_databases`.
- Si el modo es `legacy_shared`, valida la conexion actual.
- Si el modo es `database_per_client`, valida la conexion dinamica.
- Valida auditoria si hay base audit configurada.
- No crea ni modifica datos.

## Impuestos

Los impuestos deben vivir en cada base operativa de cliente. No se crea una tabla global unica de impuestos.

Para clientes nuevos, el seed base debe insertar la plantilla inicial de impuestos, incluyendo `cat_impuestos` segun `sql/seed_cxp_gt.sql`. Cada cliente podra modificar sus impuestos en su propia base sin afectar a otros.

Para clientes `legacy_shared`, no se modifican impuestos actuales en esta fase.

## Auditoria y temporales

En `legacy_shared`, `AuditLogger` conserva la conexion Doctrine `audit` actual. Si `AUDIT_DATABASE_URL` no esta configurada, el proyecto ya usa fallback a `DATABASE_URL`.

Para `database_per_client`, `tenant_databases` ya tiene campos `audit_db_*` para que una fase posterior conecte auditoria/temporales por cliente. No se borra `_temporalescxp` actual.

## Doctrine

No se cambia el EntityManager actual ni se modifican entidades en masa. `TenantFilter` sigue activo para `legacy_shared`.

Para `database_per_client`, la infraestructura permite resolver datos de conexion por cliente, pero se mantiene compatibilidad con `cliente_id` y `sitio_id` dentro de cada base.

## Tablas actuales revisadas

Basado en `database/schema/mbinvcxp_schema.sql`, `sql/schema_cxp_gt.sql` y entidades del repo, estas tablas parecen globales/master o de seguridad:

- `clientes`
- `sitios`
- `usuarios`
- `roles`
- `usuarios_sitios_roles`
- `monedas`
- `paises`
- `regimenes_fiscales`
- `tenant_databases`
- `tenant_installation_log`
- `tenant_migration_log`
- `tenant_provisioning_jobs`

Estas tablas parecen catalogos tenant-scoped o parametrizacion por cliente:

- `impuestos`
- `cat_impuestos`
- `retenciones`
- `centros_costo`
- `proyectos`
- `clases_documento`
- `tipos_documento`
- `cat_tipos_documento`
- `condiciones_pago`
- `bancos`
- `cuentas_bancarias`
- `cuentas_contables`
- `cat_clasif_proveedor`
- `tipos_cambio`
- `idp_tasas`

Estas tablas parecen operativas:

- `proveedores`
- `documentos_cxp`
- `documentos_cxp_det`
- `documentos_cxp_retenciones`
- `documentos_cxp_combustible`
- `adjuntos`
- `pagos`
- `pagos_aplicaciones`
- `pagos_vouchers`
- `cheques_pago`
- `transferencias_pago`
- `anticipos_proveedor`
- `anticipos_aplicaciones`
- `ordenes_compra`
- `ordenes_compra_det`
- `oc_documentos`
- `aplicaciones`
- `notas_proveedor`
- `facturas_impuestos`
- `facturas_centros_costo`
- `stg_cargos`
- `stg_abonos`
- `stg_aplicaciones`

Estas tablas o bases parecen de auditoria/temporales:

- `_temporalescxp`
- `audit_events`
- `audit_outbox_events`
- `auditoria_eventos`
- `cloud_sync_logs`
- `async_jobs`

## Pruebas manuales requeridas

1. Levantar el sistema actual y confirmar que login/dashboard siguen funcionando.
2. Ejecutar `php bin/console doctrine:migrations:migrate`.
3. Ejecutar `php bin/console app:tenants:init-metadata`.
4. Confirmar que `tenant_databases` tiene registros para clientes existentes en modo `legacy_shared`.
5. Confirmar que no se elimino ningun documento, pago, proveedor, impuesto ni usuario existente.
6. Crear un cliente de prueba con base separada solo con `TENANT_PROVISIONING_ENABLED=1` y un esquema base validado para bases nuevas.
7. Confirmar que se crea la base operativa.
8. Confirmar que se crea la base temporal/auditoria.
9. Confirmar que `cat_impuestos` existe en la base nueva.
10. Confirmar que modificar impuestos en la base nueva no toca `mbinvcxp`.
11. Confirmar que clientes `legacy_shared` siguen usando `mbinvcxp`.

## Pendiente para fases futuras

- Definir el esquema base completo y seguro para bases nuevas, separado de dumps con `USE mbinvcxp`.
- Crear flujo administrativo/CLI final para alta de cliente nuevo usando `TenantDatabaseProvisioner`.
- Conectar runtime Doctrine dinamico cuando `TENANT_DATABASE_MODE_ENABLED=1`.
- Ajustar auditoria para escribir en la base audit por cliente en `database_per_client`.
- Planear migracion futura de datos vivos cliente por cliente con reconciliacion, pruebas, backups y ventana operacional.
