Appearance
Agenda — Documentacion Tecnica Backend
Modulo: general Feature: Agenda (gestion de eventos, visibilidad compuesta, recurrencia, eventos de sistema) Fecha: 2026-03-31
Documento de Negocio
Nivel de Schema
Todas las tablas de la agenda viven en el schema public (LEVEL_EMPRESA).
| Razon | Detalle |
|---|---|
Usuarios en public | La tabla usuarios (view dblink) y grupos ya estan en public |
| Visibilidad cross-sucursal | Eventos con audiencia EMPRESA o SUCURSAL deben ser accesibles sin cross-schema queries |
| Agenda siempre oficial | La agenda no participa del patron dual-database; ignora el modo prueba |
| Acceso global | La agenda es una feature de general, no pertenece a ningun schema de sucursal |
Arquitectura de Capas
| Capa | Archivo (referencia) | Responsabilidad |
|---|---|---|
| Route | Routes/General/AgendaRoute.php | Endpoints REST de eventos |
| Controller | controller/modulo-general/AgendaController.php | Manejo HTTP, request/response |
| Service | service/General/AgendaService.php | Logica de negocio, resolucion de audiencia |
| Domain | Domain/Agenda/ | Reglas: visibilidad, recurrencia, idempotencia |
| Model | models/modulo-general/EventoModel.php | Acceso a datos en schema public |
| DTO | Resources/General/EventoDTO.php | Objeto de transferencia de datos |
Flujo de Peticion
Request
--> AuthMiddleware (verifica JWT, extrae usuario)
--> ConnectionMiddleware (configura conexion; schema public para agenda)
--> AgendaRoute
--> AgendaController
--> AgendaService
--> AudienciaService (resolucion de visibilidad)
--> RecurrenciaService (generacion de instancias)
--> EventoModel (acceso a datos)
--> Response (JSON)Endpoints API
GET /api/agenda/eventos
Lista los eventos visibles para el usuario autenticado, segun las reglas de audiencia.
Parametros de consulta (opcionales):
| Campo | Tipo | Descripcion |
|---|---|---|
fecha_desde | date | Inicio del rango de fechas |
fecha_hasta | date | Fin del rango de fechas |
tipo | string | Filtro por tipo: TAREA, AVISO, REUNION, SISTEMA |
estado | string | Filtro por estado: PENDIENTE, EN_PROGRESO, COMPLETADO, CANCELADO, VISTO |
prioridad | string | Filtro por prioridad: BAJA, MEDIA, ALTA, CRITICA |
origen | string | Filtro por origen: MANUAL, SISTEMA |
modulo_origen | string | Filtro por modulo de sistema (ctacte, crm, etc.) |
etiqueta | string | Filtro por etiqueta |
incluir_vistos | boolean | Incluir eventos de sistema ya vistos (default: false) |
Logica de visibilidad: el servicio resuelve la audiencia del usuario combinando:
- Eventos donde
usuario_creador_id = usuario_actual - Eventos donde existe una fila en
evento_audienciaque incluye al usuario (ver algoritmo de resolucion)
GET /api/agenda/eventos/{id}
Retorna el detalle completo de un evento, incluyendo audiencia, adjuntos y comentarios. Solo retorna el evento si el usuario tiene visibilidad sobre el.
POST /api/agenda/eventos
Crea un evento nuevo. Para eventos de tipo REUNION, fecha_fin es obligatorio. Si recurrente = true, genera las instancias futuras segun la configuracion de recurrencia.
Body:
| Campo | Tipo | Req | Descripcion |
|---|---|---|---|
titulo | string | Si | Titulo del evento |
tipo | string | Si | TAREA, AVISO, REUNION (nunca SISTEMA via este endpoint) |
prioridad | string | Si | BAJA, MEDIA, ALTA, CRITICA |
fecha_inicio | datetime | Si | Inicio |
todo_el_dia | boolean | Si | Si ocupa todo el dia |
fecha_fin | datetime | Cond | Obligatorio si tipo = REUNION |
descripcion | string | No | Texto libre |
color | string | No | Color hex (#RRGGBB) |
etiquetas | array | No | Lista de strings |
audiencia | array | No | Lista de targets (ver estructura abajo) |
recurrente | boolean | No | Si el evento se repite |
recurrencia | object | Cond | Obligatorio si recurrente = true |
entidad_schema | string | No | Schema de la entidad vinculada |
entidad_tipo | string | No | Tipo de entidad vinculada |
entidad_id | int | No | ID de la entidad vinculada |
Estructura de audiencia[]:
| Campo | Tipo | Descripcion |
|---|---|---|
tipo | string | USUARIO, GRUPO, SUCURSAL, EMPRESA |
ref_id | int | ID de usuario o grupo (null para SUCURSAL/EMPRESA) |
ref_schema | string | Schema de sucursal como filtro adicional (opcional) |
Estructura de recurrencia:
| Campo | Tipo | Descripcion |
|---|---|---|
frecuencia | string | DIARIA, SEMANAL, MENSUAL, ANUAL |
intervalo | int | Cada N unidades (default: 1) |
dias_semana | array | Enteros 0-6 (0=Dom), solo para SEMANAL |
fecha_fin | date | Hasta cuando se repite (null = indefinido) |
PUT /api/agenda/eventos/{id}
Actualiza un evento existente. Solo el creador puede ejecutar esta accion. Si se modifican campos de recurrencia, se recalculan las instancias futuras a partir de hoy.
DELETE /api/agenda/eventos/{id}
Eliminacion logica (soft delete). Solo el creador puede eliminar. Marca eliminado = true y registra fecha_eliminacion.
POST /api/agenda/eventos/{id}/visto
Marca un evento de sistema como visto para el usuario autenticado. Crea un registro en evento_lectura con leido_en = NOW(). Solo aplicable a eventos con origen = SISTEMA.
POST /api/agenda/eventos/{id}/comentarios
Agrega un comentario al evento. Disponible para cualquier usuario con visibilidad sobre el evento.
POST /api/agenda/eventos/{id}/adjuntos
Sube un archivo adjunto al evento. Solo el creador puede agregar adjuntos.
POST /api/agenda/sistema/eventos
Uso exclusivo de modulos del sistema (no expuesto al usuario). Crea un evento de tipo SISTEMA.
| Campo | Tipo | Req | Descripcion |
|---|---|---|---|
titulo | string | Si | Titulo descriptivo |
modulo_origen | string | Si | Identificador del modulo (ctacte, crm, etc.) |
prioridad | string | Si | Prioridad del evento |
accion_url | string | Si | Ruta de navegacion al origen |
entidad_schema | string | Si | Schema de la entidad (nivel sucursal o public) |
entidad_tipo | string | Si | Tipo de entidad |
entidad_id | int | Si | ID de la entidad |
audiencia | array | Si | Targets de visibilidad |
descripcion | string | No | Detalle adicional |
etiquetas | array | No | Tags para filtrado |
Este endpoint aplica la regla de idempotencia: verifica si ya existe un evento activo (no visto) para la misma tripla (modulo_origen, entidad_schema, entidad_tipo, entidad_id). Si existe, no inserta uno nuevo.
Esquema de Base de Datos
Todas las tablas pertenecen al schema public.
Tabla: eventos
| Campo | Tipo | Constraints | Descripcion |
|---|---|---|---|
id | bigint | PK, NOT NULL | Identificador unico |
titulo | varchar(255) | NOT NULL | Titulo del evento |
tipo | varchar(20) | NOT NULL | TAREA, AVISO, REUNION, SISTEMA |
estado | varchar(20) | NOT NULL, DEFAULT 'PENDIENTE' | PENDIENTE, EN_PROGRESO, COMPLETADO, CANCELADO, VISTO |
prioridad | varchar(20) | NOT NULL, DEFAULT 'MEDIA' | BAJA, MEDIA, ALTA, CRITICA |
origen | varchar(10) | NOT NULL | MANUAL, SISTEMA |
fecha_inicio | timestamp | NOT NULL | Fecha y hora de inicio |
todo_el_dia | boolean | NOT NULL, DEFAULT false | Si ocupa todo el dia |
fecha_fin | timestamp | NULL | Fin del evento; obligatorio para tipo REUNION |
descripcion | text | NULL | Texto libre descriptivo |
color | varchar(7) | NULL | Color hex (#RRGGBB) |
etiquetas | text[] | NULL | Tags libres como array de texto |
schema_contexto | varchar(50) | NULL | Schema de sucursal donde se creo el evento |
modulo_origen | varchar(50) | NULL | Modulo del sistema para eventos SISTEMA |
accion_url | varchar(500) | NULL | Ruta del frontend al origen del evento |
entidad_schema | varchar(50) | NULL | Schema de la entidad vinculada |
entidad_tipo | varchar(50) | NULL | Tipo de entidad vinculada (FACTURA, CLIENTE, etc.) |
entidad_id | bigint | NULL | ID de la entidad vinculada |
recurrencia_id | bigint | FK evento_recurrencia.id, NULL | Config de recurrencia |
evento_padre_id | bigint | FK eventos.id, NULL | Evento padre (instancia de serie recurrente) |
usuario_creador_id | int | NOT NULL, FK usuarios.id | Usuario que creo el evento |
fecha_creacion | timestamp | NOT NULL, DEFAULT NOW() | Auditoria: creacion |
fecha_modificacion | timestamp | NOT NULL, DEFAULT NOW() | Auditoria: ultima modificacion |
eliminado | boolean | NOT NULL, DEFAULT false | Soft delete |
fecha_eliminacion | timestamp | NULL | Timestamp del borrado logico |
Check constraints:
estado IN ('PENDIENTE','EN_PROGRESO','COMPLETADO','CANCELADO','VISTO')tipo IN ('TAREA','AVISO','REUNION','SISTEMA')prioridad IN ('BAJA','MEDIA','ALTA','CRITICA')origen IN ('MANUAL','SISTEMA')color ~* '^#[0-9A-F]{6}$'(cuando no es NULL)
Tabla: evento_audiencia
Cada fila representa un target de visibilidad para un evento. La union de todas las filas de un evento define quienes pueden verlo.
| Campo | Tipo | Constraints | Descripcion |
|---|---|---|---|
id | bigint | PK, NOT NULL | Identificador unico |
evento_id | bigint | NOT NULL, FK eventos.id | Evento al que pertenece |
tipo | varchar(15) | NOT NULL | USUARIO, GRUPO, SUCURSAL, EMPRESA |
ref_id | int | NULL | ID de usuario o grupo; NULL para SUCURSAL y EMPRESA |
ref_schema | varchar(50) | NULL | Schema de sucursal como filtro adicional |
Nota sobre ref_schema: cuando se combina con tipo GRUPO o USUARIO, actua como filtro AND: el evento es visible para los miembros del grupo (o el usuario) que ademas pertenezcan a la sucursal indicada. La pertenencia a una sucursal se determina comparando ref_schema con el schema del usuario en el sistema central, nivelado al nivel sucursal.
Tabla: evento_recurrencia
| Campo | Tipo | Constraints | Descripcion |
|---|---|---|---|
id | bigint | PK, NOT NULL | Identificador unico |
frecuencia | varchar(10) | NOT NULL | DIARIA, SEMANAL, MENSUAL, ANUAL |
intervalo | int | NOT NULL, DEFAULT 1 | Repetir cada N unidades |
dias_semana | int[] | NULL | Para SEMANAL: array de 0 (Dom) a 6 (Sab) |
fecha_fin | date | NULL | Hasta cuando se genera la serie; NULL = indefinido |
Tabla: evento_adjunto
| Campo | Tipo | Constraints | Descripcion |
|---|---|---|---|
id | bigint | PK, NOT NULL | Identificador unico |
evento_id | bigint | NOT NULL, FK eventos.id | Evento al que pertenece |
nombre | varchar(255) | NOT NULL | Nombre original del archivo |
ruta | varchar(500) | NOT NULL | Ruta o clave de almacenamiento |
tipo_mime | varchar(100) | NOT NULL | Tipo MIME del archivo |
fecha_creacion | timestamp | NOT NULL, DEFAULT NOW() | Auditoria |
Tabla: evento_comentario
| Campo | Tipo | Constraints | Descripcion |
|---|---|---|---|
id | bigint | PK, NOT NULL | Identificador unico |
evento_id | bigint | NOT NULL, FK eventos.id | Evento al que pertenece |
usuario_id | int | NOT NULL, FK usuarios.id | Autor del comentario |
texto | text | NOT NULL | Contenido del comentario |
fecha_creacion | timestamp | NOT NULL, DEFAULT NOW() | Auditoria |
eliminado | boolean | NOT NULL, DEFAULT false | Soft delete |
Tabla: evento_lectura
Registra cuando un usuario marco como visto un evento de sistema. Una fila por par (evento, usuario).
| Campo | Tipo | Constraints | Descripcion |
|---|---|---|---|
id | bigint | PK, NOT NULL | Identificador unico |
evento_id | bigint | NOT NULL, FK eventos.id | Evento leido |
usuario_id | int | NOT NULL, FK usuarios.id | Usuario que lo leyo |
leido_en | timestamp | NOT NULL, DEFAULT NOW() | Timestamp de la lectura |
Constraint de unicidad: UNIQUE (evento_id, usuario_id) — evita doble marcado.
Indexes
| Tabla | Columnas | Tipo | Proposito |
|---|---|---|---|
eventos | (usuario_creador_id) | B-tree | Consultas por creador |
eventos | (fecha_inicio, eliminado) | B-tree | Vista de calendario por rango de fechas |
eventos | (origen, estado, eliminado) | B-tree | Filtro de eventos activos de sistema |
eventos | (entidad_schema, entidad_tipo, entidad_id) | B-tree | Idempotencia de emisiones de sistema |
evento_audiencia | (evento_id) | B-tree | Carga de audiencia de un evento |
evento_audiencia | (tipo, ref_id) | B-tree | Busqueda inversa: eventos de un usuario o grupo |
evento_audiencia | (ref_schema) | B-tree | Busqueda por sucursal |
evento_lectura | (evento_id, usuario_id) | B-tree UNIQUE | Verificacion de lectura y constraint |
evento_lectura | (usuario_id) | B-tree | Todos los eventos leidos por un usuario |
Diagramas
ERD — Modelo de entidades
mermaid
erDiagram
eventos {
bigint id PK
varchar titulo
varchar tipo
varchar estado
varchar prioridad
varchar origen
timestamp fecha_inicio
boolean todo_el_dia
timestamp fecha_fin
text descripcion
varchar color
varchar schema_contexto
varchar modulo_origen
varchar accion_url
varchar entidad_schema
varchar entidad_tipo
bigint entidad_id
bigint recurrencia_id FK
bigint evento_padre_id FK
int usuario_creador_id FK
timestamp fecha_creacion
boolean eliminado
}
evento_audiencia {
bigint id PK
bigint evento_id FK
varchar tipo
int ref_id
varchar ref_schema
}
evento_recurrencia {
bigint id PK
varchar frecuencia
int intervalo
int[] dias_semana
date fecha_fin
}
evento_adjunto {
bigint id PK
bigint evento_id FK
varchar nombre
varchar ruta
varchar tipo_mime
}
evento_comentario {
bigint id PK
bigint evento_id FK
int usuario_id FK
text texto
timestamp fecha_creacion
}
evento_lectura {
bigint id PK
bigint evento_id FK
int usuario_id FK
timestamp leido_en
}
eventos ||--o{ evento_audiencia : "tiene audiencia"
eventos ||--o| evento_recurrencia : "configura recurrencia"
eventos ||--o{ evento_adjunto : "tiene adjuntos"
eventos ||--o{ evento_comentario : "tiene comentarios"
eventos ||--o{ evento_lectura : "registra lecturas"
eventos }o--o| eventos : "instancia de (evento_padre_id)"Diagrama de estados — Ciclo de vida del evento
mermaid
stateDiagram-v2
[*] --> PENDIENTE : Creacion
PENDIENTE --> EN_PROGRESO : Marcar en progreso (solo TAREA)
PENDIENTE --> COMPLETADO : Completar (TAREA o AVISO)
PENDIENTE --> CANCELADO : Cancelar (solo creador)
EN_PROGRESO --> COMPLETADO : Completar
EN_PROGRESO --> CANCELADO : Cancelar (solo creador)
PENDIENTE --> VISTO : Marcar como visto (solo SISTEMA)
COMPLETADO --> [*]
CANCELADO --> [*]
VISTO --> [*]
note right of VISTO : Solo para origen=SISTEMA.<br/>Estado individual por usuario.<br/>Registra en evento_lectura.
note right of COMPLETADO : El evento permanece visible<br/>con estado completado.<br/>No se elimina.Flowchart — Algoritmo de resolucion de visibilidad
Determina si el usuario U puede ver el evento E.
mermaid
flowchart TD
Start(["Usuario U consulta evento E"]) --> EsCreador{"U es el creador?"}
EsCreador -->|Si| PuedeVer(["Puede ver"])
EsCreador -->|No| EstaEliminado{"Evento eliminado?"}
EstaEliminado -->|Si| NoPuedeVer(["No puede ver"])
EstaEliminado -->|No| CargarAudiencia["Cargar filas de evento_audiencia"]
CargarAudiencia --> IterarFilas{"Para cada fila de audiencia"}
IterarFilas --> TipoEmpresa{"tipo = EMPRESA?"}
TipoEmpresa -->|Si| PuedeVer
TipoEmpresa -->|No| TipoSucursal{"tipo = SUCURSAL?"}
TipoSucursal -->|Si| CheckSchema{"ref_schema =<br/>schema_sucursal(U)?"}
CheckSchema -->|Si| PuedeVer
CheckSchema -->|No| SiguienteFila["Siguiente fila"]
TipoSucursal -->|No| TipoGrupo{"tipo = GRUPO?"}
TipoGrupo -->|Si| CheckGrupo{"U es miembro<br/>del grupo ref_id?"}
CheckGrupo -->|No| SiguienteFila
CheckGrupo -->|Si| TieneRefSchema{"ref_schema<br/>definido?"}
TieneRefSchema -->|No| PuedeVer
TieneRefSchema -->|Si| CheckSchemaGrupo{"ref_schema =<br/>schema_sucursal(U)?"}
CheckSchemaGrupo -->|Si| PuedeVer
CheckSchemaGrupo -->|No| SiguienteFila
TipoGrupo -->|No| TipoUsuario{"tipo = USUARIO?"}
TipoUsuario -->|Si| CheckUsuario{"ref_id = U.id?"}
CheckUsuario -->|No| SiguienteFila
CheckUsuario -->|Si| TieneRefSchemaU{"ref_schema<br/>definido?"}
TieneRefSchemaU -->|No| PuedeVer
TieneRefSchemaU -->|Si| CheckSchemaUsuario{"ref_schema =<br/>schema_sucursal(U)?"}
CheckSchemaUsuario -->|Si| PuedeVer
CheckSchemaUsuario -->|No| SiguienteFila
TipoUsuario -->|No| SiguienteFila
SiguienteFila --> MasFilas{"Hay mas filas?"}
MasFilas -->|Si| IterarFilas
MasFilas -->|No| NoPuedeVerSecuencia — Creacion de evento manual con recurrencia
mermaid
sequenceDiagram
participant U as Usuario
participant API as AgendaController
participant S as AgendaService
participant RS as RecurrenciaService
participant M as EventoModel
participant DB as public schema
U->>API: POST /api/agenda/eventos
API->>S: crearEvento(DTO, usuarioId)
S->>S: validar tipo y campos requeridos
S->>S: verificar fecha_fin si tipo=REUNION
alt recurrente = true
S->>RS: generarInstancias(recurrenciaConfig, fechaInicio)
RS-->>S: lista de fechas de instancias
end
S->>M: insertarEvento(datos)
M->>DB: INSERT INTO eventos
DB-->>M: id del evento creado
S->>M: insertarAudiencia(eventoId, audienciaDTO[])
M->>DB: INSERT INTO evento_audiencia (N filas)
alt recurrente = true
loop Para cada instancia futura
S->>M: insertarInstancia(fechaInstancia, eventoId)
M->>DB: INSERT INTO eventos (evento_padre_id = eventoId)
end
end
S-->>API: EventoDTO
API-->>U: 201 CreatedSecuencia — Emision de evento de sistema desde un modulo
mermaid
sequenceDiagram
participant MOD as Modulo del sistema
participant AS as AgendaService
participant M as EventoModel
participant AM as AudienciaModel
participant DB as public schema
MOD->>AS: emitirEventoSistema(payload)
AS->>M: buscarEventoActivoSistema(modulo, entidadSchema, entidadTipo, entidadId)
M->>DB: SELECT FROM eventos WHERE origen=SISTEMA AND eliminado=false...
DB-->>M: resultado
alt Evento activo ya existe (idempotencia)
AS-->>MOD: EventoDTO existente (sin insertar)
else No existe evento activo
AS->>M: insertarEvento(datosEvento)
M->>DB: INSERT INTO eventos (origen=SISTEMA)
DB-->>M: id del evento creado
AS->>AM: resolverAudiencia(audienciaConfig)
AM->>DB: INSERT INTO evento_audiencia (N filas)
AS-->>MOD: EventoDTO creado
endSecuencia — Marcado de lectura de evento de sistema
mermaid
sequenceDiagram
participant U as Usuario
participant API as AgendaController
participant S as AgendaService
participant M as EventoModel
participant LM as LecturaModel
participant DB as public schema
U->>API: POST /api/agenda/eventos/{id}/visto
API->>S: marcarComoVisto(eventoId, usuarioId)
S->>M: obtenerEvento(eventoId)
M->>DB: SELECT FROM eventos WHERE id = ?
DB-->>M: evento
alt Evento no existe o no visible para el usuario
S-->>API: 404 Not Found
API-->>U: 404
else Evento no es de origen SISTEMA
S-->>API: 422 Unprocessable
API-->>U: 422 Solo eventos de sistema pueden marcarse como vistos
else Evento de sistema, usuario tiene visibilidad
S->>LM: registrarLectura(eventoId, usuarioId)
LM->>DB: INSERT INTO evento_lectura ON CONFLICT DO NOTHING
DB-->>LM: ok
S-->>API: ok
API-->>U: 200 OK
endAlgoritmo de Generacion de Instancias (Recurrencia)
El RecurrenciaService genera las fechas de instancias futuras en memoria y delega la insercion al EventoModel.
| Frecuencia | Logica de generacion |
|---|---|
| DIARIA | fecha_inicio + (n * intervalo) dias, donde n = 1, 2, 3, ... |
| SEMANAL | Siguiente ocurrencia de los dias_semana seleccionados, avanzando intervalo semanas |
| MENSUAL | Mismo dia del mes que fecha_inicio, avanzando intervalo meses |
| ANUAL | Mismo dia y mes que fecha_inicio, avanzando intervalo años |
Limites de generacion:
- Si
fecha_finesta definida: se generan instancias hasta esa fecha inclusive - Si
fecha_fines NULL: se generan instancias para los proximos 2 anos como horizonte operativo; el scheduler puede extender el horizonte periodicamente
Resolucion del Schema de Sucursal de un Usuario
Para comparar ref_schema de la audiencia con el schema al que pertenece un usuario, el sistema usa la siguiente logica de normalizacion:
schema_asignado_usuario: "suc0001caja001"
--> extraer nivel sucursal
--> resultado: "suc0001"
schema_asignado_usuario: "suc0001"
--> ya es nivel sucursal
--> resultado: "suc0001"
schema_asignado_usuario: "public"
--> empresa sin sucursales
--> resultado: "public"La funcion equivalente ya existe en el backend como ConnectionUtils::extractSucursalSchema().
Validaciones
Validacion estructural (Validator / Middleware)
| Campo | Regla |
|---|---|
titulo | Requerido, string, max 255 caracteres |
tipo | Requerido, enum: TAREA, AVISO, REUNION |
prioridad | Requerido, enum: BAJA, MEDIA, ALTA, CRITICA |
fecha_inicio | Requerido, datetime valido |
todo_el_dia | Requerido, boolean |
color | Opcional, regex ^#[0-9A-Fa-f]{6}$ |
audiencia[].tipo | Enum: USUARIO, GRUPO, SUCURSAL, EMPRESA |
recurrencia.frecuencia | Enum: DIARIA, SEMANAL, MENSUAL, ANUAL |
recurrencia.intervalo | Entero positivo mayor a 0 |
recurrencia.dias_semana[] | Enteros 0-6 (solo si frecuencia = SEMANAL) |
Validacion de negocio (Service / Domain)
| Regla | Detalle |
|---|---|
| Fecha de fin obligatoria para REUNION | Si tipo = REUNION y fecha_fin es NULL, rechazar con 422 |
| Fecha de fin posterior a fecha de inicio | fecha_fin > fecha_inicio cuando ambas estan presentes |
| Solo el creador edita y elimina | Verificar usuario_creador_id = usuario_actual; rechazar con 403 si no coincide |
tipo = SISTEMA no permitido via POST manual | El endpoint POST /eventos no acepta tipo = SISTEMA; ese tipo es exclusivo del endpoint interno |
| Idempotencia de eventos de sistema | Verificar existencia de evento activo por (modulo_origen, entidad_schema, entidad_tipo, entidad_id) antes de insertar |
| Referencia polimórfica nunca a nivel caja | Si entidad_schema tiene formato sucXXXXcajaXXXX, normalizarlo a sucXXXX |
marcado como visto solo para SISTEMA | Si origen != SISTEMA, rechazar la operacion con 422 |
Puntos de Integracion
| Modulo | Integracion | Descripcion |
|---|---|---|
Usuarios (public) | Lectura | usuario_creador_id y usuario_id en comentarios/lecturas referencian la view usuarios |
Grupos (public) | Lectura | ref_id en audiencia con tipo = GRUPO referencia la tabla grupos |
| CtaCte | Emisor | Llama al endpoint interno para emitir eventos de vencimiento |
| CRM | Emisor | Llama al endpoint interno para emitir recordatorios de seguimiento |
| Membresias | Emisor | Llama al endpoint interno para emitir vencimientos de membresía |
| Compras | Emisor | Llama al endpoint interno para emitir vencimientos de facturas de proveedor |
| Stock | Emisor | Llama al endpoint interno para emitir alertas de stock minimo |
| Tesoreria | Emisor | Llama al endpoint interno para emitir vencimientos de cheques |
| ConnectionUtils | Util | extractSucursalSchema() para normalizar el schema de usuario al comparar con ref_schema |
Consideraciones de Performance
| Caso | Estrategia |
|---|---|
| Carga del calendario por rango de fechas | Index compuesto (fecha_inicio, eliminado) cubre el filtro principal |
| Resolucion de visibilidad por usuario | Join con evento_audiencia filtrado por tipo y ref_id; usar IN con los grupos del usuario |
| Eventos de sistema no vistos | Index (origen, estado, eliminado) para filtrar rapidamente eventos SISTEMA pendientes |
| Idempotencia en emision masiva | Index unico sobre (modulo_origen, entidad_schema, entidad_tipo, entidad_id) |
| Instancias de eventos recurrentes a futuro | Generacion por horizonte de 2 anos; evitar generar instancias infinitas en memoria |
Seguridad y Auditoria
| Aspecto | Implementacion |
|---|---|
| Acceso | Solo usuarios autenticados (JWT). La agenda siempre usa la conexion oficial |
| Visibilidad | El servicio filtra activamente los eventos por audiencia; nunca retorna eventos fuera del alcance del usuario |
| Modificacion | Verificacion de usuario_creador_id en toda operacion de escritura sobre eventos MANUAL |
| Soft delete | Los eventos no se eliminan fisicamente; eliminado = true con fecha_eliminacion |
| Auditoria | fecha_creacion y fecha_modificacion en eventos; fecha_creacion en comentarios y adjuntos; leido_en en lecturas |
| Modo prueba | La agenda no participa del patron dual-database; la conexion siempre apunta a bautista (oficial), aunque el contexto general del request este en modo prueba |