# 🗄️ Base de Datos

## Información general

- **Nombre:** `db_vinosylicores`
- **Motor:** MySQL 8.0+ / MariaDB 10.3+
- **Charset:** `utf8mb4`
- **Collation:** `utf8mb4_unicode_ci`
- **Migraciones:** Versionadas con Laravel Migrations

## Estructura de módulos

La base de datos está organizada por módulos funcionales con prefijos de tabla:

### Prefijos de tablas por módulo

| Prefijo | Módulo | Descripción |
|---------|--------|-------------|
| `base_` | Base/Fundacional | Usuarios, perfiles, permisos, empresas, sucursales |
| `ptv_` | Punto de Venta | Clientes, listas de precios, cotizaciones, operaciones |
| `com_` | Compras | Proveedores, requisiciones, cotizaciones de compra |
| `inv_` | Inventario | Productos, categorías, movimientos, almacenes |
| `promo_` | Promociones | Combos, promociones, detalles |

## Tablas principales por módulo

### Módulo Base (base_*)

#### Autenticación y Usuarios
- **base_usuario**: Usuarios del sistema
  - PK: `idUsuario`
  - Campos: nombre, email, password, token 2FA, estado
  - Relaciones: belongsTo Perfil, belongsTo Sucursal

- **base_perfil**: Roles/Perfiles de usuario
  - PK: `idPerfil`
  - Campos: alias, descripción, estado

- **base_ruta**: Rutas/Permisos del sistema
  - PK: `idRuta`
  - Campos: nombre, permiso, descripción, estado

- **base_perfilruta**: Tabla pivote Perfil-Ruta
  - PKs: `idPerfil`, `idRuta`
  - Implementa sistema de permisos

- **base_menu**: Menús del sistema
  - PK: `idMenu`
  - Campos: nombre, icono, orden, menú padre (jerarquía)

- **base_perfilmenu**: Tabla pivote Perfil-Menú
  - PKs: `idPerfil`, `idMenu`

#### Estructura organizacional
- **base_empresa**: Empresas/Organizaciones
  - PK: `idEmpresa`
  - Campos: nombre, RFC, dirección, logo

- **base_sucursal**: Sucursales de la empresa
  - PK: `idSucursal`
  - FK: `idEmpresa`
  - Campos: nombre, dirección, teléfono

#### Datos geográficos
- **base_pais**: Catálogo de países
  - PK: `idPais`

- **base_estado**: Estados/Provincias
  - PK: `idEstado`
  - FK: `idPais`

- **base_delegacion**: Municipios/Delegaciones
  - PK: `idDelegacion`
  - FK: `idEstado`

- **base_colonia**: Colonias/Barrios
  - PK: `idColonia`
  - FK: `idDelegacion`
  - Campo: código postal

#### Otros catálogos
- **base_banco**: Catálogo de bancos
  - PK: `idBanco`
  - Campos: nombre, clave, estado

- **base_bitacora**: Registro de auditoría
  - PK: `idBitacora`
  - Campos: idAccion, idRegistro, detalle, fecha, idUsuario

- **base_notificacion**: Notificaciones del sistema
  - PK: `idNotificacion`
  - Campos: título, mensaje, tipo, leída, fecha

### Módulo Punto de Venta (ptv_*)

#### Clientes
- **ptv_cliente**: Clientes del sistema
  - PK: `idCliente`
  - FK: `idCategoriaCliente`, `idListaPrecio`
  - Campos especiales:
    - `clienteFolio`: Auto-generado (formato: PPYYYYNNNN)
    - `clienteNombre`, `clienteEmail`, `clienteTelefono`
    - `clienteEstado`: Activo/Inactivo

- **ptv_categoriacliente**: Categorías de clientes
  - PK: `idCategoriaCliente`
  - Campos:
    - `categoriaClienteAlias`: Usado para prefijo de folios
    - `categoriaClienteObservaciones`
    - `categoriaClienteEstado`

#### Listas de precios
- **ptv_listaprecio**: Listas de precios
  - PK: `idListaPrecio`
  - Campos: alias, descripción, estado

- **ptv_listapreciodetalle**: Detalles de lista de precios
  - PK: `idListaPrecioDetalle`
  - FK: `idListaPrecio`, `idProducto`
  - Campos: precio, descuento

#### Operaciones de venta
- **ptv_operacion**: Operaciones/Ventas
  - PK: `idOperacion`
  - FK: `idCliente`, `idSucursal`, `idCaja`
  - Campos: folio, fecha, total, estado

