erp-core/docs/04-modelado/domain-models/messaging-domain.md

12 KiB

MODELO DE DOMINIO: Mensajería y Notificaciones

Módulos: MGN-012 (Reportes), MGN-014 (Mensajería y Notificaciones) Fecha: 2025-11-24 Referencia Odoo: mail (mail.thread, mail.message, mail.followers, mail.activity) Referencia Gamilit: notifications_management schema


Diagrama de Entidades (Texto UML)

[Message]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - author_id: UUID (FK user)
  - model: String (ej: "SaleOrder")
  - res_id: UUID (ID del registro)
  - message_type: ENUM (note, comment, notification, email)
  - subject: String
  - body: Text
  - parent_id: UUID (FK self)
  - subtype_id: UUID (FK)

  1 <----> * [Attachment]
  1 <----> * [Notification]

[Follower]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - model: String
  - res_id: UUID
  - partner_id: UUID (FK)
  - user_id: UUID (FK)

[Notification]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - message_id: UUID (FK)
  - user_id: UUID (FK)
  - notification_type: ENUM (inbox, email, push)
  - is_read: Boolean
  - read_at: Timestamp

[Activity]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - model: String
  - res_id: UUID
  - activity_type_id: UUID (FK)
  - user_id: UUID (FK)
  - assigned_by: UUID (FK user)
  - summary: String
  - note: Text
  - date_deadline: Date
  - status: ENUM (pending, done, overdue, cancelled)
  - completed_at: Timestamp

[ActivityType]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - name: String
  - icon: String
  - sequence: Integer
  - default_user_id: UUID (FK)

[MessageSubtype]
  - id: UUID (PK)
  - name: String
  - description: Text
  - internal: Boolean
  - parent_id: UUID (FK self)

[Attachment]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - name: String
  - file_path: String
  - file_size: Integer
  - mimetype: String
  - checksum: String
  - model: String
  - res_id: UUID

[EmailTemplate]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - name: String
  - model: String
  - subject: String (Handlebars template)
  - body_html: Text (Handlebars template)
  - email_from: String
  - email_to: String

[TrackingValue]
  - id: UUID (PK)
  - tenant_id: UUID (FK)
  - message_id: UUID (FK)
  - field_name: String
  - field_type: ENUM (char, integer, float, boolean, many2one, date)
  - old_value: String
  - new_value: String

Entidades Principales

1. Message (Mensaje/Chatter)

Descripción: Mensaje asociado a un registro (patrón mail.thread).

Atributos:

  • id: UUID
  • author_id: Autor del mensaje (user)
  • model: Modelo del registro (ej: "SaleOrder")
  • res_id: ID del registro asociado
  • message_type: note, comment, notification, email
  • subject: Asunto
  • body: Cuerpo del mensaje (HTML)
  • parent_id: Mensaje padre (replies)
  • subtype_id: Subtipo de mensaje

Relaciones:

  • 1 Message → N Attachments
  • 1 Message → N Notifications
  • 1 Message → N TrackingValues

Patrón Odoo: mail.message Tipos:

  • note: Nota interna (solo empleados)
  • comment: Comentario (visible a followers)
  • notification: Notificación automática
  • email: Email enviado/recibido

2. Follower (Seguidor)

Descripción: Usuario que sigue un registro (recibe notificaciones).

Atributos:

  • id: UUID
  • model: Modelo del registro
  • res_id: ID del registro
  • partner_id: Partner seguidor
  • user_id: Usuario seguidor

Relaciones:

  • N Followers → 1 User/Partner

Patrón Odoo: mail.followers Auto-follow:

  • Usuario que crea registro se vuelve follower automáticamente
  • Usuario asignado (assigned_to) se vuelve follower
  • Usuario mencionado (@username) se vuelve follower

3. Notification (Notificación)

Descripción: Notificación enviada a usuario.

Atributos:

  • id: UUID
  • message_id: Mensaje asociado
  • user_id: Usuario destinatario
  • notification_type: inbox, email, push
  • is_read: Leída/No leída
  • read_at: Timestamp de lectura

Relaciones:

  • N Notifications → 1 Message
  • N Notifications → 1 User

Patrón Odoo: mail.notification Tipos:

  • inbox: Notificación in-app (campana)
  • email: Email enviado
  • push: Push notification (mobile/web)

4. Activity (Actividad Programada)

Descripción: Actividad programada (tarea, llamada, reunión).

