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

156 lines
6.5 KiB
Markdown

# 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
```json
{
"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 |