- **ptv_operacionproducto**: Detalle de operación
  - PK: `idOperacionProducto`
  - FK: `idOperacion`, `idProducto`
  - Campos: cantidad, precio, subtotal

- **ptv_operacionabono**: Abonos a operaciones
  - PK: `idOperacionAbono`
  - FK: `idOperacion`
  - Campos: monto, fecha, referencia

#### Cotizaciones
- **ptv_cotizacion**: Cotizaciones a clientes
  - PK: `idCotizacion`
  - FK: `idCliente`
  - Campos: folio, fecha, total, estado

- **ptv_cotizacionproducto**: Detalle de cotización
  - PK: `idCotizacionProducto`
  - FK: `idCotizacion`, `idProducto`

#### Caja
- **ptv_caja**: Cajas de punto de venta
  - PK: `idCaja`
  - FK: `idSucursal`
  - Campos: nombre, estado

- **ptv_cajahistorial**: Historial de operaciones de caja
  - PK: `idCajaHistorial`
  - FK: `idCaja`, `idUsuario`
  - Campos: apertura, cierre, montoInicial, montoFinal

### Módulo Compras (com_*)

#### Proveedores
- **com_proveedor**: Proveedores
  - PK: `idProveedor`
  - FK: `idBanco`
  - Campos:
    - `proveedorNombre`: Único
    - `proveedorRazonSocial`
    - `proveedorRFC`
    - `proveedorEmail`, `proveedorTelefono`
    - `proveedorDireccion`, `proveedorCuenta`
    - `proveedorContacto`
    - `proveedorEstado`

- **com_categoriaproveedor**: Categorías de proveedores
  - PK: `idCategoriaProveedor`
  - FK: `idCategoriaProveedorSuperior` (auto-relación para jerarquía)
  - Campos:
    - `categoriaProveedorAlias`: Único
    - `categoriaProveedorEstado`

- **com_proveedorcategoria**: Relación Proveedor-Categoría
  - PK: `idProveedorCategoria`
  - FK: `idProveedor`, `idCategoriaProveedor`
  - **Nota:** Relación 1:1 (un proveedor una categoría)

#### Requisiciones y Pedidos
- **com_requisicion**: Requisiciones de compra
  - PK: `idRequisicion`
  - Campos: folio, fecha, observaciones, estado

- **com_requisicionproducto**: Productos de requisición
  - PK: `idRequisicionProducto`
  - FK: `idRequisicion`, `idProducto`
  - Campos: cantidad, precioEstimado

- **com_pedido**: Pedidos a proveedores
  - PK: `idPedido`
  - FK: `idProveedor`

- **com_pedidoproducto**: Productos de pedido
  - PK: `idPedidoProducto`
  - FK: `idPedido`, `idProducto`

#### Cotizaciones de compra
- **com_cotizacion**: Cotizaciones de proveedores
  - PK: `idCotizacion`
  - FK: `idProveedor`
  - Campos: folio, fecha, total, estado

- **com_cotizacionproducto**: Productos de cotización
  - PK: `idCotizacionProducto`
  - FK: `idCotizacion`, `idProducto`

### Módulo Inventario (inv_*)

#### Productos
- **inv_producto**: Catálogo de productos
  - PK: `idProducto`
  - FK: `idCategoriaProducto`, `idUnidad`
  - Campos:
    - `productoNombre`, `productoDescripcion`
    - `productoCodigo`, `productoCodigoBarras`
    - `productoPrecioCompra`, `productoPrecioVenta`
    - `productoStock`, `productoStockMinimo`
    - `productoImagen`
    - `productoEstado`

- **inv_categoriaproducto**: Categorías de productos
  - PK: `idCategoriaProducto`
  - Campos: alias, descripción, estado

- **inv_unidad**: Unidades de medida
  - PK: `idUnidad`
  - Campos: nombre, abreviatura, estado

#### Relación Proveedor-Producto
- **inv_proveedorproducto**: Productos por proveedor
  - PK: `idProveedorProducto`
  - FK: `idProveedor`, `idProducto`
  - Campos: precio, tiempoEntrega

#### Movimientos de inventario
- **inv_inventario**: Inventario por almacén
  - PK: `idInventario`
  - FK: `idProducto`, `idAlmacen`
  - Campos: cantidad, ubicación

- **inv_movimiento**: Movimientos de inventario
  - PK: `idMovimiento`
  - FK: `idProducto`, `idOperacion`, `idUsuario`
  - Campos: tipo, cantidad, fecha, referencia

- **inv_operacion**: Operaciones de inventario
  - PK: `idOperacion`
  - Campos: tipo, folio, fecha, observaciones

