# Referencia de la API REST ## Formato General Todas las respuestas siguen el formato `ApiResponse`: ```json { "success": true, "message": "OK", "data": { ... }, "timestamp": "2026-07-04T12:00:00" } ``` Los errores usan el mismo formato con `success: false` y mensaje descriptivo. ## Autenticación ### `POST /api/auth/login` Iniciar sesión. **Request body:** ```json { "username": "admin", "password": "admin123" } ``` **Response (200):** ```json { "success": true, "message": "OK", "data": { "accessToken": "eyJhbGciOi...", "refreshToken": "eyJhbGciOi...", "tokenType": "Bearer", "userId": 1, "username": "admin", "role": "ADMIN" } } ``` ### `POST /api/auth/register` Registrar nuevo usuario. **Request body:** ```json { "username": "usuario1", "email": "user@example.com", "password": "password123", "fullName": "Usuario Ejemplo", "phone": "600123456", "roleName": "GERENTE" } ``` ### `POST /api/auth/refresh` Renovar token de acceso. **Request body:** ```json { "refreshToken": "eyJhbGciOi..." } ``` ## Usuarios (solo ADMIN) | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/users` | Listar todos los usuarios | | `GET` | `/api/users/{id}` | Obtener usuario por ID | | `PUT` | `/api/users/{id}` | Actualizar usuario | | `DELETE` | `/api/users/{id}` | Desactivar usuario (soft-delete) | ## Propiedades | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/properties` | Listar propiedades activas | | `GET` | `/api/properties/tree` | Obtener propiedades raíz (sin padre) | | `GET` | `/api/properties/{id}/children` | Obtener hijos de una propiedad | | `GET` | `/api/properties/{id}` | Obtener propiedad por ID | | `POST` | `/api/properties` | Crear propiedad | | `PUT` | `/api/properties/{id}` | Actualizar propiedad | | `PATCH` | `/api/properties/{id}/status` | Cambiar estado de propiedad | | `GET` | `/api/properties/{id}/history` | Historial de cambios de estado | | `DELETE` | `/api/properties/{id}` | Eliminar propiedad (soft-delete) | | `GET` | `/api/properties/types` | Listar tipos de propiedad | | `GET` | `/api/properties/statuses` | Listar estados de propiedad | **Estructura de Property:** ```json { "id": 1, "parent": null, "group": { "id": 1, "name": "Residencial Centro" }, "type": { "id": 2, "name": "PISO", "description": "Vivienda..." }, "status": { "id": 2, "name": "ALQUILADO", "description": "..." }, "reference": "PIS-001", "name": "Piso Centro", "addressStreet": "Calle Mayor", "addressNumber": "12", "addressCity": "Madrid", "addressPostalCode": "28001", "addressProvince": "Madrid", "cadastralRef": "1234567VK1234A", "surfaceM2": 85.50, "floor": "3", "door": "A", "rentalAmount": 850.00, "active": true } ``` ## Conjuntos (Property Groups) | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/property-groups` | Listar todos los conjuntos | | `GET` | `/api/property-groups/{id}` | Obtener conjunto por ID | | `POST` | `/api/property-groups` | Crear conjunto | | `PUT` | `/api/property-groups/{id}` | Actualizar conjunto | | `DELETE` | `/api/property-groups/{id}` | Eliminar conjunto | | `GET` | `/api/property-groups/{id}/properties` | Propiedades pertenecientes al conjunto | **Estructura de PropertyGroup:** ```json { "id": 1, "name": "Residencial Centro", "addressStreet": "Calle Mayor", "addressNumber": "10", "addressCity": "Madrid", "addressPostalCode": "28001", "isActive": true } ``` ## Inquilinos | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/tenants?search=` | Listar/buscar inquilinos | | `GET` | `/api/tenants/{id}` | Obtener inquilino por ID | | `POST` | `/api/tenants` | Crear inquilino | | `PUT` | `/api/tenants/{id}` | Actualizar inquilino | | `DELETE` | `/api/tenants/{id}` | Eliminar inquilino (soft-delete) | ## Contratos | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/contracts?propertyId=&tenantId=` | Listar/filtrar contratos | | `GET` | `/api/contracts/{id}` | Obtener contrato por ID | | `POST` | `/api/contracts` | Crear contrato (auto: propiedad → ALQUILADO) | | `PUT` | `/api/contracts/{id}` | Actualizar contrato | | `POST` | `/api/contracts/{id}/terminate` | Terminar contrato (auto: propiedad → VACIO) | ## Recibos de Ingresos (Income Receipts) | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/income-receipts?propertyId=&contractId=&from=&to=&statusId=` | Listar/filtrar recibos de ingresos | | `GET` | `/api/income-receipts/pending` | Total pendiente de cobro | | `GET` | `/api/income-receipts/{id}` | Obtener recibo por ID | | `POST` | `/api/income-receipts` | Crear recibo | | `PUT` | `/api/income-receipts/{id}` | Actualizar recibo | | `PATCH` | `/api/income-receipts/{id}/pay` | Registrar pago | | `DELETE` | `/api/income-receipts/{id}` | Eliminar recibo | ## Plantillas de Gastos (Expense Templates) | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/expense-templates?propertyId=&categoryId=` | Listar/filtrar plantillas | | `GET` | `/api/expense-templates/active` | Plantillas activas | | `GET` | `/api/expense-templates/{id}` | Obtener plantilla por ID | | `POST` | `/api/expense-templates` | Crear plantilla | | `PUT` | `/api/expense-templates/{id}` | Actualizar plantilla | | `PATCH` | `/api/expense-templates/{id}/toggle` | Activar/desactivar plantilla | | `POST` | `/api/expense-templates/{id}/generate` | Generar recibo de gasto desde plantilla | | `DELETE` | `/api/expense-templates/{id}` | Eliminar plantilla | ## Recibos de Gastos (Expense Receipts) | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/expense-receipts?propertyId=&templateId=&from=&to=&statusId=` | Listar/filtrar recibos de gastos | | `GET` | `/api/expense-receipts/{id}` | Obtener recibo por ID | | `POST` | `/api/expense-receipts` | Crear recibo manual | | `PUT` | `/api/expense-receipts/{id}` | Actualizar recibo | | `PATCH` | `/api/expense-receipts/{id}/pay` | Registrar pago | | `DELETE` | `/api/expense-receipts/{id}` | Eliminar recibo | ## Incidencias | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/incidents?propertyId=&statusId=` | Listar/filtrar incidencias | | `GET` | `/api/incidents/{id}` | Obtener incidencia por ID | | `POST` | `/api/incidents` | Crear incidencia | | `PATCH` | `/api/incidents/{id}/status` | Actualizar estado | | `PATCH` | `/api/incidents/{id}/assign` | Asignar técnico | | `PATCH` | `/api/incidents/{id}/schedule` | Programar reparación | | `DELETE` | `/api/incidents/{id}` | Eliminar incidencia | **Flujo de estados de incidencia:** `SIN_REVISAR` → `TECNICO_AVISADO` → `REPARACION_PREVISTA` → `REPARADO` → `IGNORADO` → `ANULADO` ## Mantenimiento Programado | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/maintenance?propertyId=` | Listar mantenimientos | | `GET` | `/api/maintenance/pending` | Mantenimientos pendientes | | `GET` | `/api/maintenance/upcoming?from=&to=` | Próximos mantenimientos | | `GET` | `/api/maintenance/{id}` | Obtener por ID | | `POST` | `/api/maintenance` | Crear mantenimiento | | `PUT` | `/api/maintenance/{id}` | Actualizar | | `PATCH` | `/api/maintenance/{id}/complete` | Marcar completado | | `DELETE` | `/api/maintenance/{id}` | Eliminar | ## Recibos | Método | Ruta | Descripción | Rol | |--------|------|-------------|-----| | `GET` | `/api/receipts` | Listar recibos | ADMIN, GERENTE, CONTABLE | | `GET` | `/api/receipts/{id}` | Obtener recibo | ADMIN, GERENTE, CONTABLE | | `POST` | `/api/receipts/generate` | Generar recibo individual | ADMIN, GERENTE, CONTABLE | | `POST` | `/api/receipts/generate-monthly` | Generar recibos mensuales | ADMIN | | `GET` | `/api/receipts/{id}/pdf` | Descargar PDF | ADMIN, GERENTE, CONTABLE | | `POST` | `/api/receipts/{id}/send-email` | Enviar por email | ADMIN, GERENTE, CONTABLE | | `GET` | `/api/receipts/reports/monthly?year=&month=` | Reporte Excel mensual | ADMIN, GERENTE, CONTABLE | ### `POST /api/receipts/generate` Genera un recibo individual para un contrato específico. **Request body:** ```json { "contractId": 1, "issueDate": "2026-07-01", "dueDate": "2026-07-15", "description": "Alquiler julio 2026" } ``` ### `POST /api/receipts/generate-monthly` Genera recibos para todos los contratos activos cuyo `payment_day` coincida con el mes actual. Solo ADMIN. ### `GET /api/receipts/{id}/pdf` Devuelve el PDF del recibo como `application/pdf` con header `Content-Disposition: attachment; filename="recibo-R-2026-00001.pdf"`. ### `POST /api/receipts/{id}/send-email` Envía el recibo por email al inquilino con el PDF adjunto. ### `GET /api/receipts/reports/monthly?year=2026&month=7` Descarga un informe Excel (`.xlsx`) con el resumen de recibos de ingresos, recibos de gastos y balance del mes. ## Notificaciones | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/notifications?unreadOnly=true` | Listar notificaciones del usuario | | `GET` | `/api/notifications/unread-count` | Contar no leídas | | `PATCH` | `/api/notifications/{id}/read` | Marcar como leída | | `PATCH` | `/api/notifications/read-all` | Marcar todas como leídas | ## Dashboard | Método | Ruta | Descripción | |--------|------|-------------| | `GET` | `/api/dashboard/summary` | Resumen general (contadores, YTD) | | `GET` | `/api/dashboard/income-expense?year=2026` | Ingresos/gastos mensuales del año | **Respuesta de `/summary`:** ```json { "success": true, "data": { "totalProperties": 10, "rentedProperties": 5, "activeContracts": 5, "totalTenants": 8, "openIncidents": 2, "pendingMaintenance": 1, "incomeYtd": 42500.00, "expenseYtd": 12300.00, "pendingIncome": 2850.00 } } ``` ## Documentos | Método | Ruta | Descripción | |--------|------|-------------| | `POST` | `/api/documents/upload` | Subir archivo (multipart) | | `GET` | `/api/documents/entity/{entityType}/{entityId}` | Documentos de una entidad | | `GET` | `/api/documents/types-for-entity/{entityType}` | Tipos de documento permitidos para una entidad | | `GET` | `/api/documents/search` | Búsqueda avanzada con filtros | | `GET` | `/api/documents/{id}/download` | Descargar documento | | `DELETE` | `/api/documents/{id}` | Eliminar documento | | `GET` | `/api/documents/{id}/entities` | Ver entidades asociadas a un documento | | `POST` | `/api/documents/{id}/entities` | Asociar documento a otra entidad | | `DELETE` | `/api/documents/{id}/entities/{entityType}/{entityId}` | Desasociar documento de una entidad | **Tipos de entidad soportados:** `PROPERTY`, `CONTRACT`, `TENANT`, `INCIDENT`, `MAINTENANCE` **Upload params:** `file` (multipart), `entityType`, `entityId`, `documentTypeId`, `description` (opcional) ### `GET /api/documents/types-for-entity/{entityType}` Devuelve los tipos de documento permitidos para una entidad, indicando cuáles son obligatorios. **Response (200):** ```json { "success": true, "data": [ { "documentTypeId": 1, "documentTypeName": "CONTRATO", "canUpload": true, "mustHave": true, "description": "Documento principal del contrato de alquiler" }, { "documentTypeId": 10, "documentTypeName": "OTRO", "canUpload": true, "mustHave": false, "description": "Otros documentos del contrato" } ] } ``` ## Códigos de Error | Código | Significado | |--------|-------------| | 200 | OK | | 201 | Creado | | 400 | Bad Request (validación, datos incorrectos) | | 401 | No autenticado | | 403 | No autorizado (rol insuficiente) | | 404 | Recurso no encontrado | | 409 | Conflicto (duplicado) | | 500 | Error interno del servidor | ## Documentación Interactiva (Swagger) Disponible en `http://localhost:8080/swagger-ui.html` cuando el backend está corriendo. También se puede obtener el spec OpenAPI en `http://localhost:8080/api-docs`.