Esquema de Base de Datos
Visión General
Base de datos MySQL 8 con 24 tablas. El esquema se inicializa mediante db/init.sql en el arranque del contenedor MySQL. Hibernate opera en modo validate para verificar que el mapeo JPA coincida con el esquema.
Diagrama de Tablas
Tablas Detalladas
1. roles
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
Nombre del rol |
| description |
VARCHAR(255) |
Descripción |
Datos semilla: ADMIN, GERENTE, CONTABLE, VISUALIZADOR
2. users
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| username |
VARCHAR(50) UNIQUE |
Nombre de usuario |
| email |
VARCHAR(100) UNIQUE |
Correo electrónico |
| password_hash |
VARCHAR(255) |
Hash BCrypt |
| full_name |
VARCHAR(150) |
Nombre completo |
| phone |
VARCHAR(20) |
Teléfono |
| role_id |
INT FK → roles(id) |
Rol del usuario |
| active |
BOOLEAN |
Usuario activo (soporta soft-delete) |
| created_at |
DATETIME |
Fecha de creación |
| updated_at |
DATETIME |
Fecha de modificación |
| last_login |
DATETIME |
Último inicio de sesión |
3. user_permissions
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| user_id |
BIGINT FK → users(id) CASCADE |
Usuario |
| permission |
VARCHAR(50) |
Permiso específico |
| granted |
BOOLEAN |
Concedido/denegado |
Unique: (user_id, permission)
4. property_types
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(50) UNIQUE |
Tipo (EDIFICIO, PISO, etc.) |
| description |
VARCHAR(255) |
Descripción |
5. property_statuses
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(50) UNIQUE |
Estado (DISPONIBLE, ALQUILADO, etc.) |
| description |
VARCHAR(255) |
Descripción |
6. properties
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| parent_id |
BIGINT FK → properties(id) SET NULL |
Propiedad padre (jerarquía) |
| group_id |
BIGINT FK → property_groups(id) SET NULL |
Conjunto al que pertenece |
| type_id |
INT FK → property_types(id) |
Tipo de propiedad |
| status_id |
INT FK → property_statuses(id) |
Estado actual |
| reference |
VARCHAR(50) UNIQUE |
Referencia interna |
| name |
VARCHAR(200) |
Nombre identificativo |
| description |
TEXT |
Descripción |
| address_street |
VARCHAR(200) |
Calle |
| address_number |
VARCHAR(20) |
Número |
| address_city |
VARCHAR(100) |
Ciudad |
| address_postal_code |
VARCHAR(10) |
Código postal |
| address_province |
VARCHAR(100) |
Provincia |
| cadastral_ref |
VARCHAR(30) |
Referencia catastral |
| surface_m2 |
DECIMAL(10,2) |
Superficie en m² |
| floor |
VARCHAR(50) |
Planta / Piso |
| door |
VARCHAR(50) |
Puerta |
| rental_amount |
DECIMAL(12,2) |
Importe de alquiler |
| rented_since |
DATE |
Alquilado desde |
| vacant_since |
DATE |
Vacío desde |
| occupied_since |
DATE |
Ocupado desde |
| notes |
TEXT |
Notas |
| active |
BOOLEAN |
Activo (soft-delete) |
| created_by |
BIGINT FK → users(id) SET NULL |
Creado por |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
Índices: parent, type, status, active
7. property_status_history
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| property_id |
BIGINT FK → properties(id) CASCADE |
Propiedad |
| status_id |
INT FK → property_statuses(id) |
Nuevo estado |
| changed_by |
BIGINT FK → users(id) SET NULL |
Quién cambió |
| changed_at |
DATETIME |
Cuándo |
| notes |
VARCHAR(500) |
Motivo del cambio |
8. property_groups
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| name |
VARCHAR(200) |
Nombre del conjunto |
| address_street |
VARCHAR(200) |
Calle |
| address_number |
VARCHAR(20) |
Número |
| address_city |
VARCHAR(100) |
Ciudad |
| address_postal_code |
VARCHAR(10) |
Código postal |
| is_active |
BOOLEAN |
Activo |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
Relaciones: Una propiedad puede pertenecer opcionalmente a un conjunto. Al eliminar un conjunto, las propiedades asociadas quedan con group_id = NULL (ON DELETE SET NULL).
9. tenant_types
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
PERSONA_FISICA / PERSONA_JURIDICA |
10. tenants
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| tenant_type_id |
INT FK → tenant_types(id) |
Tipo de inquilino |
| fiscal_id |
VARCHAR(20) UNIQUE |
DNI/NIF/CIF |
| full_name |
VARCHAR(200) |
Nombre o razón social |
| business_name |
VARCHAR(200) |
Solo personas jurídicas |
| email |
VARCHAR(100) |
Correo electrónico |
| phone |
VARCHAR(20) |
Teléfono |
| address |
VARCHAR(300) |
Dirección |
| iban |
VARCHAR(34) |
IBAN para domiciliación |
| notes |
TEXT |
Notas |
| active |
BOOLEAN |
Activo (soft-delete) |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
11. contract_statuses
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
ACTIVO, VENCIDO, RENOVADO, RESCINDIDO, ANULADO |
12. payment_periods
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
MENSUAL, TRIMESTRAL, SEMESTRAL, ANUAL |
13. contracts
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| property_id |
BIGINT FK → properties(id) |
Propiedad |
| tenant_id |
BIGINT FK → tenants(id) |
Inquilino |
| status_id |
INT FK → contract_statuses(id) |
Estado |
| period_id |
INT FK → payment_periods(id) DEFAULT 1 |
Período de pago |
| contract_number |
VARCHAR(50) UNIQUE |
Número de contrato |
| start_date |
DATE |
Fecha de inicio |
| end_date |
DATE |
Fecha de fin |
| renewal_date |
DATE |
Fecha de renovación |
| rental_amount |
DECIMAL(12,2) |
Renta mensual |
| deposit_amount |
DECIMAL(12,2) |
Fianza |
| payment_day |
INT DEFAULT 1 |
Día de pago |
| payment_day_end |
INT DEFAULT NULL |
Día final del rango de pago (NULL = día único) |
| iban_charge |
VARCHAR(34) |
IBAN domiciliación |
| notes |
TEXT |
Notas |
| signed_at |
DATE |
Fecha de firma |
| terminated_at |
DATE |
Fecha de terminación |
| termination_cause |
VARCHAR(500) |
Causa de terminación |
| created_by |
BIGINT FK → users(id) SET NULL |
Creado por |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
14. document_types
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(50) UNIQUE |
Tipo de documento |
Tipos: CONTRATO, ANEXO_CONTRATO, DNI_ARREENDATARIO, CIF_EMPRESA, FOTO_PROPIEDAD, FOTO_INCIDENCIA, FACTURA, JUSTIFICANTE_PAGO, CERTIFICADO, OTRO
16. documents
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| document_type_id |
INT FK → document_types(id) |
Tipo |
| original_name |
VARCHAR(255) |
Nombre original del archivo |
| stored_name |
VARCHAR(255) |
Nombre almacenado en disco (UUID + extensión) |
| mime_type |
VARCHAR(100) |
Tipo MIME |
| file_size |
BIGINT |
Tamaño en bytes |
| description |
VARCHAR(500) |
Descripción |
| uploaded_by |
BIGINT FK → users(id) SET NULL |
Subido por |
| uploaded_at |
DATETIME |
Fecha de subida |
Relaciones: Relación One-to-Many con document_entities.
17. document_entities (tabla pivote)
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| document_id |
BIGINT FK → documents(id) CASCADE |
Documento |
| entity_type |
VARCHAR(30) |
Tipo de entidad asociada |
| entity_id |
BIGINT |
ID de la entidad |
| created_at |
DATETIME |
Fecha de creación |
Entidades soportadas: PROPERTY, TENANT, CONTRACT, INCOME, EXPENSE, INCIDENT, MAINTENANCE
Caso de uso: Permite asociar un mismo documento a múltiples entidades. Por ejemplo, una fianza puede estar asociada tanto a un INCOME (cuando se recibe) como a un EXPENSE (cuando se devuelve).
Índices: UNIQUE(document_id, entity_type, entity_id), INDEX(entity_type, entity_id)
17. document_type_entity_allowed (tabla pivote)
Define qué tipos de documento pueden asociarse a qué tipos de entidades del sistema.
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| document_type_id |
INT FK → document_types(id) |
Tipo de documento |
| entity_type |
VARCHAR(30) |
Tipo de entidad (PROPERTY, TENANT, CONTRACT, INCOME, EXPENSE, INCIDENT, MAINTENANCE) |
| can_upload |
BOOLEAN |
Si el usuario puede subir este tipo en esta entidad |
| must_have |
BOOLEAN |
Si es obligatorio al crear/editar la entidad |
| description |
VARCHAR(255) |
Descripción del uso del documento |
| created_at |
DATETIME |
Fecha de creación |
Relaciones permitidas:
| Tipo Documento |
Entidad |
Obligatorio |
Descripción |
| CONTRATO |
CONTRACT |
Sí |
Documento principal del contrato |
| CONTRATO |
TENANT |
No |
Copia firmada por inquilino |
| CONTRATO |
PROPERTY |
No |
Contrato asociado al inmueble |
| ANEXO_CONTRATO |
CONTRACT |
No |
Anexos y modificaciones |
| DNI_ARRENDATARIO |
TENANT |
Sí |
DNI del inquilino |
| CIF_EMPRESA |
TENANT |
No |
Para personas jurídicas |
| FOTO_PROPIEDAD |
PROPERTY |
Sí |
Fotos del inmueble |
| FOTO_INCIDENCIA |
INCIDENT |
No |
Fotos de la incidencia |
| FACTURA |
EXPENSE |
Sí |
Factura o justificante del gasto |
| JUSTIFICANTE_PAGO |
INCOME |
Sí |
Justificante de pago |
| CERTIFICADO |
TENANT |
No |
Certificados varios |
| CERTIFICADO |
CONTRACT |
No |
Certificados asociados |
| OTRO |
Todas |
No |
Otros documentos |
Índices: UNIQUE(document_type_id, entity_type), INDEX(entity_type)
18. income_categories
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| name |
VARCHAR(100) |
Nombre |
| description |
VARCHAR(255) |
Descripción |
| active |
BOOLEAN |
Activo |
Categorías: ALQUILER, FIANZA, GASTOS_COMUNIDAD, INTERESES_DEMORA, INDEMNIZACION, OTROS_INGRESOS
17. income_statuses
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
PENDIENTE, PAGADO, VENCIDO, PARCIAL, ANULADO |
18. income_receipts
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| contract_id |
BIGINT FK → contracts(id) SET NULL |
Contrato asociado |
| property_id |
BIGINT FK → properties(id) |
Propiedad (NOT NULL) |
| tenant_id |
BIGINT FK → tenants(id) SET NULL |
Inquilino |
| bank_account_id |
BIGINT FK → bank_accounts(id) SET NULL |
Cuenta bancaria |
| is_domiciled |
BOOLEAN DEFAULT FALSE |
Domiciliado |
| category_id |
BIGINT FK → income_categories(id) SET NULL |
Categoría |
| status_id |
INT FK → income_statuses(id) |
Estado |
| period_label |
VARCHAR(20) |
Etiqueta de período (ej: "2026-07") |
| amount |
DECIMAL(12,2) |
Importe bruto |
| tax_withheld |
DECIMAL(12,2) DEFAULT 0 |
Retención IRPF |
| net_amount |
DECIMAL(12,2) |
Importe neto |
| issue_date |
DATE |
Fecha de emisión |
| due_date |
DATE |
Fecha de vencimiento |
| payment_date |
DATE |
Fecha de pago |
| payment_method |
VARCHAR(30) |
TRANSFERENCIA / EFECTIVO / BIZUM / RECIBO / TARJETA |
| description |
VARCHAR(500) |
Descripción |
| receipt_number |
VARCHAR(50) |
Número de recibo |
| notes |
TEXT |
Notas |
| created_by |
BIGINT FK → users(id) SET NULL |
Creado por |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
19. expense_categories
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| name |
VARCHAR(100) |
Nombre |
| description |
VARCHAR(255) |
Descripción |
| active |
BOOLEAN |
Activo |
20. expense_statuses
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
PENDIENTE, PAGADO, VENCIDO, ANULADO |
21. expense_templates
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| property_id |
BIGINT FK → properties(id) NULL |
Propiedad asociada |
| property_group_id |
BIGINT FK → property_groups(id) NULL |
Conjunto asociado |
| bank_account_id |
BIGINT FK → bank_accounts(id) NULL |
Cuenta bancaria |
| is_domiciled |
BOOLEAN DEFAULT FALSE |
Domiciliado |
| category_id |
BIGINT FK → expense_categories(id) SET NULL |
Categoría |
| period_id |
INT FK → payment_periods(id) |
Periodicidad |
| payment_day |
INT DEFAULT 1 |
Día de pago |
| supplier_name |
VARCHAR(200) |
Proveedor |
| supplier_fiscal_id |
VARCHAR(20) |
NIF/CIF |
| amount |
DECIMAL(12,2) NULL |
Importe fijo (NULL = variable) |
| tax_amount |
DECIMAL(12,2) |
Importe impuestos |
| description |
VARCHAR(500) |
Concepto |
| notes |
TEXT |
Notas |
| is_variable |
BOOLEAN DEFAULT FALSE |
Importe variable (usuario rellena cada mes) |
| active |
BOOLEAN DEFAULT TRUE |
Template activo/inactivo |
| created_by |
BIGINT FK → users(id) SET NULL |
Creador |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
22. expense_receipts
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| template_id |
BIGINT FK → expense_templates(id) SET NULL |
Template origen (NULL = gasto manual) |
| property_id |
BIGINT FK → properties(id) NULL |
Propiedad asociada |
| property_group_id |
BIGINT FK → property_groups(id) NULL |
Conjunto asociado |
| bank_account_id |
BIGINT FK → bank_accounts(id) NULL |
Cuenta bancaria |
| is_domiciled |
BOOLEAN DEFAULT FALSE |
Domiciliado |
| category_id |
BIGINT FK → expense_categories(id) SET NULL |
Categoría |
| status_id |
INT FK → expense_statuses(id) |
Estado |
| supplier_name |
VARCHAR(200) |
Proveedor |
| supplier_fiscal_id |
VARCHAR(20) |
NIF/CIF |
| invoice_number |
VARCHAR(50) |
Número de factura |
| amount |
DECIMAL(12,2) DEFAULT 0 |
Base imponible |
| tax_amount |
DECIMAL(12,2) DEFAULT 0 |
Importe impuestos |
| total_amount |
DECIMAL(12,2) |
Total con impuestos |
| is_variable |
BOOLEAN DEFAULT FALSE |
Es gasto variable |
| previous_amount |
DECIMAL(12,2) NULL |
Importe del periodo anterior (para variables) |
| issue_date |
DATE |
Fecha de emisión |
| due_date |
DATE |
Fecha de vencimiento |
| payment_date |
DATE |
Fecha de pago |
| payment_method |
VARCHAR(30) |
Método de pago |
| description |
VARCHAR(500) |
Concepto |
| notes |
TEXT |
Notas |
| created_by |
BIGINT FK → users(id) SET NULL |
Creador |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
Índices: template, property, property_group, category, status, issue_date
23. incident_statuses
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(50) UNIQUE |
SIN_REVISAR, TECNICO_AVISADO, REPARACION_PREVISTA, REPARADO, IGNORADO, ANULADO |
24. incident_priorities
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(20) UNIQUE |
BAJA, MEDIA, ALTA, URGENTE |
25. incidents
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| property_id |
BIGINT FK → properties(id) |
Propiedad |
| status_id |
INT FK → incident_statuses(id) |
Estado |
| priority_id |
INT FK → incident_priorities(id) |
Prioridad |
| title |
VARCHAR(200) |
Título |
| description |
TEXT |
Descripción |
| reported_by |
BIGINT FK → users(id) SET NULL |
Reportado por |
| assigned_to |
BIGINT FK → users(id) SET NULL |
Asignado a |
| reported_at |
DATETIME |
Fecha de reporte |
| scheduled_date |
DATE |
Fecha prevista reparación |
| resolved_at |
DATETIME |
Fecha de resolución |
| resolution_notes |
TEXT |
Notas de resolución |
| cost_estimate |
DECIMAL(12,2) |
Coste estimado |
| final_cost |
DECIMAL(12,2) |
Coste final |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
26. maintenance_periods
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(30) UNIQUE |
UNICA_VEZ, MENSUAL, TRIMESTRAL, etc. |
27. scheduled_maintenance
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| property_id |
BIGINT FK → properties(id) |
Propiedad |
| period_id |
INT FK → maintenance_periods(id) |
Periodicidad |
| title |
VARCHAR(200) |
Título |
| description |
TEXT |
Descripción |
| estimated_cost |
DECIMAL(12,2) |
Coste estimado |
| last_execution |
DATE |
Última ejecución |
| next_execution |
DATE |
Próxima ejecución |
| reminder_days_before |
INT DEFAULT 30 |
Días antes para recordatorio |
| responsible |
VARCHAR(200) |
Responsable |
| notes |
TEXT |
Notas |
| completed |
BOOLEAN |
Completado |
| completed_at |
DATE |
Fecha de finalización |
| completed_by |
BIGINT FK → users(id) SET NULL |
Completado por |
| created_by |
BIGINT FK → users(id) SET NULL |
Creado por |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
28. notification_types
| Columna |
Tipo |
Descripción |
| id |
INT PK |
Auto-increment |
| name |
VARCHAR(50) UNIQUE |
INCIDENCIA_ABIERTA, MANTENIMIENTO_PROXIMO, RECIBO_VENCIDO, CONTRATO_PROXIMO_VENCER, CONTRATO_VENCIDO, SISTEMA |
29. notifications
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| user_id |
BIGINT FK → users(id) CASCADE |
Usuario destinatario |
| type_id |
INT FK → notification_types(id) |
Tipo |
| title |
VARCHAR(200) |
Título |
| body |
TEXT |
Cuerpo |
| entity_type |
VARCHAR(30) |
Tipo de entidad relacionada |
| entity_id |
BIGINT |
ID de entidad |
| sent_by_email |
BOOLEAN |
Enviado por email |
| read |
BOOLEAN |
Leído |
| read_at |
DATETIME |
Fecha de lectura |
| created_at |
DATETIME |
Creación |
30. receipt_series
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| series_name |
VARCHAR(50) |
Nombre de la serie |
| fiscal_year |
INT |
Año fiscal |
| last_number |
INT DEFAULT 0 |
Último número usado |
| prefix |
VARCHAR(20) DEFAULT 'R-' |
Prefijo del número |
| active |
BOOLEAN |
Serie activa |
| created_at |
DATETIME |
Creación |
| updated_at |
DATETIME |
Modificación |
Unique: (series_name, fiscal_year)
31. email_log
| Columna |
Tipo |
Descripción |
| id |
BIGINT PK |
Auto-increment |
| income_receipt_id |
BIGINT |
ID del recibo de ingreso asociado |
| recipient_email |
VARCHAR(200) |
Email del destinatario |
| subject |
VARCHAR(300) |
Asunto |
| body |
TEXT |
Cuerpo del mensaje |
| success |
BOOLEAN |
Envío exitoso |
| error_message |
TEXT |
Mensaje de error si falló |
| sent_at |
DATETIME |
Fecha de envío |
Notas Técnicas
- Soft-delete: Las tablas
users, properties, tenants tienen columna active para borrado lógico.
- Índices: Las columnas más consultadas tienen índices (foreign keys, fechas, estados).
- Charset:
utf8mb4 con collation utf8mb4_unicode_ci para soporte completo de Unicode.
- Motor: Todas las tablas usan InnoDB para integridad referencial y transacciones.
- Integridad referencial: 32 constraints FK en total (incluyendo V5 para document_type_entity_allowed).
- Al borrar el volumen de datos, el script
init.sql se ejecuta automáticamente al arrancar el contenedor MySQL.
- Hibernate: Opera con
ddl-auto: validate. Cualquier cambio en las entidades JPA requiere actualizar init.sql.
Codificación de caracteres (UTF-8)
Para evitar problemas con acentos y caracteres especiales (tildes, eñes, etc.) en todo el sistema:
- Base de datos: charset
utf8mb4 y collation utf8mb4_unicode_ci.
- Conexión JDBC (
application.yml): la URL incluye characterEncoding=UTF-8&connectionCollation=utf8mb4_unicode_ci para forzar la lectura/escritura en UTF-8.
- Respuestas HTTP (
application.yml): server.servlet.encoding.charset=UTF-8 y force=true para que el header Content-Type siempre incluya charset=UTF-8.
- Frontend (nginx): directiva
charset utf-8; en el bloque server del Dockerfile.frontend.
- Datos de prueba (
seed.sql): el script incluye SET NAMES utf8mb4; al inicio para evitar corrupciones al insertar desde clientes con charset por defecto (latin1).
Si se ejecuta seed.sql manualmente desde un cliente MySQL, usar siempre --default-character-set=utf8mb4 o ejecutar primero SET NAMES utf8mb4;.
Datos de prueba (seed)
El archivo backend/src/main/resources/db/seed.sql contiene datos de demostración (usuarios adicionales, propiedades, inquilinos, contratos, recibos de ingresos, plantillas de gastos, recibos de gastos, incidencias, etc.).
Para poblar la base de datos tras un docker compose down -v:
Las contraseñas de los usuarios de prueba (admin, gerente, contable) son todas admin123 y solo válidas para desarrollo local.