- **inv_loteproducto**: Lotes de productos
  - PK: `idLoteProducto`
  - FK: `idProducto`
  - Campos: lote, fechaCaducidad, cantidad

#### Almacenes
- **inv_almacen**: Almacenes
  - PK: `idAlmacen`
  - FK: `idSucursal`
  - Campos: nombre, ubicación, estado

### Módulo Promociones (promo_*)

#### Combos
- **promo_combo**: Combos de productos
  - PK: `idCombo`
  - Campos:
    - `comboNombre`, `comboDescripcion`
    - `comboPrecio`, `comboDescuento`
    - `comboFechaInicio`, `comboFechaFin`
    - `comboEstado`

- **promo_comboproducto**: Productos del combo
  - PK: `idComboProducto`
  - FK: `idCombo`, `idProducto`
  - Campos: cantidad

#### Promociones
- **promo_promocion**: Promociones
  - PK: `idPromocion`
  - Campos:
    - `promocionNombre`, `promocionDescripcion`
    - `promocionTipo`: Descuento, 2x1, 3x2, etc.
    - `promocionValor`
    - `promocionFechaInicio`, `promocionFechaFin`
    - `promocionEstado`

- **promo_promocionproducto**: Productos en promoción
  - PK: `idPromocionProducto`
  - FK: `idPromocion`, `idProducto`

- **promo_detallepromocion**: Detalles de aplicación
  - PK: `idDetallePromocion`
  - FK: `idPromocion`
  - Campos: condiciones, restricciones

### Tablas del sistema Laravel

- **personal_access_tokens**: Tokens de Sanctum
  - Usado para autenticación API

- **cache**: Caché en base de datos
- **cache_locks**: Locks de caché
- **sessions**: Sesiones de usuario
- **jobs**: Cola de trabajos
- **job_batches**: Lotes de trabajos
- **failed_jobs**: Trabajos fallidos

## Relaciones importantes

### Diagrama conceptual de relaciones

```
Usuario (base_usuario)
├── belongsTo: Perfil (base_perfil)
├── belongsTo: Sucursal (base_sucursal)
└── hasMany: Operaciones

Perfil (base_perfil)
├── belongsToMany: Rutas (base_ruta) via base_perfilruta
└── belongsToMany: Menus (base_menu) via base_perfilmenu

Cliente (ptv_cliente)
├── belongsTo: CategoriaCliente (ptv_categoriacliente)
├── belongsTo: ListaPrecio (ptv_listaprecio)
└── hasMany: Operaciones

Proveedor (com_proveedor)
├── belongsTo: Banco (base_banco)
├── hasOne: ProveedorCategoria → CategoriaProveedor
└── belongsToMany: Productos via inv_proveedorproducto

Producto (inv_producto)
├── belongsTo: CategoriaProducto (inv_categoriaproducto)
├── belongsTo: Unidad (inv_unidad)
├── belongsToMany: Proveedores via inv_proveedorproducto
├── belongsToMany: ListasPrecio via ptv_listapreciodetalle
└── hasMany: Movimientos

Operacion (ptv_operacion)
├── belongsTo: Cliente (ptv_cliente)
├── belongsTo: Sucursal (base_sucursal)
└── hasMany: OperacionProducto
```

## Índices y optimizaciones

### Índices recomendados

```sql
-- Búsquedas frecuentes en clientes
CREATE INDEX idx_cliente_nombre ON ptv_cliente(clienteNombre);
CREATE INDEX idx_cliente_folio ON ptv_cliente(clienteFolio);
CREATE INDEX idx_cliente_email ON ptv_cliente(clienteEmail);
CREATE INDEX idx_cliente_estado ON ptv_cliente(clienteEstado);

-- Búsquedas frecuentes en proveedores
CREATE INDEX idx_proveedor_nombre ON com_proveedor(proveedorNombre);
CREATE INDEX idx_proveedor_rfc ON com_proveedor(proveedorRFC);
CREATE INDEX idx_proveedor_estado ON com_proveedor(proveedorEstado);

-- Búsquedas frecuentes en productos
CREATE INDEX idx_producto_nombre ON inv_producto(productoNombre);
CREATE INDEX idx_producto_codigo ON inv_producto(productoCodigo);
CREATE INDEX idx_producto_codigobarras ON inv_producto(productoCodigoBarras);
CREATE INDEX idx_producto_estado ON inv_producto(productoEstado);

-- Optimización de operaciones
CREATE INDEX idx_operacion_fecha ON ptv_operacion(operacionFecha);
CREATE INDEX idx_operacion_cliente ON ptv_operacion(idCliente, operacionEstado);

-- Optimización de movimientos
CREATE INDEX idx_movimiento_producto_fecha ON inv_movimiento(idProducto, movimientoFecha);
```

