gh_UserManager/docs/EVENTS.md
bermooda-company 54d5891edf user
2026-08-23 23:59:14 +03:30

6.5 KiB

Events

Overview

The Identity Platform uses an event-driven architecture built on Redis Streams. Events decouple the platform from products and enable reliable, scalable, idempotent communication.

Each event is published to a Redis stream and includes:

  • event_type: A namespaced identifier (e.g., user.created, authentication.login)
  • event_id: A UUID that uniquely identifies THIS event occurrence
  • correlation_id: A UUID that ties this event to a request chain (e.g., a login request may trigger user.updated, session.created, authentication.login_success)
  • timestamp: ISO 8601 UTC
  • version: Schema version of this event (semver: 1.0.0)
  • data: Event-specific payload (product-agnostic)
  • metadata: Correlation info, source, IP, etc.

Event Structure

{
  "event_id": "uuid",
  "correlation_id": "uuid",
  "event_type": "user.created",
  "version": "1.0.0",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "source": "identity-platform",
  "data": {
    "user_id": "uuid",
    "email": "user@acme.com"
  },
  "metadata": {
    "ip": "192.168.1.1",
    "user_agent": "Mozilla/5.0...",
    "request_id": "uuid"
  }
}

Event Types

User Events

Event Type Version Trigger Data
user.created 1.0.0 New user registered user_id, email, phone, created_at
user.updated 1.0.0 User profile updated user_id, changed_fields[], updated_at
user.deleted 1.0.0 User deleted (GDPR) user_id, deleted_at
user.disabled 1.0.0 User status → suspended/banned user_id, status, reason
user.verified 1.0.0 Email/phone verified user_id, channel (email/phone), verified_at

Organization Events

Event Type Version Trigger Data
organization.created 1.0.0 New org created org_id, name, created_by
organization.updated 1.0.0 Org details updated org_id, changed_fields[], updated_at

Membership Events

Event Type Version Trigger Data
membership.created 1.0.0 User added to org user_id, org_id, role, status
membership.updated 1.0.0 Role/status changed user_id, org_id, changed_fields[]
membership.removed 1.0.0 User removed from org user_id, org_id, removed_by

Authentication Events

Event Type Version Trigger Data
authentication.login 1.0.0 Successful login user_id, session_id, product_key, ip, device
authentication.logout 1.0.0 Successful logout user_id, session_id, product_key
authentication.failed 1.0.0 Failed login attempt user_id (if known), email, ip, reason
authentication.mfa_required 1.0.0 MFA step reached user_id, method
authentication.mfa_verified 1.0.0 MFA passed user_id, method

Session Events

Event Type Version Trigger Data
session.created 1.0.0 New session session_id, user_id, product_key, session_type
session.expired 1.0.0 Session timed out session_id, user_id, reason
session.revoked 1.0.0 Session revoked session_id, user_id, product_key, reason

Security Events

Event Type Version Trigger Data
security.event 1.0.0 Any security event logged event_type, severity, user_id, ip, user_agent
security.token_revoked 1.0.0 Token blacklisted user_id, token_type, reason

Event Properties

idempotency

Every event has a unique event_id (UUID). Consumers must deduplicate by event_id. This allows safe retry of failed deliveries without duplicate processing.

correlation

Events triggered by the same request share a correlation_id. Example:

correlation_id: req_abc123
  ↓ triggers
  event: user.created (user_id=123)
  event: session.created (user_id=123, session_id=456)
  event: authentication.login (user_id=123, session_id=456)

versioning

Event payloads are versioned with semver. When the schema changes in a backward-compatible way (adding optional fields), the version increments the PATCH. Breaking changes (removing fields, changing types) increment MAJOR. Consumers MUST check version before processing.

Delivery Guarantees

Guarantee Mechanism
At-least-once Redis Streams with consumer groups
Deduplication event_id uniqueness
Ordering Per-stream ordering preserved
Durability Redis AOF persistence
Retry Consumer must ACK (XACK); unacked claimed by other consumers
DLQ Failed messages (max retries exceeded) routed to events.dlq.stream

Consumer Contract

Products consuming events MUST:

  1. Use consumer groups per product + service combination
  2. Acknowledge (XACK) every processed message
  3. Idempotently handle duplicates via event_id
  4. Validate version before processing (reject unknown MAJOR versions)
  5. Route failed messages to DLQ after max retries
  6. Preserve correlation_id across their own downstream events

Internal vs External Events

Channel Audience Persistence Delivery
SecurityEvent (DB table) Internal admin/audit Permanent (2 years) Queryable via API
Redis Streams Products + internal services 7 days Consumer group
Audit log (SecurityEvent) Compliance Permanent Archive

The SecurityEvent model in PostgreSQL is the internal audit log. These are NOT the same as Redis Stream events but are correlated:

User logs in
  → SecurityEvent (DB: login_success, severity=info)  [audit trail]
  → Redis Stream event (user.created, authentication.login)  [product notifications]

Stream Names

Stream Events
events.user user.created, user.updated, user.deleted, user.disabled, user.verified
events.organization organization.created, organization.updated
events.membership membership.created, membership.updated, membership.removed
events.authentication authentication.login, authentication.logout, authentication.failed
events.session session.created, session.expired, session.revoked
events.security security.event, security.token_revoked
events.dlq Dead-letter queue for failed deliveries