Files

23 KiB

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

property_groups ──── properties ──── property_types
 │                                 │  property_statuses
 │                                 └── property_status_history
 │
roles ──── users ──── user_permissions
 │
 │
 ├── tenants ──── tenant_types
 │
 ├── contracts ──── contract_statuses
 │    │             payment_periods
 │    │
 │    └── income_receipts ──── income_categories
 │         │                    income_statuses
 │         │
 │         └── email_log
 │
 ├── expense_templates ──── expense_categories
 │                           expense_statuses
 │                           payment_periods
 │
 ├── expense_receipts ──── expense_categories
 │                          expense_statuses
 │
 ├── incidents ──── incident_statuses
 │                   incident_priorities
 │
 ├── scheduled_maintenance ──── maintenance_periods
 │
 └── notifications ──── notification_types

documents ──── document_types ──── document_type_entity_allowed

receipt_series

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 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 DNI del inquilino
CIF_EMPRESA TENANT No Para personas jurídicas
FOTO_PROPIEDAD PROPERTY Fotos del inmueble
FOTO_INCIDENCIA INCIDENT No Fotos de la incidencia
FACTURA EXPENSE Factura o justificante del gasto
JUSTIFICANTE_PAGO INCOME 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:

# Copiar el script al contenedor
docker cp backend/src/main/resources/db/seed.sql sa-polar-mysql:/tmp/seed.sql

# Ejecutarlo forzando UTF-8
docker exec sa-polar-mysql bash -c "mysql -u root -proot --default-character-set=utf8mb4 sa_polar < /tmp/seed.sql"

Las contraseñas de los usuarios de prueba (admin, gerente, contable) son todas admin123 y solo válidas para desarrollo local.