515
IMPLEMENTATION_SUMMARY.md
Normal file
515
IMPLEMENTATION_SUMMARY.md
Normal file
@@ -0,0 +1,515 @@
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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`
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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)
|
||||
```yaml
|
||||
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`
|
||||
```json
|
||||
{
|
||||
"_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:**
|
||||
```javascript
|
||||
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
|
||||
|
||||
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
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
curl http://localhost:8002/notifications/1 \
|
||||
-H "Authorization: Bearer {tu_jwt_token}"
|
||||
```
|
||||
|
||||
### 3. Test Manual: Cambio de Estado
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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"
|
||||
```bash
|
||||
# Solución: Asegurar que MongoDB esté levantado
|
||||
docker-compose up -d mongodb
|
||||
|
||||
# Verificar logs
|
||||
docker-compose logs mongodb
|
||||
```
|
||||
|
||||
### Problema: "RabbitMQ connection refused"
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
- [x] Crear modelo de dominio `Notification`
|
||||
- [x] Crear interfaz `NotificationRepository`
|
||||
- [x] Implementar `NotificationRepositoryMongo`
|
||||
- [x] Crear `NotificationService` con lógica de negocio
|
||||
- [x] Crear esquemas Pydantic
|
||||
- [x] Implementar endpoints de API
|
||||
- [x] Crear router de notificaciones
|
||||
- [x] Crear app FastAPI para notificaciones
|
||||
- [x] Crear `NotificationConsumer`
|
||||
- [x] Actualizar `config.py` con nueva BD
|
||||
- [x] Actualizar `docker-compose.yaml`
|
||||
- [x] Modificar `UpdateReportStatus` para enviar eventos
|
||||
- [x] Actualizar `messages.py` con `UPDATE_STATUS`
|
||||
- [x] Actualizar `main.py` para ejecutar nueva API y consumidor
|
||||
- [x] Crear documentación detallada para frontend
|
||||
- [x] 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
|
||||
Reference in New Issue
Block a user