### Índices compuestos

```sql
-- Cliente por categoría y estado
CREATE INDEX idx_cliente_cat_estado ON ptv_cliente(idCategoriaCliente, clienteEstado);

-- Producto por categoría y estado
CREATE INDEX idx_producto_cat_estado ON inv_producto(idCategoriaProducto, productoEstado);

-- Operaciones por sucursal y fecha
CREATE INDEX idx_operacion_suc_fecha ON ptv_operacion(idSucursal, operacionFecha);
```

## Convenciones y estándares

### Nomenclatura

1. **Nombres de tablas:**
   - Formato: `{prefijo}_{entidad}` en singular
   - Ejemplo: `com_proveedor`, `ptv_cliente`

2. **Nombres de campos:**
   - Formato: `{entidad}{Campo}` en camelCase sin espacios
   - Ejemplo: `proveedorNombre`, `clienteEmail`

3. **Primary Keys:**
   - Formato: `id{Entidad}`
   - Ejemplo: `idProveedor`, `idCliente`

4. **Foreign Keys:**
   - Mismo formato que la PK referenciada
   - Ejemplo: `idProveedor` en `com_proveedorcategoria`

5. **Campos de estado:**
   - Formato: `{entidad}Estado`
   - Valores comunes: 'Activo', 'Inactivo'

6. **Timestamps:**
   - No se usan timestamps automáticos de Laravel
   - Campos de fecha nombrados explícitamente
   - Ejemplo: `operacionFecha`, `movimientoFecha`

### Tipos de datos comunes

- **IDs:** `INT UNSIGNED AUTO_INCREMENT`
- **Nombres/Textos cortos:** `VARCHAR(50-255)`
- **Descripciones:** `TEXT`
- **Emails:** `VARCHAR(100)`
- **Teléfonos:** `VARCHAR(15)`
- **Precios/Montos:** `DECIMAL(10,2)`
- **Estados:** `VARCHAR(20)` o `ENUM`
- **Fechas:** `DATETIME` o `TIMESTAMP`

## Backup y mantenimiento

### Backup manual

```bash
# Backup completo
mysqldump -u root -p db_vinosylicores > backup_$(date +%Y%m%d).sql

# Backup de estructura solamente
mysqldump -u root -p --no-data db_vinosylicores > estructura_$(date +%Y%m%d).sql

# Backup de datos solamente
mysqldump -u root -p --no-create-info db_vinosylicores > datos_$(date +%Y%m%d).sql
```

### Restaurar backup

```bash
mysql -u root -p db_vinosylicores < backup_20250114.sql
```

### Mantenimiento de tablas

```sql
-- Optimizar tablas
OPTIMIZE TABLE ptv_cliente, com_proveedor, inv_producto;

-- Analizar tablas
ANALYZE TABLE ptv_operacion, inv_movimiento;

-- Reparar tabla (si es necesario)
REPAIR TABLE nombre_tabla;
```

## Migraciones

### Comandos útiles

```bash
# Ver estado de migraciones
php artisan migrate:status

# Ejecutar migraciones pendientes
php artisan migrate

# Revertir última migración
php artisan migrate:rollback

# Revertir todas las migraciones
php artisan migrate:reset

# Rehacer migraciones (rollback + migrate)
php artisan migrate:refresh

# Migración fresca con seeds
php artisan migrate:fresh --seed

# Crear nueva migración
php artisan make:migration create_nombre_tabla --create=nombre_tabla
php artisan make:migration add_campo_to_tabla --table=nombre_tabla
```

## Consideraciones de rendimiento

1. **Paginación:** Siempre usar paginación en listados grandes
2. **Eager Loading:** Usar `with()` para cargar relaciones
3. **Select específico:** Evitar `SELECT *` cuando solo se necesitan algunos campos
4. **Índices:** Agregar índices en campos de búsqueda frecuente
5. **Caché:** Cachear consultas frecuentes que no cambian mucho
6. **Particionamiento:** Considerar para tablas muy grandes (operaciones, movimientos)

## Notas adicionales

- La base de datos NO usa soft deletes de Laravel
- Se usa campo `{entidad}Estado` con valores 'Activo'/'Inactivo'
- Los timestamps NO están habilitados en modelos (`public $timestamps = false`)
- Todas las fechas se manejan manualmente
- La bitácora registra acciones con código de acción numérico
