Files
VoxPopuli/IMPLEMENTATION_SUMMARY.md
2026-04-29 12:28:11 -06:00

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_db para configuración de BD de notificaciones
  • ✏️ Actualizado comentario de mongodb_url para 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_app desde 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_STATUS a ReportEventType
  • ✏️ Agregado: Campos old_estado, new_estado, old_visibility, new_visibility a ReportMessage
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 ReportMessage y send_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 --auth en comando
  • ✏️ Agregado: Servicio RabbitMQ completo con:
    • Usuario: voxpopuli / Contraseña: voxpopuli_pass
    • Management UI en puerto 15672
    • Healthcheck configurado
  • ✏️ Volúmenes: Agregado rabbitmq_data para 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:


📊 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)
GET /notifications/{user_id} Obtener notificaciones del usuario
GET /notifications/{user_id}/unread-count Contar no leídas
PUT /notifications/{notification_id}/read Marcar como leída
PUT /notifications/{user_id}/read-all Marcar todas como leídas
DELETE /notifications/{notification_id} Eliminar notificación

Documentación interactiva: http://localhost:8002/docs


🔐 Seguridad y Validaciones

Por Implementar en Frontend

  1. Autenticación:

    • Incluir JWT token en header Authorization: Bearer {token}
    • Validar que el token no esté expirado
  2. Autorización:

    • Backend valida que user_id en token === user_id en path
    • Usuario solo puede ver sus propias notificaciones
  3. 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

  1. WebSocket Server:

    • Implementar socket.io en FastAPI
    • Notificaciones push en tiempo real
    • Reducir latencia para usuarios conectados
  2. Cache Redis:

    • Cachear conteo de no leídas
    • Sincronizar estado entre instancias
  3. Histórico de Cambios:

    • Almacenar todos los cambios de estado
    • Mostrar timeline en detalle de reporte
  4. Notificaciones Push:

    • Integrar con Firebase Cloud Messaging
    • Enviar notificaciones a dispositivos móviles
  5. 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_usuario es 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 NotificationService con lógica de negocio
  • Crear esquemas Pydantic
  • Implementar endpoints de API
  • Crear router de notificaciones
  • Crear app FastAPI para notificaciones
  • Crear NotificationConsumer
  • Actualizar config.py con nueva BD
  • Actualizar docker-compose.yaml
  • Modificar UpdateReportStatus para enviar eventos
  • Actualizar messages.py con UPDATE_STATUS
  • Actualizar main.py para ejecutar nueva API y consumidor
  • Crear documentación detallada para frontend
  • Crear este documento de resumen

🎯 Próximos Pasos para Frontend

  1. Leer: FRONTEND_NOTIFICATIONS_IMPLEMENTATION.md
  2. Crear: Hook useNotifications con React Query
  3. Implementar: Componente de icono de campana
  4. Agregar: Dropdown de notificaciones
  5. Crear: Página dedicada de notificaciones
  6. Integrar: Toast notifications
  7. Implementar: Polling cada 30 segundos
  8. Testear: Flujo completo de usuario

Estado: Completado
Próxima Revisión: Después de implementación de frontend
Contacto: Development Team