Atributos:

  • id: UUID
  • model: Modelo del registro asociado
  • res_id: ID del registro
  • activity_type_id: Tipo de actividad
  • user_id: Usuario asignado
  • assigned_by: Usuario que asignó
  • summary: Resumen
  • note: Nota adicional
  • date_deadline: Fecha límite
  • status: pending, done, overdue, cancelled
  • completed_at: Fecha de completado

Relaciones:

  • N Activities → 1 ActivityType
  • N Activities → 1 User (asignado)

Patrón Odoo: mail.activity Estados:

  • pending: Pendiente
  • done: Completada
  • overdue: Vencida (date_deadline < HOY)
  • cancelled: Cancelada

5. ActivityType (Tipo de Actividad)

Descripción: Tipo de actividad programable.

Atributos:

  • id: UUID
  • name: Nombre (ej: "Llamada", "Reunión")
  • icon: Icono para UI
  • sequence: Orden
  • default_user_id: Usuario por defecto

Relaciones:

  • 1 ActivityType → N Activities

Patrón Odoo: mail.activity.type Tipos estándar:

  • Call (Llamada telefónica)
  • Meeting (Reunión)
  • Email (Enviar email)
  • To Do (Tarea general)

6. MessageSubtype (Subtipo de Mensaje)

Descripción: Subtipo para clasificar mensajes.

Atributos:

  • id: UUID
  • name: Nombre (ej: "Status Change", "Stage Changed")
  • description: Descripción
  • internal: Solo interno (no visible a followers externos)
  • parent_id: Subtipo padre

Relaciones:

  • 1 MessageSubtype → N Messages

Patrón Odoo: mail.message.subtype Subtipos estándar:

  • Discussions (Comentarios)
  • Note (Notas internas)
  • Status Change (Cambio de estado)
  • Stage Changed (Cambio de etapa)

7. Attachment (Adjunto)

Descripción: Archivo adjunto a mensaje o registro.

Atributos:

  • id: UUID
  • name: Nombre del archivo
  • file_path: Ruta en storage (S3 o filesystem)
  • file_size: Tamaño en bytes
  • mimetype: Tipo MIME
  • checksum: Hash SHA256
  • model: Modelo asociado
  • res_id: ID del registro

Relaciones:

  • N Attachments → 1 Message
  • N Attachments → 1 Registro (genérico)

Patrón Odoo: ir.attachment Storage: S3 o filesystem local

8. EmailTemplate (Template de Email)

Descripción: Template configurable para emails.

Atributos:

  • id: UUID
  • name: Nombre del template
  • model: Modelo asociado
  • subject: Asunto (Handlebars)
  • body_html: Cuerpo HTML (Handlebars)
  • email_from: Email remitente
  • email_to: Email destinatario (template)

Relaciones:

  • 1 EmailTemplate → N Emails enviados

Patrón Odoo: mail.template Variables disponibles:

{{user.name}}
{{company.name}}
{{order.name}}
{{order.amount_total}}

9. TrackingValue (Valor Trackeado)

Descripción: Cambio de valor en campo trackeado.

Atributos:

  • id: UUID
  • message_id: Mensaje asociado
  • field_name: Nombre del campo
  • field_type: Tipo de campo
  • old_value: Valor anterior
  • new_value: Valor nuevo

Relaciones:

  • N TrackingValues → 1 Message

Patrón Odoo: mail.tracking.value Ejemplo:

Field: status
Old: draft
New: confirmed
→ Mensaje: "User X changed Status from Draft to Confirmed"

Reglas de Negocio

RN-MSG-001: Auto-Follow

  • Usuario que crea registro → follower automático
  • Usuario asignado (assigned_to) → follower automático
  • Usuario mencionado (@username) → follower automático

RN-MSG-002: Notificaciones a Followers

  • Al crear mensaje tipo 'comment', notificar a followers
  • Al crear mensaje tipo 'note' (internal), no notificar a followers externos

RN-MSG-003: Tracking Automático

  • Decorador @TrackChanges(['status', 'amount']) en modelo
  • Al actualizar campo, generar mensaje automático con TrackingValues
  • Mensaje subtipo: "Status Change" o similar

RN-MSG-004: Actividades Vencidas

  • Sistema marca activities con status='overdue' si date_deadline < HOY
  • Enviar notificación diaria de actividades vencidas

