🔑 RoomManager
Gestión integral de alquiler por habitaciones: contratos, caja, liquidaciones a propietarios y firma digital
Escala del Proyecto
Descripción General
Alquilar un piso completo es sencillo. Alquilarlo por habitaciones — coliving o rent to rent — multiplica el trabajo administrativo: cada habitación tiene su inquilino, su contrato, su fianza, su fecha de cobro y su parte proporcional de los gastos comunes. Con cinco pisos y cuatro habitaciones cada uno, eso son veinte relaciones contractuales simultáneas.
RoomManager gestiona ese modelo completo: pisos, habitaciones, inquilinos, alquileres, pagos, fianzas, gastos con comprobante, incidencias, tareas y calendario. Y cierra el círculo por arriba, con el módulo de caja: liquida al propietario del piso lo que le corresponde, genera el recibo y recoge su firma digital.
Además publica una oferta pública de las habitaciones libres, de forma que los interesados envían consultas que entran directamente en el sistema. Es software de gestión con su propia puerta de entrada comercial.
Tecnologías Utilizadas
PHP
MySQL / MariaDB
Bootstrap 5
JavaScript
API REST
Stripe
Health check
Módulos del Sistema
Inventario con servicios asociados a cada piso y a cada habitación por separado, y galería de fotos.
Ficha del inquilino, avatar, documentación y cambio de habitación sin perder el histórico.
Contratos con generación en PDF, fechas, importes y estado.
Registro de cobros por alquiler con su comprobante adjunto.
Control de fianzas entregadas, retenidas y devueltas.
Gastos del piso con subida de comprobante y reparto.
Liquidación al propietario por periodo, con desglose de items, recibo imprimible y firma digital.
Parte de incidencias por habitación o piso con seguimiento.
Trabajo pendiente y avisos por fecha.
Vista unificada de cobros, vencimientos y tareas.
Landing con las habitaciones disponibles y formulario de consulta.
Bandeja de las consultas recibidas desde la oferta pública.
Cifras agregadas de ocupación e ingresos.
Gestión de usuarios y de suscripciones de la plataforma.
Arquitectura
Arquitectura híbrida deliberada: las páginas son PHP renderizado en servidor — carga
inmediata y funciona sin JavaScript — pero cada acción interactiva llama a un
endpoint REST de api/ que responde JSON. Son 33
endpoints, uno por recurso, más los webhooks de Stripe y un
health.php para monitorización.
RoomManager/ ├── index.php · landing.php · oferta.php # privado y público ├── login.php · register.php · forgot_password.php · reset_password.php ├── pisos.php · habitaciones.php · inquilinos.php · alquileres.php ├── pagos.php · fianzas.php · gastos.php · caja.php ├── firmar_liquidacion.php · recibo_liquidacion.php # firma y recibo ├── checkout.php · pago_exitoso.php · suscripcion_expirada.php ├── api/ # 33 endpoints REST + webhook_stripe + health ├── config/ # database.php, auth.php ├── includes/ # header, footer, rental_helpers ├── sql/ # schema + 12 migraciones + deploy_safe_upgrade.sh ├── uploads/ # fotos, avatares, comprobantes └── backups/ # volcados previos a migración
Base de Datos
22 tablas en el esquema de producción. Las tres de caja son las que hacen posible la liquidación con firma: cabecera, líneas de detalle y estado de firma.
| Tabla | Contenido |
|---|---|
| usuarios | Cuentas de acceso con su suscripción asociada |
| pisos | Inmuebles gestionados |
| habitaciones | Habitaciones de cada piso, con precio y estado |
| inquilinos | Personas alojadas, con avatar y documentación |
| alquileres | Relación contractual entre inquilino y habitación |
| pagos | Cobros registrados con su comprobante |
| fianzas | Fianzas entregadas, retenidas y devueltas |
| gastos | Gastos del piso con comprobante adjunto |
| servicios | Catálogo de servicios (luz, agua, internet, limpieza…) |
| piso_servicios | Servicios contratados a nivel de piso |
| habitacion_servicios | Servicios incluidos en una habitación concreta |
| caja_propietarios | Cuenta corriente de cada propietario |
| caja_liquidaciones | Liquidación por periodo, con su estado de firma |
| caja_liquidacion_items | Líneas de detalle de cada liquidación |
| consultas_habitaciones | Consultas recibidas desde la oferta pública |
| incidencias | Partes de incidencia con seguimiento |
| tareas | Trabajo pendiente asignado |
| recordatorios | Avisos por fecha |
| documentos | Documentación adjunta |
| fotos_habitaciones | Galería por habitación |
| notificaciones | Avisos en la aplicación |
| login_attempts | Intentos de acceso, para el bloqueo por fuerza bruta |
| password_resets | Tokens de recuperación de contraseña |
| preferencias_usuario | Ajustes de interfaz por usuario |
Integraciones Externas
Cobro de la suscripción a la plataforma mediante sesión de Checkout, con páginas de éxito y cancelación.
api/webhook_stripe.php recibe los eventos y activa, renueva o
expira la suscripción del usuario.
Contratos de alquiler y recibos de liquidación exportables e imprimibles.
api/health.php expone el estado del servicio y de la base de
datos para monitorización externa.
Flujo Completo de Funcionamiento
- Suscripción: el usuario se registra y activa su plan mediante Stripe Checkout; el webhook confirma el alta.
- Alta del inmueble: se crea el piso, sus habitaciones y los servicios que incluye cada una.
- Publicación: las habitaciones libres aparecen en la oferta pública con sus fotos.
- Consulta entrante: un interesado envía el formulario y la consulta entra en la bandeja del gestor.
- Contrato: se da de alta al inquilino, se firma el alquiler y se genera el contrato en PDF.
- Fianza y cobros: se registra la fianza y se van anotando los pagos mensuales con su comprobante.
- Gastos: los gastos del piso se registran con justificante y se reparten.
- Liquidación: al cerrar el periodo, la caja calcula lo que corresponde al propietario y desglosa cada línea.
- Firma digital: el propietario firma el recibo; el sistema guarda su nombre, la IP y la fecha como prueba.
- Recibo: se emite el recibo de liquidación imprimible como cierre documental de la operación.
Seguridad Implementada
- Contraseñas con
password_hash()y verificación por hash. - Bloqueo por fuerza bruta con registro de intentos en la tabla
login_attempts. - Recuperación de contraseña por token de un solo uso con caducidad.
- Consultas con prepared statements PDO en toda la aplicación.
- Verificación de firma del webhook de Stripe antes de alterar el estado de la suscripción.
- Trazabilidad de la firma digital: se almacena nombre, IP y fecha de firma de cada liquidación.
- Comprobantes y documentos servidos por ruta controlada, no como estático público.
- Configuración fuera del código y directorios sensibles protegidos por
.htaccess.
Retos Técnicos y Decisiones de Diseño
Migrar en producción sin perder datos
El esquema evolucionó doce veces con inquilinos y cobros reales dentro. En lugar de
un único schema.sql destructivo, cada cambio es una migración numerada
(migration_v2 … migration_v12) acompañada de
deploy_safe_upgrade.sh, que hace copia de seguridad antes de aplicar.
La carpeta backups/ conserva los volcados previos a cada salto.
Dar valor probatorio a una firma en el navegador
Una firma dibujada en un canvas no vale nada por sí sola. Lo que le da peso es el
contexto: api/caja_firma.php guarda junto a la firma el nombre
declarado, la dirección IP, la fecha exacta y el estado del proceso. Con eso el
recibo de liquidación es defendible ante el propietario.
Servidor y API a la vez
Las páginas se renderizan en PHP porque cargan al instante y no dependen de JavaScript; pero cada acción concreta pasa por un endpoint REST. Así el frontend actualiza sin recargar y esos mismos endpoints quedan disponibles para cualquier cliente futuro.
Mi Rol
Desarrollador full stack — autor único.
Modelo de datos, los 33 endpoints, el frontend con Bootstrap 5, la integración de Stripe, el circuito de firma digital, la estrategia de migraciones y el despliegue.
Estado del Proyecto
En producción en roommanager.tinoprop.com, con datos
reales de pisos, inquilinos y liquidaciones. El esquema va por la doceava migración.
Código y Enlaces
El repositorio no es público al contener configuración de producción y datos de inquilinos reales. Puedo mostrar el código en una entrevista.