# ESQUEMA DE BASE DE DATOS — `recargas_2` **Motor:** MySQL 5.6.51-google-log (Google Cloud SQL) **Tablas base:** 79 · **Vistas:** 6 · **Extraído:** 2026-08-12 por introspección de `information_schema` > Restricciones de MySQL 5.6 que condicionan cualquier diseño sobre este esquema: sin > tipo `JSON` nativo, sin CTE, sin funciones de ventana, y prefijo de índice limitado a > 767 bytes por columna (191 caracteres con `utf8mb4`). --- ## TABLAS CENTRALES DEL DINERO ### `transacciones` — 48,151 filas Registro maestro. `xid` tiene índice `UNIQUE`, lo que la convierte en el anclaje natural de la idempotencia. Índices sobre `estado`, `created_at`, `(empresa_id, created_at)`, `api_reference`, `request_id` y `token_id`. **No tiene clave foránea hacia `empresas`** y hay 166 filas con `empresa_id` NULL. Estados (`ENUM`): `pendiente`, `procesando`, `completada`, `fallida`, `anulada`. ### `empresas` — 368 filas Comercios afiliados. Ya incluye la infraestructura de API: `api_enabled`, `api_key` (UNIQUE), `api_secret_hash`, `api_webhook_url`, `ambiente` (`production`/`development`), `api_last_access`. Contiene `saldo_actual`, que **duplica** el de `empresa_balances` y ya diverge en 96 casos. ### `empresa_balances` — 195 filas Fuente de verdad del saldo para la API v1. `UNIQUE (empresa_id)` y FK a `empresas` con `ON DELETE CASCADE`. Campos: `saldo_actual`, `saldo_disponible`, `saldo_retenido`, límites diario/semanal/mensual, `tipo_credito` (`prepago`/`postpago`). ### `movimientos_balance` — 932 filas Libro mayor. `ENUM` de tipos: `recarga`, `debito`, `credito`, `ajuste`, `reversion`, `comision`, `penalizacion`. **Solo 1 asiento de tipo `debito`** frente a 43,123 transacciones cobradas: el sistema legado nunca escribió aquí los débitos. Ver `SECURITY_AUDIT.md` M-02. --- ## SISTEMA DE CREDENCIALES DE API | Tabla | Filas | Uso | |---|---|---| | `api_tokens` | 360 | `api_key` (UNIQUE) + `api_secret`, estado, límite diario, expiración | | `api_token_permissions` | 4 | Permisos por token — **prácticamente sin usar** | | `api_permisos` | 0 | Permisos por categoría de endpoint | | `api_token_logs` | 4 | | | `api_token_ips` | 0 | Lista blanca de IPs | | `api_endpoints` | 1 | Catálogo de endpoints | | `api_credentials` | 0 | Vacía | `api_tokens.api_secret` guarda el secreto **en texto plano** en 347 de 360 filas. --- ## TABLAS NUEVAS DE LA API v1 (migración 2026_08_12_000001) | Tabla | Función | |---|---| | `api_idempotency_keys` | `UNIQUE (empresa_id, idempotency_key)` — impide el doble cobro | | `api_rate_counters` | `UNIQUE (token_id, ventana)` — contador atómico por minuto | | `api_audit_log` | Auditoría append-only de operaciones | --- ## ANOMALÍAS DETECTADAS | Anomalía | Detalle | |---|---| | Colaciones mezcladas | `transacciones` es `utf8mb4`; `empresas`, `empresa_balances` y `movimientos_balance` son `utf8_unicode_ci`. Los JOIN convierten colación y descartan índices | | Saldo duplicado | `empresas.saldo_actual` vs `empresa_balances.saldo_actual` — 96 divergencias | | Vista rota | `v_transacciones_super_master` referencia objetos inexistentes | | ENUM inválido | 8 filas con `empresas.ambiente = ''` | | Hashes corruptos | 7 `api_secret_hash` de longitud 16/18/27/34 (bcrypt siempre mide 60) | | Tablas sin purga | `oauth_states` 55,386 filas · `proyecto_webhook_logs` 38,417 | | Tablas vacías | 13 tablas de funcionalidades nunca implementadas | --- ## VISTAS `v_estadisticas_diarias` · `v_estadisticas_diarias_empresa` · `v_estadisticas_por_proyecto` · `v_empresas_performance` · `v_empresas_con_proyecto` · `v_transacciones_detalle` · `v_transacciones_super_master` (**rota**) --- ## CLAVES FORÁNEAS (38) | Origen | | Destino | |---|---|---| | `alertas_sistema.empresa_id` | → | `empresas.id` | | `alertas_sistema.usuario_id` | → | `usuarios.id` | | `api_permisos.token_id` | → | `api_tokens.id` | | `api_request_logs.token_id` | → | `api_tokens.id` | | `api_request_logs.empresa_id` | → | `empresas.id` | | `api_tokens.empresa_id` | → | `empresas.id` | | `api_token_ips.token_id` | → | `api_tokens.id` | | `api_token_logs.token_id` | → | `api_tokens.id` | | `api_token_permissions.token_id` | → | `api_tokens.id` | | `api_token_stats.token_id` | → | `api_tokens.id` | | `audit_logs.usuario_id` | → | `usuarios.id` | | `audit_logs.empresa_id` | → | `empresas.id` | | `codigos_verificacion.cliente_id` | → | `clientes.id` | | `comisiones_calculadas.empresa_id` | → | `empresas.id` | | `comisiones_calculadas.servicio_id` | → | `servicios.id` | | `comisiones_calculadas.transaccion_id` | → | `transacciones.id` | | `comprobantes_pago.cliente_id` | → | `clientes.id` | | `empresa_balances.empresa_id` | → | `empresas.id` | | `empresa_comision.esquema_id` | → | `esquemas_comision.id` | | `empresa_comisiones.empresa_id` | → | `empresas.id` | | `empresa_comisiones.servicio_id` | → | `servicios.id` | | `empresa_comisiones.esquema_id` | → | `esquemas_comision.id` | | `empresa_cuentas_bancarias.empresa_id` | → | `empresas.id` | | `empresa_cuentas_bancarias.banco_id` | → | `bancos.id` | | `empresa_plantilla.plantilla_id` | → | `plantillas_comisiones.id` | | `empresa_usuarios.empresa_id` | → | `empresas.id` | | `esquemas_comision.created_by` | → | `usuarios.id` | | `jwt_tokens.usuario_id` | → | `usuarios.id` | | `jwt_token_history.token_id` | → | `jwt_tokens.id` | | `logs_actividad_clientes.cliente_id` | → | `clientes.id` | | `movimientos_balance.empresa_id` | → | `empresas.id` | | `movimientos_balance.usuario_id` | → | `usuarios.id` | | `movimientos_balance.autorizado_por` | → | `usuarios.id` | | `paquetes.servicio_id` | → | `servicios.id` | | `servicios.categoria_id` | → | `categorias.id` | | `sesiones.usuario_id` | → | `usuarios.id` | | `sesiones_clientes.cliente_id` | → | `clientes.id` | | `sesiones_master.usuario_id` | → | `usuarios_master.id` | --- ## INVENTARIO COMPLETO DE TABLAS | Tabla | Filas (aprox.) | Columnas | |---|---|---| | `alertas_sistema` | 5 | 13 | | `api_audit_log` | 0 | 15 | | `api_credentials` | 0 | 11 | | `api_endpoints` | 0 | 10 | | `api_idempotency_keys` | 0 | 13 | | `api_logs` | 45 | 10 | | `api_permisos` | 0 | 7 | | `api_rate_counters` | 0 | 5 | | `api_request_logs` | 0 | 16 | | `api_tokens` | 360 | 12 | | `api_token_ips` | 0 | 5 | | `api_token_logs` | 4 | 10 | | `api_token_permissions` | 4 | 5 | | `api_token_stats` | 0 | 9 | | `audit_logs` | 4 | 13 | | `auth_logs` | 207 | 9 | | `bancos` | 1 | 26 | | `categorias` | 9 | 8 | | `clientes` | 265 | 22 | | `codigos_verificacion` | 338 | 9 | | `comisiones_calculadas` | 0 | 15 | | `comprobantes_pago` | 9 | 12 | | `configuracion` | 20 | 6 | | `dini_clientes` | 6 | 9 | | `dini_historial_precios` | 14 | 7 | | `dini_ordenes` | 7 | 11 | | `dini_orden_items` | 14 | 11 | | `dini_productos` | 72 | 8 | | `empresas` | 368 | 39 | | `empresa_balances` | 195 | 12 | | `empresa_comision` | 0 | 16 | | `empresa_comisiones` | 2,759 | 14 | | `empresa_cuentas_bancarias` | 0 | 9 | | `empresa_liquidacion` | 26 | 11 | | `empresa_plantilla` | 0 | 6 | | `empresa_producto_comision` | 2,174 | 7 | | `empresa_usuarios` | 0 | 12 | | `esquemas_comision` | 3 | 11 | | `historial_comisiones` | 0 | 7 | | `jwt_blacklist` | 0 | 6 | | `jwt_rate_limits` | 0 | 8 | | `jwt_sessions` | 0 | 13 | | `jwt_tokens` | 2,548 | 22 | | `jwt_token_history` | 0 | 10 | | `login_attempts` | 2 | 6 | | `logs_actividad_clientes` | 1,935 | 7 | | `movimientos_balance` | 932 | 24 | | `oauth_states` | 55,386 | 3 | | `pagos_comisiones` | 126 | 15 | | `paquetes` | 27 | 15 | | `plantillas_comisiones` | 0 | 10 | | `productos` | 37 | 18 | | `proyectos` | 4 | 16 | | `proyecto_auditoria` | 24 | 10 | | `proyecto_configuraciones` | 2 | 9 | | `proyecto_webhook_logs` | 38,424 | 11 | | `refresh_tokens` | 0 | 12 | | `security_blacklist` | 0 | 6 | | `security_logs` | 445 | 6 | | `seo_landings` | 32 | 11 | | `servicios` | 49 | 14 | | `sesiones` | 0 | 7 | | `sesiones_clientes` | 254 | 7 | | `sesiones_master` | 143 | 8 | | `transacciones` | 48,162 | 28 | | `usuarios` | 5 | 11 | | `usuarios_master` | 12 | 12 | | `wa_auditoria` | 3,010 | 10 | | `wa_catalogo` | 1 | 8 | | `wa_config` | 20 | 5 | | `wa_cuentas` | 1 | 18 | | `wa_empresas_habilitadas` | 1 | 7 | | `wa_mensajes` | 372 | 13 | | `wa_operaciones` | 9 | 26 | | `wa_panel_lectura` | 2 | 4 | | `wa_rate_limit` | 0 | 3 | | `wa_sesiones` | 5 | 13 | | `wa_tokens` | 4 | 7 | | `wa_verificaciones` | 0 | 9 | > El conteo de filas proviene de `information_schema.table_rows`, que en InnoDB es una > estimación. Las cifras citadas en la auditoría (transacciones, divergencias de saldo, > formatos de secreto) se obtuvieron con `COUNT(*)` exacto.