RN-MSG-005: Email desde Templates

  • Al enviar email, reemplazar variables Handlebars
  • Variables disponibles: registro, user, company
  • Guardar email enviado como Message tipo='email'

RN-MSG-006: Notificaciones Multi-Canal

  • Usuario puede configurar preferencias:
    • inbox: Siempre
    • email: Solo para menciones
    • push: Nunca
  • Sistema respeta preferencias al crear Notification

RN-MSG-007: WebSocket Real-Time

  • Notificaciones inbox se envían por WebSocket (Socket.IO)
  • Cliente recibe notificación instantánea
  • Badge count actualizado en tiempo real

RN-MSG-008: Chatter Genérico

  • TODO modelo puede tener chatter (mixin)
  • Patrón: model + res_id + messages
  • UI consistente en todos los módulos

Casos de Uso Principales

  1. UC-MSG-001: Usuario comenta en orden de venta (chatter)
  2. UC-MSG-002: Sistema registra cambio automático (tracking)
  3. UC-MSG-003: Usuario recibe notificación in-app
  4. UC-MSG-004: Usuario recibe notificación por email
  5. UC-MSG-005: Usuario menciona a otro (@username) en comentario
  6. UC-MSG-006: Usuario programa actividad (llamada)
  7. UC-MSG-007: Sistema marca actividad como overdue
  8. UC-MSG-008: Usuario sigue orden de compra (follow)
  9. UC-MSG-009: Sistema envía email desde template
  10. UC-MSG-010: Usuario adjunta archivo en mensaje

Validaciones y Constraints

-- Message tipo válido
CHECK (message_type IN ('note', 'comment', 'notification', 'email'))

-- Activity status válido
CHECK (status IN ('pending', 'done', 'overdue', 'cancelled'))

-- Notification type válido
CHECK (notification_type IN ('inbox', 'email', 'push'))

-- Attachment file_size > 0
CHECK (file_size > 0)

-- Activity deadline no puede ser pasado al crear
-- (validación en backend)

-- Follower único por model + res_id + user_id
UNIQUE (tenant_id, model, res_id, user_id)

Índices Requeridos

CREATE INDEX idx_messages_model_res_id ON system.messages(model, res_id);
CREATE INDEX idx_messages_author_id ON system.messages(author_id);
CREATE INDEX idx_messages_message_type ON system.messages(message_type);
CREATE INDEX idx_followers_model_res_id ON system.followers(model, res_id);
CREATE INDEX idx_followers_user_id ON system.followers(user_id);
CREATE INDEX idx_notifications_user_id ON system.notifications(user_id);
CREATE INDEX idx_notifications_is_read ON system.notifications(is_read);
CREATE INDEX idx_activities_user_id ON system.activities(user_id);
CREATE INDEX idx_activities_status ON system.activities(status);
CREATE INDEX idx_activities_date_deadline ON system.activities(date_deadline);
CREATE INDEX idx_attachments_model_res_id ON system.attachments(model, res_id);
CREATE INDEX idx_tracking_values_message_id ON system.tracking_values(message_id);

Integración con Otros Módulos

Con TODOS los Módulos

  • Chatter es transversal: todos los modelos pueden tener mensajes
  • Tracking automático en modelos transaccionales
  • Actividades programables en cualquier registro

Con MGN-001 (Fundamentos)

  • Messages de User
  • Notifications a User
  • Followers son Users/Partners

Con MGN-007 (Ventas)

  • Cotizaciones con chatter
  • Tracking de cambios de status
  • Actividades de seguimiento a cliente

Con MGN-011 (Proyectos)

  • Tareas con chatter
  • Actividades por tarea
  • Followers de proyecto

Con MGN-013 (Portal)

  • Cliente ve mensajes en portal
  • Cliente puede comentar (tipo='comment')
  • Cliente NO ve mensajes internos (type='note')

Implementación Técnica

Mixin de Chatter (Backend)

// Decorador para modelos con chatter
@HasChatter()
export class SaleOrder {
  // ...campos
}

// Decorador para tracking
@TrackChanges(['status', 'amount_total', 'partner_id'])
export class SaleOrder {
  status: string;
  amount_total: number;
  partner_id: string;
}

WebSocket (Real-Time)

// Enviar notificación en tiempo real
socket.to(`user:${userId}`).emit('notification', {
  id: notification.id,
  message: notification.message,
  type: notification.type
});

Referencias


Importancia: ESENCIAL para auditoría y colaboración