17 KiB
Resumen de Implementación: API de Notificaciones - VoxPopuli
Fecha: 29 de Abril de 2024
Versión: 1.0.0
Autor: VoxPopuli Development Team
📋 Resumen Ejecutivo
Se ha implementado exitosamente una nueva API de Notificaciones que se integra con la arquitectura existente del proyecto. Las notificaciones se disparan automáticamente cuando los reportes cambian de estado, proporcionando a los usuarios actualizaciones en tiempo real sobre el progreso de sus reportes.
Puntos Clave:
✅ Nueva API de Notificaciones en puerto 8002
✅ Base de datos MongoDB dedicada (voxpopuli_notifications)
✅ Integración automática con eventos de cambio de estado de reportes
✅ Sistema de consumidores RabbitMQ para procesamiento asíncrono
✅ Arquitectura hexagonal consistente con el resto del proyecto
✅ Docker-compose actualizado con nuevos servicios
📁 Estructura de Archivos Creados
src/
├── domain/
│ └── notifications.py ✨ Nuevo
├── application/
│ ├── ports/
│ │ └── notification_repository.py ✨ Nuevo
│ └── services/
│ └── notification_services.py ✨ Nuevo
├── infrastructure/
│ ├── adapters/
│ │ └── persistence/
│ │ └── notification_repository_mongo.py ✨ Nuevo
│ └── api/
│ └── notifications/ ✨ Nuevo directorio
│ ├── __init__.py
│ ├── app.py
│ ├── router.py
│ ├── root.py
│ ├── schemas.py
│ └── notifications.py
└── consumers/
└── notification_consumer.py ✨ Nuevo
📄 FRONTEND_NOTIFICATIONS_IMPLEMENTATION.md ✨ Nuevo
📄 IMPLEMENTATION_SUMMARY.md ✨ Nuevo (este archivo)
🏗️ Cambios en Archivos Existentes
1. src/core/config.py
- ✏️ Agregado:
mongodb_notifications_dbpara configuración de BD de notificaciones - ✏️ Actualizado comentario de
mongodb_urlpara incluir ambas APIs
mongodb_notifications_db: str = Field(
default="voxpopuli_notifications",
description="Base de datos MongoDB para Notificaciones"
)
2. src/main.py
- ✏️ Importado:
create_notifications_appdesde API de notificaciones - ✏️ Importado:
NotificationConsumer - ✏️ Agregado: Thread para ejecutar API de notificaciones (puerto 8002)
- ✏️ Agregado: Thread para ejecutar consumidor de notificaciones
- ✏️ Actualizado: Mensajes de inicio para mostrar la nueva API
# Cambios principales
from infrastructure.api.notifications.app import create_app as create_notifications_app
from consumers.notification_consumer import NotificationConsumer
# Agregado en run():
notifications_thread = threading.Thread(target=run_notifications_api, daemon=True)
notifications_consumer_thread = threading.Thread(target=run_notifications_consumer, daemon=True)
3. src/infrastructure/adapters/rabbitmq/messages.py
- ✏️ Agregado: Tipo de evento
UPDATE_STATUSaReportEventType - ✏️ Agregado: Campos
old_estado,new_estado,old_visibility,new_visibilityaReportMessage
class ReportEventType(str, Enum):
CREATE = "report.create"
UPDATE_VISIBILITY = "report.update_visibility"
UPDATE_STATUS = "report.update_status" # ✨ Nuevo
DELETE = "report.delete"
@dataclass
class ReportMessage:
# ... campos existentes ...
old_estado: Optional[str] = None # ✨ Nuevo
new_estado: Optional[str] = None # ✨ Nuevo
4. src/application/services/report_services.py
- ✏️ Clase
UpdateReportStatus: Completamente refactorizada para enviar eventos a RabbitMQ - ✏️ Agregado: Importación de
ReportMessageysend_to_queue - ✏️ Agregado: Lógica para crear mensaje UPDATE_STATUS y enviarlo a
notifications_queue - ✏️ Agregado: Captura del estado anterior para comparación
# Cambios en UpdateReportStatus.execute():
old_estado = report.estado # Guardar estado anterior
# Después de actualizar:
if old_estado != new_estado:
message = ReportMessage(
event_type=ReportEventType.UPDATE_STATUS,
id_reporte=report_id,
id_usuario=report.id_usuario,
old_estado=old_estado,
new_estado=new_estado,
# ... otros campos ...
)
send_to_queue("notifications_queue", message.to_dict())
5. docker-compose.yaml
- ✏️ MongoDB: Agregados credenciales de autenticación
- Usuario:
admin/ Contraseña:admin_password - Agregado flag
--authen comando
- Usuario:
- ✏️ Agregado: Servicio RabbitMQ completo con:
- Usuario:
voxpopuli/ Contraseña:voxpopuli_pass - Management UI en puerto 15672
- Healthcheck configurado
- Usuario:
- ✏️ Volúmenes: Agregado
rabbitmq_datapara persistencia
🚀 Nuevos Servicios en Docker Compose
RabbitMQ (Nuevo)
rabbitmq:
image: rabbitmq:3.13-management
container_name: voxpopuli_rabbitmq
ports:
- "5672:5672" # AMQP
- "15672:15672" # Management UI (http://localhost:15672)
credentials:
user: voxpopuli
password: voxpopuli_pass
Acceso Management UI:
- URL: http://localhost:15672
- Usuario:
voxpopuli - Contraseña:
voxpopuli_pass
📊 Base de Datos MongoDB
Nuevas Colecciones
Base de datos: voxpopuli_notifications
Colección: notificaciones
{
"_id": ObjectId,
"id_usuario": 1,
"id_reporte": "uuid-del-reporte",
"message": "¡Tu reporte #uuid ha sido resuelto!",
"fecha": ISODate("2024-04-29T15:30:00Z"),
"read": false
}
Índices Recomendados:
db.notificaciones.createIndex({ "id_usuario": 1, "fecha": -1 })
db.notificaciones.createIndex({ "id_usuario": 1, "read": 1 })
🔄 Flujo de Eventos
Cambio de Estado de Reporte → Notificación
1. Frontend llama:
PUT /reports/{report_id}/status
{ "estado": "resuelto" }
2. API de Reportes:
└─ UpdateReportStatus.execute()
├─ Valida estado
├─ Obtiene reporte actual (estado anterior)
├─ Actualiza en MongoDB
└─ NUEVO: Envía mensaje a RabbitMQ
{
"event_type": "report.update_status",
"id_reporte": "uuid",
"id_usuario": 1,
"old_estado": "en proceso",
"new_estado": "resuelto",
...
}
3. RabbitMQ:
└─ Almacena en queue `notifications_queue`
4. Consumidor de Notificaciones:
├─ Escucha la cola
├─ Recibe el evento UPDATE_STATUS
└─ Procesa mensaje:
└─ NotificationService.send_report_status_notification()
└─ Crea notificación en MongoDB
{
"id_usuario": 1,
"id_reporte": "uuid",
"message": "¡Tu reporte ha sido resuelto!",
"fecha": now(),
"read": false
}
5. Frontend (Polling o WebSocket):
└─ GET /notifications/1
└─ Obtiene notificación creada
📡 Colas RabbitMQ
reports_queue
- Propósito: Eventos de creación, eliminación y cambios de reportes
- Consumidor:
ReportConsumer(consumer de reportes) - Eventos: CREATE, UPDATE_VISIBILITY, DELETE
notifications_queue (NUEVA)
- Propósito: Eventos de cambios de estado para crear notificaciones
- Consumidor:
NotificationConsumer(consumer de notificaciones) - Eventos: UPDATE_STATUS, UPDATE_VISIBILITY
users_queue
- Propósito: Eventos de usuarios
- Consumidor:
UserConsumer
🔌 API Endpoints de Notificaciones
Base: http://localhost:8002
| Método | Endpoint | Descripción | Auth |
|---|---|---|---|
| GET | / |
Health check | No |
| POST | /notifications/ |
Crear notificación (interno) | Sí |
| GET | /notifications/{user_id} |
Obtener notificaciones del usuario | Sí |
| GET | /notifications/{user_id}/unread-count |
Contar no leídas | Sí |
| PUT | /notifications/{notification_id}/read |
Marcar como leída | Sí |
| PUT | /notifications/{user_id}/read-all |
Marcar todas como leídas | Sí |
| DELETE | /notifications/{notification_id} |
Eliminar notificación | Sí |
Documentación interactiva: http://localhost:8002/docs
🔐 Seguridad y Validaciones
Por Implementar en Frontend
-
Autenticación:
- Incluir JWT token en header
Authorization: Bearer {token} - Validar que el token no esté expirado
- Incluir JWT token en header
-
Autorización:
- Backend valida que
user_iden token ===user_iden path - Usuario solo puede ver sus propias notificaciones
- Backend valida que
-
Rate Limiting:
- Considerar máximo 1 request de polling cada 10 segundos
- WebSocket es alternativa para mayor escalabilidad
🧪 Pruebas Recomendadas
1. Test Manual: Crear Notificación
# Terminal 1: Iniciar el proyecto
python src/main.py
# Terminal 2: Test crear notificación
curl -X POST http://localhost:8002/notifications/ \
-H "Content-Type: application/json" \
-d '{
"id_usuario": 1,
"id_reporte": "test-report-123",
"message": "Tu reporte ha sido actualizado"
}'
2. Test Manual: Obtener Notificaciones
curl http://localhost:8002/notifications/1 \
-H "Authorization: Bearer {tu_jwt_token}"
3. Test Manual: Cambio de Estado
# Cambiar estado de reporte → dispara notificación automáticamente
curl -X PUT http://localhost:8002/reports/{report_id}/status \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {tu_jwt_token}" \
-d '{"estado": "resuelto"}'
# Luego verificar que notificación se creó:
curl http://localhost:8002/notifications/1 \
-H "Authorization: Bearer {tu_jwt_token}"
🐳 Comandos Docker
# Levantar todos los servicios
docker-compose up -d
# Ver logs en tiempo real
docker-compose logs -f
# Ver logs específicos de un servicio
docker-compose logs -f mongodb
docker-compose logs -f rabbitmq
# Detener servicios
docker-compose down
# Verificar estado
docker-compose ps
📋 Arquitectura de Capas
┌─────────────────────────────────────────────────────┐
│ Presentación (Frontend) │
│ (Implementar según FRONTEND_NOTIFICATIONS_...) │
└────────────────────┬────────────────────────────────┘
│ HTTP/REST + WebSocket (opcional)
┌────────────────────v────────────────────────────────┐
│ API FastAPI │
│ ├─ /notifications/{user_id} │
│ ├─ /notifications/{notification_id}/read │
│ └─ ... (Ver endpoints arriba) │
└────────────────────┬────────────────────────────────┘
│
┌────────────────────v────────────────────────────────┐
│ Capa de Aplicación (Services) │
│ └─ NotificationService │
│ ├─ create_notification() │
│ ├─ get_user_notifications() │
│ ├─ mark_as_read() │
│ └─ send_report_status_notification() │
└────────────────────┬────────────────────────────────┘
│
┌────────────────────v────────────────────────────────┐
│ Capa de Dominio │
│ └─ Notification (dataclass) │
│ ├─ id_usuario │
│ ├─ id_reporte │
│ ├─ message │
│ ├─ fecha │
│ └─ read │
└────────────────────┬────────────────────────────────┘
│
┌────────────────────v────────────────────────────────┐
│ Puertos (Interfaces Abstractas) │
│ └─ NotificationRepository │
│ ├─ create() │
│ ├─ get_by_user() │
│ ├─ mark_as_read() │
│ └─ ... │
└────────────────────┬────────────────────────────────┘
│
┌────────────────────v────────────────────────────────┐
│ Infraestructura (Adaptadores) │
│ └─ NotificationRepositoryMongo │
│ ├─ Implementa NotificationRepository │
│ └─ Usa MongoDB │
└─────────────────────────────────────────────────────┘
📈 Escalabilidad Futura
Fase 2 - Recomendaciones
-
WebSocket Server:
- Implementar socket.io en FastAPI
- Notificaciones push en tiempo real
- Reducir latencia para usuarios conectados
-
Cache Redis:
- Cachear conteo de no leídas
- Sincronizar estado entre instancias
-
Histórico de Cambios:
- Almacenar todos los cambios de estado
- Mostrar timeline en detalle de reporte
-
Notificaciones Push:
- Integrar con Firebase Cloud Messaging
- Enviar notificaciones a dispositivos móviles
-
Búsqueda Full-Text:
- Elasticsearch para buscar en notificaciones
- Filtrado avanzado
🆘 Troubleshooting
Problema: "Cannot connect to MongoDB"
# Solución: Asegurar que MongoDB esté levantado
docker-compose up -d mongodb
# Verificar logs
docker-compose logs mongodb
Problema: "RabbitMQ connection refused"
# Solución: Asegurar que RabbitMQ esté levantado
docker-compose up -d rabbitmq
# Verificar logs
docker-compose logs rabbitmq
# Acceder a management UI
http://localhost:15672 (usuario: voxpopuli, pass: voxpopuli_pass)
Problema: "Notification not found"
- Verificar que
id_usuarioes correcto - Verificar que JWT token pertenece al usuario
- Revisar que el consumidor está ejecutando
Problema: No se crean notificaciones al cambiar estado
# 1. Verificar que consumidor está corriendo
# (Debe haber thread "Notifications-Consumer" en logs)
# 2. Verificar mensaje en RabbitMQ
# Ir a http://localhost:15672 > Queues > notifications_queue
# 3. Revisar logs del consumidor
docker-compose logs notifications-consumer # Si estuviera en Docker
📚 Documentación Relacionada
- FRONTEND_NOTIFICATIONS_IMPLEMENTATION.md - Guía completa para implementar frontend
- ARCHITECTURE.md - Arquitectura general del proyecto
- DATABASE.md - Información sobre bases de datos
- README.md - Setup y ejecución del proyecto
✅ Checklist de Implementación Backend (Completado)
- Crear modelo de dominio
Notification - Crear interfaz
NotificationRepository - Implementar
NotificationRepositoryMongo - Crear
NotificationServicecon lógica de negocio - Crear esquemas Pydantic
- Implementar endpoints de API
- Crear router de notificaciones
- Crear app FastAPI para notificaciones
- Crear
NotificationConsumer - Actualizar
config.pycon nueva BD - Actualizar
docker-compose.yaml - Modificar
UpdateReportStatuspara enviar eventos - Actualizar
messages.pyconUPDATE_STATUS - Actualizar
main.pypara ejecutar nueva API y consumidor - Crear documentación detallada para frontend
- Crear este documento de resumen
🎯 Próximos Pasos para Frontend
- Leer:
FRONTEND_NOTIFICATIONS_IMPLEMENTATION.md - Crear: Hook
useNotificationscon React Query - Implementar: Componente de icono de campana
- Agregar: Dropdown de notificaciones
- Crear: Página dedicada de notificaciones
- Integrar: Toast notifications
- Implementar: Polling cada 30 segundos
- Testear: Flujo completo de usuario
Estado: ✅ Completado
Próxima Revisión: Después de implementación de frontend
Contacto: Development Team