Arquitectura del Sistema
Esta página profundiza en cómo está construido FeedbackPulse SaaS. Comprender la arquitectura te ayuda a depurar problemas, extender la plataforma y tomar decisiones de despliegue informadas.
Stack Tecnológico
| Capa | Tecnología | Propósito |
|---|---|---|
| Backend | Laravel 12 (PHP 8.4+) | Framework de aplicación, enrutamiento, ORM, colas |
| Base de Datos | MySQL 8.0+ / MariaDB 10.6+ | Almacenamiento persistente de datos |
| Frontend | Blade + Alpine.js + Tailwind CSS | UI renderizada en servidor con componentes reactivos |
| Pagos | Stripe PHP SDK + PayPal REST API | Facturación por suscripción |
| IA | OpenAI GPT API | Análisis de sentimiento, etiquetado automático, sugerencias de respuesta |
| Autenticación | Laravel Socialite | OAuth con Google y GitHub |
| Correo | Laravel Mail (SMTP) | Correos transaccionales, resúmenes, informes |
| Tiempo Real | Server-Sent Events (SSE) | Transmisión en vivo de envíos |
| Tareas Programadas | Laravel Scheduler (cron) | Resúmenes, expiración de pruebas, retención de datos |
Modelo Multi-Inquilino
FeedbackPulse utiliza un modelo de multi-inquilino de base de datos única y esquema compartido. Esto significa:
- Una sola base de datos sirve a todos los inquilinos
- Cada tabla con ámbito de inquilino tiene una columna
tenant_id - Un scope global (
TenantScope) filtra automáticamente todas las consultas al inquilino actual - Un trait (
BelongsToTenant) rellena automáticamentetenant_idal crear y aplica el scope
Cómo Funciona la Resolución de Inquilinos
Cuando llega una solicitud, el middleware ResolveTenant determina el inquilino actual con la siguiente prioridad:
- Subdominio —
acme.yourdomain.com→ busca el inquilino con el subdominio "acme" - Dominio personalizado —
feedback.acmecorp.com→ busca el dominio verificado en la tablatenant_domains - Usuario autenticado — recurre al
tenant_iddel usuario con sesión iniciada
Para páginas públicas (como /wall/acme-corp), el inquilino se resuelve desde el slug de la URL directamente en el controlador (sin pasar por el middleware).
Aislamiento de Datos
+------------------------------------------+
| Base de Datos |
| |
| products (tenant_id = 1) -> Acme data |
| products (tenant_id = 2) -> TechCorp |
| products (tenant_id = 3) -> E-Commerce |
| |
| TenantScope garantiza que Acme SOLO vea |
| filas donde tenant_id = 1 |
+------------------------------------------+
Seguridad: Los controladores de cara al público usan
withoutGlobalScopes()para omitir el scope del inquilino y luego filtran manualmente por ID de inquilino. Esto es intencional: las páginas públicas necesitan mostrar datos sin una sesión autenticada.
Estructura de Directorios
feedbackpulse-saas/
+-- app/
| +-- Console/Commands/ # 7 comandos artisan (resúmenes, retención, alertas)
| +-- Http/
| | +-- Controllers/
| | | +-- Admin/ # Controladores del panel de superadmin
| | | +-- Auth/ # Login, registro, 2FA, OAuth, suplantación
| | | +-- Customer/ # Portal del cliente
| | | +-- Public/ # Páginas públicas (muro, formulario, hoja de ruta, registro de cambios, hub)
| | | +-- Tenant/ # Controladores del panel del inquilino
| | | +-- Webhooks/ # Manejadores de webhooks de Stripe y PayPal
| | +-- Middleware/ # 15 middleware personalizados
| +-- Mail/ # 7 clases de correo
| +-- Models/ # 28 modelos Eloquent
| +-- Scopes/ # TenantScope (scope global de consultas)
| +-- Services/ # Lógica de negocio (IA, pagos, webhooks, etc.)
| +-- Traits/ # Trait BelongsToTenant
| +-- Providers/ # Proveedores de servicios
+-- config/ # 11 archivos de configuración de Laravel
+-- database/
| +-- migrations/ # Más de 35 archivos de migración
| +-- seeders/ # Seeders de datos de demostración
+-- public/ # Raíz web (index.php, assets, enlace simbólico de almacenamiento)
+-- resources/views/ # 86 plantillas Blade
| +-- admin/ # Vistas del superadmin
| +-- auth/ # Vistas de autenticación (login, registro, 2FA)
| +-- tenant/ # Vistas del panel del inquilino
| +-- public/ # Vistas de páginas públicas
| +-- emails/ # Plantillas de correo electrónico
| +-- layouts/ # Plantillas de diseño (admin, inquilino, invitado, instalación)
| +-- partials/ # Componentes compartidos (nav, meta, paleta de comandos)
| +-- install/ # Vistas del instalador web
| +-- legal/ # Páginas de privacidad, términos y cookies
| +-- errors/ # Páginas de error (403, 404, 419, 429, 500)
| +-- landing/ # Parciales de la página de inicio
+-- routes/
| +-- web.php # 416 líneas de rutas web
| +-- api.php # Rutas de la API v2
+-- storage/ # Subidas, caché, sesiones, registros
+-- bootstrap/ # Archivos de arranque del framework
Roles de Usuario
FeedbackPulse tiene cuatro roles de usuario, almacenados en la columna users.role:
| Rol | Acceso | URL de Inicio de Sesión |
|---|---|---|
superadmin | Control total de la plataforma (/admin/*) | /login |
tenant_admin | Control total del inquilino (/dashboard, /settings/*) | /login |
tenant_staff | Acceso limitado al inquilino (sin facturación, sin eliminar) | /login |
customer | Solo portal del cliente (/customer/dashboard) | /customer/login |
Jerarquía de Roles
superadmin
+-- Puede suplantar a cualquier tenant_admin
+-- tenant_admin
+-- Puede invitar a tenant_staff
+-- Puede gestionar facturación, configuración y equipo
+-- tenant_staff
+-- Puede gestionar envíos y campañas
+-- customer
+-- Puede ver su propio feedback
Ciclo de Vida de una Solicitud
Esto es lo que ocurre cuando una solicitud llega a FeedbackPulse:
Solicitud del Navegador
|
v
public/index.php
|
v
Laravel Kernel (pila de middleware)
|
+-- EnsureInstalled -> Redirige a /install si no está configurado
+-- SecurityHeaders -> Agrega HSTS, CSP, X-Frame-Options
+-- VerifyCsrfToken -> Verifica token CSRF (excepto webhooks)
+-- ResolveTenant -> Determina el inquilino actual
+-- Authenticate -> Verifica si el usuario ha iniciado sesión
+-- EnsureTenantAccess -> Verifica que el usuario pertenezca al inquilino
+-- EnsureTwoFactorVerified -> Comprueba 2FA si está habilitado
+-- CheckPlanLimit -> Aplica los límites de características del plan
|
v
Controlador (procesa la solicitud)
|
v
Vista Blade (renderiza HTML)
|
v
Respuesta -> Navegador
Arquitectura de Base de Datos
Tablas Principales
| Tabla | Filas Por | Propósito |
|---|---|---|
tenants | Plataforma | Cuentas multi-inquilino |
users | Plataforma | Todas las cuentas de usuario (todos los roles) |
plans | Plataforma | Planes de suscripción |
platform_settings | Plataforma | Configuración global clave-valor |
products | Inquilino | Productos de feedback |
feedback_campaigns | Inquilino | Configuraciones del formulario de feedback |
feedback_submissions | Inquilino | Envíos individuales de feedback |
feedback_tags | Inquilino | Etiquetas (muchos a muchos con envíos) |
roadmap_items | Inquilino | Elementos kanban de la hoja de ruta |
roadmap_votes | Inquilino | Votos anónimos en elementos de la hoja de ruta |
feature_requests | Inquilino | Sugerencias de funcionalidades de la comunidad |
changelog_entries | Inquilino | Notas de versión del producto |
team_members | Inquilino | Registros de miembros del equipo |
team_invitations | Inquilino | Invitaciones pendientes |
api_keys | Inquilino | Claves de acceso a la API |
audit_logs | Plataforma | Registro de auditoría de acciones |
notifications | Plataforma | Notificaciones en la aplicación |
payment_events | Plataforma | Eventos de webhook de Stripe/PayPal |
webhook_logs | Inquilino | Registros de entrega de webhooks salientes |
data_deletion_requests | Inquilino | Solicitudes de eliminación GDPR |
landing_pages | Plataforma | Datos del constructor de páginas de inicio |
tenant_domains | Inquilino | Mapeos de dominios personalizados |
referral_codes | Inquilino | Códigos de referido |
referral_conversions | Plataforma | Seguimiento de conversiones de referido |
cron_logs | Plataforma | Registros de ejecución de tareas programadas |
Índices Clave
Todas las tablas con ámbito de inquilino están indexadas en (tenant_id, created_at) para un rendimiento óptimo de las consultas. La tabla feedback_submissions tiene índices adicionales en status, product_id, campaign_id y sentiment_label.
Arquitectura de Seguridad
| Capa | Protección |
|---|---|
| Transporte | HTTPS forzado, cabeceras HSTS |
| Autenticación | Bcrypt (12 rondas), 2FA opcional (TOTP) |
| Autorización | Middleware basado en roles + clases de políticas |
| CSRF | Tokens CSRF de Laravel en todos los formularios |
| XSS | Escape automático de Blade ({{ }}) |
| Inyección SQL | Consultas parametrizadas de Eloquent |
| Limitación de Velocidad | Throttling por ruta (5-120 req/min) |
| Seguridad de API | Claves de API con hash SHA256, límites por inquilino |
| Seguridad de Webhooks | Verificación de firma HMAC (Stripe), protección SSRF |
| Datos | Configuración sensible cifrada en reposo |
| Sesiones | Cifradas, solo HTTP, cookies seguras |
| Cabeceras | CSP, X-Frame-Options, X-Content-Type-Options |
Próximos Pasos
- Glosario de Términos — comprende la terminología
- Guía de Instalación — configura tu servidor
- Esquema de Base de Datos — estructuras detalladas de tablas