Identity Service — Event Schemas
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · 04 EDA · NAMING
All events ride the platform envelope (@ghasi/event-envelope v1). NATS JetStream transport. Event type = NATS subject. Format: identity.{aggregate}.{event}.v{N}.
1. Envelope (reference)
{
"specversion": "1.0",
"id": "evt_01H...",
"type": "identity.user.registered.v1",
"source": "ghasi-ehealth/identity-service",
"subject": "usr_01H...",
"time": "2026-04-17T09:00:00.000Z",
"datacontenttype": "application/json",
"traceparent": "00-...",
"tenantid": "ten_01H...",
"data": { "...": "event specific" }
}
2. Events produced
2.1 User & session
| Event type | Subject (NATS) | Retention class | Avg. volume | Schema highlights |
|---|---|---|---|---|
identity.user.registered.v1 | identity.user.registered.v1 | 7y (audit) | low | userId, tenantId, email, locale, backend, isProvider, createdAt |
identity.user.email_verified.v1 | same | 7y | low | userId, tenantId, verifiedAt |
identity.user.suspended.v1 | same | 7y | low | userId, tenantId, reason, suspendedBy, suspendedAt |
identity.user.reactivated.v1 | same | 7y | low | userId, tenantId, reactivatedBy, reactivatedAt |
identity.user.deactivated.v1 | same | 7y | low | userId, tenantId, reason, deactivatedBy, deactivatedAt |
identity.user.password_changed.v1 | same | 7y | medium | userId, tenantId, changedBy (self|admin), changedAt |
identity.user.mfa_enrolled.v1 | same | 7y | low | userId, tenantId, factorType (totp|webauthn|recovery), factorId, enrolledAt |
identity.user.mfa_challenge_failed.v1 | same | 1y (security) | medium | userId, tenantId, factorType, reason |
identity.user.logged_in.v1 | same | 1y | high | userId, tenantId, sessionId, deviceId, backend, vendor, amr[], ip, at |
identity.session.created.v1 | same | 1y | high | sessionId, userId, tenantId, deviceId, createdAt, absoluteExpiresAt |
identity.session.revoked.v1 | same | 1y | medium | sessionId, userId, tenantId, reason (user|admin|refresh_replay|suspend), revokedAt |
Example — identity.user.suspended.v1
{
"userId": "usr_01H...",
"tenantId": "ten_01H...",
"reason": "security policy violation",
"suspendedBy": "usr_01admin...",
"suspendedAt": "2026-04-17T10:00:00Z"
}
2.2 Devices
| Event type | Retention | Highlights |
|---|---|---|
identity.device.registered.v1 | 7y | deviceId, userId, tenantId, fingerprintHash, ua, registeredAt |
identity.device.bound_for_offline.v1 | 7y | deviceId, userId, tenantId, certId, publicKey, expiresAt, boundAt |
identity.device.revoked.v1 | 7y | deviceId, userId, tenantId, reason, revokedAt |
2.3 API keys & service accounts
| Event type | Retention | Highlights |
|---|---|---|
identity.api_key.issued.v1 | 7y | apiKeyId, tenantId, userId, scopes[], issuedAt |
identity.api_key.revoked.v1 | 7y | apiKeyId, tenantId, revokedBy, revokedAt |
identity.service_account.created.v1 | 7y | serviceAccountId, clientId, tenantId?, createdBy, createdAt |
identity.service_account.revoked.v1 | 7y | serviceAccountId, clientId, revokedBy, revokedAt |
2.4 Federated identity
| Event type | Retention | Highlights |
|---|---|---|
identity.external_identity.linked.v1 | 7y | externalIdentityId, userId, tenantId, issuer, subject, linkedAt |
2.5 Licensing (merged module)
| Event type | Retention | Highlights |
|---|---|---|
identity.license.module.created.v1 | 7y | moduleId, code, name, category, dependencies[], isAlwaysOn, createdBy |
identity.license.module.updated.v1 | 7y | moduleId, code, before{...}, after{...}, updatedBy |
identity.license.assignment.created.v1 | 7y | assignmentId, moduleCode, nodeId, tenantId, scope, status, effectiveFrom, effectiveTo, assignedBy, constraints |
identity.license.assignment.status_changed.v1 | 7y | assignmentId, moduleCode, nodeId, tenantId, previousStatus, newStatus, reason, changedBy |
identity.license.assignment.constraints_updated.v1 | 7y | assignmentId, moduleCode, nodeId, tenantId, before, after, updatedBy |
identity.license.assignment.expired.v1 | 7y | assignmentId, moduleCode, nodeId, tenantId, expiredAt (effective_to) |
Example — identity.license.assignment.status_changed.v1
{
"assignmentId": "lic_01H...",
"moduleCode": "diag.laboratory",
"nodeId": "node_01H...",
"tenantId": "ten_01H...",
"previousStatus": "active",
"newStatus": "suspended",
"reason": "Payment pending",
"changedBy": "usr_superadmin_01H..."
}
3. Events consumed
| Event | Producer | Reaction |
|---|---|---|
tenant.tenant.activated.v1 | tenant-service | Provision Keycloak group bindings; enqueue Tenant Admin invite |
tenant.tenant.suspended.v1 | tenant-service | Revoke all sessions for tenant within TTL; emit session.revoked events |
tenant.tenant.terminated.v1 | tenant-service | Mark users deactivated; revoke devices; terminate all license assignments |
tenant.tenant.config.changed.v1 | tenant-service | Refresh session/MFA policy cache when relevant key changes |
tenant.user.invited.v1 | tenant-service | Create shadow user in pending_verification; send invite email |
tenant.node.created.v1 | tenant-service | Evict ancestor-chain cache for child nodes |
tenant.node.moved.v1 | tenant-service | Evict all licn:{tenantId}:*:node:* keys in affected subtree |
audit.gdpr.subject_request.received.v1 | audit-service | Participate in erasure saga |
4. Consumer reaction map (external)
| Event | Consumer | Reaction |
|---|---|---|
identity.user.suspended.v1 | tenant-service | Evict evaluation caches for user; mark memberships inactive |
identity.user.deactivated.v1 | tenant-service | Purge role assignments; emit own cascade |
identity.user.logged_in.v1 | audit-service | Append immutable audit log |
identity.device.bound_for_offline.v1 | patient-chart-service, document-service | Derive encryption keys for device |
identity.license.assignment.status_changed.v1 | Kong edge plugin | Refresh tenant module set for MODULE_NOT_ACTIVE enforcement |
identity.license.assignment.status_changed.v1 | frontend shell | Toggle navigation items on next page load |
identity.service_account.revoked.v1 | all services | Reject any active tokens from this client |
| All | audit-service | Persist to audit log |
5. Schema governance
| Control | Rule |
|---|---|
| Schema location | @ghasi/api-contracts/events/identity/*.schema.json |
| Breaking change | Forbidden on vN — introduce vN+1 with dual-publish overlap ≥ 2 releases |
| Registry | schemas published to Confluent-compat registry on CI, schema-id included in envelope header schemaId |
| Conformance tests | test/contract/*.schema.spec.ts — validate every emitted event against registered schema |
| Ordering guarantee | NATS JetStream per-subject FIFO; subject header = aggregate id for partitioning |
6. Retention classes
| Class | Retention | Applies to |
|---|---|---|
| audit-7y | 7 years | User lifecycle, licensing, service accounts, devices, external identity |
| security-1y | 1 year | Logins, MFA failures, session creations/revocations |
| ephemeral-30d | 30 days | (none currently — reserved for future identity.rate_limit_hit.v1) |