El sistema implementa un microservicio dedicado para cumplimiento normativo y trazabilidad completa, utilizando GraphQL como interfaz principal y Worker Threads para procesamiento paralelo de eventos.
graph TD
%% 1. Definición de Nodos (la estructura del diagrama)
A["Todos los Microservicios
(Emisores de Eventos)"]
B["KAFKA EVENT BUS
Topic: audit.events"]
C["MS-Auditoría
(GraphQL API)
Worker Pool (4 workers)
- Event Processing
- Log Enrichment
- Compliance Checks
- Anomaly Detection"]
D["Elasticsearch
(Event Store)
- Full-text
- Aggregations
- 7 años"]
E["Prometheus
(Métricas)
- Counters
- Histograms
- Alerts"]
F["PostgreSQL
(Audit Records)
- Structured
- Compliance
- 10 años"]
G["Kibana
(Explorador)
(Compliance)"]
H["Grafana
(Dashboards)
(Métricas)"]
%% 2. Definición de Conexiones (las flechas)
A -- "Emit Events" --> B
B -- "Consume" --> C
C --> D
C --> E
C --> F
D --> G
E --> H
%% 3. Definición de Estilos (colores, bordes, etc.)
%% Nivel 1: Emisores
classDef level1 fill:#EBF5FB,stroke:#85C1E9,stroke-width:2px,rx:10,ry:10,color:#333
%% Nivel 2: Bus de Eventos
classDef level2 fill:#E8F8F5,stroke:#76D7C4,stroke-width:2px,rx:10,ry:10,color:#333
%% Nivel 3: Consumidor Principal
classDef level3 fill:#FEF9E7,stroke:#FAD7A0,stroke-width:2px,rx:10,ry:10,color:#333
%% Nivel 4: Almacenamiento y Métricas
classDef level4 fill:#F4ECF7,stroke:#D7BDE2,stroke-width:2px,rx:10,ry:10,color:#333
%% Nivel 5: Visualización
classDef level5 fill:#FDEDEC,stroke:#F5B7B1,stroke-width:2px,rx:10,ry:10,color:#333
%% 4. Asignación de Estilos a los Nodos
class A level1
class B level2
class C level3
class D,E,F level4
class G,H level5
# Tipo principal de evento de auditoría
type AuditEvent {
id: ID!
timestamp: DateTime!
userId: String!
action: AuditAction!
resource: String!
resourceId: String
metadata: JSON!
ipAddress: String!
userAgent: String
result: AuditResult!
severity: AuditSeverity!
riskScore: Int
geoLocation: GeoLocation
}
# Enumeraciones para tipo de acción
enum AuditAction {
LOGIN
LOGOUT
LOGIN_FAILED
TRANSFER_CREATED
TRANSFER_APPROVED
TRANSFER_REJECTED
ACCOUNT_ACCESSED
PASSWORD_CHANGED
PROFILE_UPDATED
DOCUMENT_UPLOADED
DOCUMENT_DOWNLOADED
ADMIN_ACTION
SETTINGS_CHANGED
API_KEY_GENERATED
}
# Resultado de la operación
enum AuditResult {
SUCCESS
FAILURE
PARTIAL
PENDING
}
# Severidad del evento
enum AuditSeverity {
INFO
WARNING
CRITICAL
}
# Información geográfica
type GeoLocation {
country: String
city: String
latitude: Float
longitude: Float
}
# Estadísticas agregadas
type AuditStatistics {
totalEvents: Int!
successRate: Float!
failuresByAction: [ActionCount!]!
eventsByHour: [HourlyCount!]!
topUsers: [UserActivity!]!
criticalEventsCount: Int!
averageRiskScore: Float!
}
type ActionCount {
action: AuditAction!
count: Int!
failureRate: Float!
}
type HourlyCount {
hour: DateTime!
count: Int!
suspiciousActivity: Boolean!
}
type UserActivity {
userId: String!
eventCount: Int!
riskScore: Float!
lastActivity: DateTime!
}
# Queries
type Query {
# Búsqueda flexible de eventos
auditEvents(
startDate: DateTime!
endDate: DateTime!
userId: String
actions: [AuditAction!]
severity: AuditSeverity
minRiskScore: Int
limit: Int = 100
offset: Int = 0
): [AuditEvent!]!
# Estadísticas agregadas
auditStatistics(
startDate: DateTime!
endDate: DateTime!
groupBy: StatGrouping
): AuditStatistics!
# Búsqueda por texto completo
searchAuditLogs(
query: String!
limit: Int = 50
): [AuditEvent!]!
# Análisis de riesgo de usuario
userRiskAnalysis(
userId: String!
days: Int = 30
): UserRiskProfile!
}
# Subscriptions para tiempo real
type Subscription {
# Eventos críticos en tiempo real
criticalEvents: AuditEvent!
# Eventos por usuario específico
userEvents(userId: String!): AuditEvent!
# Eventos por tipo de acción
actionEvents(action: AuditAction!): AuditEvent!
}
# Dashboard de compliance para último mes
query ComplianceDashboard {
# Estadísticas generales
stats: auditStatistics(
startDate: "2025-09-06T00:00:00Z"
endDate: "2025-10-06T00:00:00Z"
groupBy: ACTION
) {
totalEvents
successRate
criticalEventsCount
averageRiskScore
failuresByAction {
action
count
failureRate
}
eventsByHour {
hour
count
suspiciousActivity
}
topUsers {
userId
eventCount
riskScore
lastActivity
}
}
# Eventos críticos del último mes
criticalTransfers: auditEvents(
startDate: "2025-09-06T00:00:00Z"
endDate: "2025-10-06T00:00:00Z"
actions: [TRANSFER_CREATED]
severity: CRITICAL
minRiskScore: 50
) {
id
timestamp
userId
metadata
result
riskScore
geoLocation {
country
city
}
}
# Análisis de riesgo de usuarios sospechosos
suspiciousUsers: auditEvents(
startDate: "2025-09-06T00:00:00Z"
endDate: "2025-10-06T00:00:00Z"
minRiskScore: 70
) {
userId
action
riskScore
timestamp
ipAddress
}
}
Los eventos de auditoría se procesan en paralelo utilizando Worker Threads de Node.js para:
flowchart LR
%% 1. Definición de Nodos con Iconos
main["fa:fa-sitemap MS-Auditoría - Main Thread
- Coordina y consume
- Responde a GraphQL"]
subgraph "⚙️ Worker Pool"
direction TB
w1["Worker1: GeoIP Lookup"]
w2["Worker2: Risk Scoring"]
w3["Worker3: Anomaly Detection"]
w4["Worker4: Compliance Checks"]
end
db["fa:fa-database Almacenamiento
Elasticsearch
+ PostgreSQL"]
%% 2. Conexiones con diferentes estilos
main -.->|Delega Tarea| w1
main -.->|Delega Tarea| w2
main -.->|Delega Tarea| w3
main -.->|Delega Tarea| w4
w1 & w2 & w3 & w4 -- "Eventos Enriquecidos" --> db
%% 3. Estilos
classDef level1 fill:#EBF5FB,stroke:#85C1E9,stroke-width:2px,rx:10,ry:10
classDef level2 fill:#F4ECF7,stroke:#D7BDE2,stroke-width:2px,rx:10,ry:10
classDef level3 fill:#FEF9E7,stroke:#FAD7A0,stroke-width:2px,rx:10,ry:10
%% 4. Asignación de Estilos
class main level1
class w1,w2,w3,w4 level2
class db level3
| Métrica | Sin Workers | Con 4 Workers | Mejora |
|---|---|---|---|
| Eventos procesados/segundo | 800 | 3,200 | ↑ 300% |
| Latencia promedio | 45ms | 12ms | ↑ 73% |
| CPU utilizada | 25% (1 core) | 85% (4 cores) | Óptimo |
| Throughput total | 2,880 eventos/hora | 11,520 eventos/hora | ↑ 300% |
Cada evento pasa por el siguiente proceso de enriquecimiento en workers:
// Ejemplo de enriquecimiento en Worker
function enrichEvent(event) {
return {
...event,
// GeoIP Lookup (CPU-intensive)
geoLocation: lookupGeoIP(event.ipAddress),
// Risk Scoring (cálculo complejo)
riskScore: calculateRiskScore({
action: event.action,
time: event.timestamp,
location: geoLocation,
userHistory: getUserHistory(event.userId)
}),
// Anomaly Detection (ML model)
isAnomaly: detectAnomaly(event, userBehaviorProfile),
// Compliance Flags
complianceFlags: checkComplianceRules(event)
};
}
Las subscriptions de GraphQL permiten monitoreo en tiempo real de eventos críticos vía WebSocket.
// GraphQL Resolver para Subscriptions
const { PubSub } = require('graphql-subscriptions');
const pubsub = new PubSub();
// Kafka consumer publica a GraphQL subscription
kafka.consumer.on('message', (message) => {
const event = JSON.parse(message.value);
// Procesar en worker thread
workerPool.process(event).then(enrichedEvent => {
// Publicar eventos críticos
if (enrichedEvent.severity === 'CRITICAL') {
pubsub.publish('CRITICAL_EVENT', {
criticalEvents: enrichedEvent
});
}
// Publicar eventos por usuario
pubsub.publish(`USER_EVENT_${enrichedEvent.userId}`, {
userEvents: enrichedEvent
});
// Publicar eventos por acción
pubsub.publish(`ACTION_${enrichedEvent.action}`, {
actionEvents: enrichedEvent
});
});
});
// Resolvers
const resolvers = {
Subscription: {
criticalEvents: {
subscribe: () => pubsub.asyncIterator(['CRITICAL_EVENT'])
},
userEvents: {
subscribe: (_, { userId }) =>
pubsub.asyncIterator([`USER_EVENT_${userId}`])
},
actionEvents: {
subscribe: (_, { action }) =>
pubsub.asyncIterator([`ACTION_${action}`])
}
}
};
// React component con GraphQL Subscription
import { useSubscription } from '@apollo/client';
const CRITICAL_EVENTS_SUBSCRIPTION = gql`
subscription OnCriticalEvent {
criticalEvents {
id
timestamp
userId
action
severity
riskScore
metadata
}
}
`;
function ComplianceDashboard() {
const { data, loading } = useSubscription(
CRITICAL_EVENTS_SUBSCRIPTION
);
useEffect(() => {
if (data?.criticalEvents) {
// Mostrar alerta en tiempo real
showAlert(data.criticalEvents);
// Reproducir sonido de alerta
playAlertSound();
}
}, [data]);
return (
<div>
{data?.criticalEvents && (
<Alert severity="error">
Evento Crítico Detectado: {data.criticalEvents.action}
</Alert>
)}
</div>
);
}
| Tipo de Dato | Retención | Storage | Justificación Normativa |
|---|---|---|---|
| Logs de aplicación | 90 días | Elasticsearch (hot) | Operación diaria, debugging |
| Eventos de auditoría | 7 años | Elasticsearch + S3 | PCI DSS Requirement 10.7, GLBA |
| Transacciones financieras | 10 años | PostgreSQL + S3 Glacier | Normativas bancarias locales |
| Datos de acceso (login) | 2 años | Elasticsearch | ISO 27001, GDPR Art. 32 |
| Métricas Prometheus | 30 días | Prometheus TSDB | Análisis de tendencias |
| Eventos críticos | 10 años | PostgreSQL + S3 | Compliance y legal |
flowchart TD
subgraph "Ciclo de Vida del Dato"
direction LR
tier_hot_data("Días 0-30"):::level_hot
hot_es["fa:fa-fire Elasticsearch Hot
SSD | <50ms | Alto Costo
Consultas Frecuentes, Dashboards"]:::level_hot_data
tier_warm_data("Días 31-365"):::level_warm
warm_es["fa:fa-thermometer-half Elasticsearch Warm
HDD | <200ms | Medio Costo
Consultas Ocasionales, Reportes Mensuales"]:::level_warm_data
tier_s3_standard_data("Años 1-3"):::level_cold
s3_standard["fa:fa-snowflake Amazon S3 Standard
Blob | Minutos Restore | Costo Medio
Auditorías Anuales"]:::level_cold_data
tier_glacier_data("Años 3-7"):::level_frozen
s3_glacier["fa:fa-ice-cream Amazon S3 Glacier
Archival | 3-5h Restore | Bajo Costo
Solo Compliance"]:::level_frozen_data
tier_deep_archive_data("Años 7-10"):::level_archive
s3_deep_archive["fa:fa-box-open S3 Glacier Deep Archive
Deep Archival | 12-48h Restore | Mínimo Costo
Legal / Auditorías Externas"]:::level_archive_data
end
%% Conexiones y transiciones
tier_hot_data --> hot_es
hot_es -- "Después de 30 días" --> tier_warm_data
tier_warm_data --> warm_es
warm_es -- "Después de 365 días" --> tier_s3_standard_data
tier_s3_standard_data --> s3_standard
s3_standard -- "Después de 3 años" --> tier_glacier_data
tier_glacier_data --> s3_glacier
s3_glacier -- "Después de 7 años" --> tier_deep_archive_data
tier_deep_archive_data --> s3_deep_archive
%% Estilos de los nodos
classDef level_hot fill:#EBF5FB,stroke:#85C1E9,stroke-width:2px,rx:8,ry:8,color:#222;
classDef level_warm fill:#E8F8F5,stroke:#76D7C4,stroke-width:2px,rx:8,ry:8,color:#222;
classDef level_cold fill:#FEF9E7,stroke:#FAD7A0,stroke-width:2px,rx:8,ry:8,color:#222;
classDef level_frozen fill:#F4ECF7,stroke:#D7BDE2,stroke-width:2px,rx:8,ry:8,color:#222;
classDef level_archive fill:#FDEDEC,stroke:#F5B7B1,stroke-width:2px,rx:8,ry:8,color:#222;
%% Estilos de los nodos de datos (más prominentes)
classDef level_hot_data fill:#D6EEF9,stroke:#5DA6D9,stroke-width:3px,rx:12,ry:12,color:#111,font-size:14px;
classDef level_warm_data fill:#D2F3EE,stroke:#4DC4AC,stroke-width:3px,rx:12,ry:12,color:#111,font-size:14px;
classDef level_cold_data fill:#FCF3DA,stroke:#E9B87F,stroke-width:3px,rx:12,ry:12,color:#111,font-size:14px;
classDef level_frozen_data fill:#EAD7EE,stroke:#C08BD1,stroke-width:3px,rx:12,ry:12,color:#111,font-size:14px;
classDef level_archive_data fill:#FBCAC8,stroke:#ED8581,stroke-width:3px,rx:12,ry:12,color:#111,font-size:14px;
| Dashboard | Usuario | Contenido |
|---|---|---|
| Security Overview | CISO, Security Team | Eventos críticos, intentos de acceso fallidos, anomalías detectadas |
| Compliance Report | Compliance Officer | Cobertura de auditoría, eventos por normativa, gaps detectados |
| Operations Monitor | DevOps, SRE | Performance del sistema, errores, latencias, uptime |
| User Activity | Fraud Team | Actividad por usuario, patrones sospechosos, risk scores |
| Transaction Audit | Finance Team | Transacciones por tipo, montos, tendencias, reconciliación |
| Alerta | Condición | Severidad | Acción |
|---|---|---|---|
| Login desde país desconocido | GeoLocation no en lista blanca | CRITICAL | PagerDuty + Bloqueo temporal |
| Múltiples logins fallidos | >5 intentos en 5 minutos | WARNING | Email + Captcha activado |
| Transferencia de alto monto | Monto > $50,000 | INFO | Notificación a compliance |
| Anomalía detectada | Risk score > 80 | CRITICAL | PagerDuty + Revisión manual |
| Acceso admin fuera de horario | Login admin 10pm-6am | WARNING | Slack + Email al CISO |