Follow a leaver from the HR transaction to a disabled Entra account. Each boundary has its own state, authority and failure modes.
HR factsIGA decisionsExternal account stateIllustrative sequence numbers · No live tenant connection
Paused · illustrative timing
Conceptual machines represent the managed Convex services, not physical server topology. On small screens, scroll the drawing sideways. Press Play to send event 129 through the system.
1 / 6 · HR records the departureExample: E-1005 → employmentStatus: terminated
The moving dot follows an event through the pipeline. Final success includes account disable and session revocation; existing access tokens may remain valid. The HR outbox retains its event after consumption. Animation speed does not represent cron timing.
Inspect the database tables and integration boundaries
01 / Source of truth
Elytra
Independent Convex deployment A Own database, backend functions and operator auth
State change and event commit together. No downstream database participates.
↓
Public HTTP API / read-only
Expose committed events
GET /api/events?since=128
Bearer secret checked by Elytra. Returns events after the cursor.
HTTPS⇄
Request ← Events →
Pull, not push
02 / Identity governance
Ascendra
Independent Convex deployment B Own database, backend functions and operator auth
Cron → Convex action / every minute
Read cursor, fetch new events
outboxCursor.lastSequence = 128 HTTP request uses the shared secret.
↓
Normalize → applyEvents mutation
Validate and materialize
Accept extra fields. Quarantine malformed events. Preserve source event time.
↓
IGA database
Convex B
identitiesHR facts + provisioning state
outboxCursorLast handled sequence → 129
auditEvents / syncEventsLocal decisions and sync results
ingestDeadLetterMalformed event + reason
integrationHealthLast poll, errors and source timing
Ingest commits local changes, cursor and scheduled work atomically. Roles, requests and certifications also live here.
↓
Scheduled action / after local commit
Resolve and provision account state
Employment + IGA decisions → desired state. This leaver: disable the Entra account.
Graph API⇄
Write → Result ←
App credentials
03 / Target directory
Microsoft Entra ID
Separate tenant · Outside Convex
Application permissions
Microsoft Graph
Client credentials authenticate Ascendra. Create, update or disable real accounts.
↓
Tenant directory
User accountaccountEnabled → false
Group membershipsGrant/revoke for mapped roles
Entra audit logDirectory-side evidence
The actual account state belongs to Entra. A local identity update is not proof of a successful Graph operation.
Response → Ascendra
Record success or failure
Sync results return to Ascendra's database. Failures stay visible for retry and investigation.
Follow an offboarding
Step through the boundaries.
1. HR records the departure
An HR operator terminates the employee. Elytra commits the employment record, lifecycle history and outbox event together.
Example: E-1005 → employmentStatus: terminated
Independent safety nets
Events tell you what changed. Reconciliation checks what is true.
Every 6 hours
Ascendra ← HR snapshots
GET /api/employees GET /api/departments
Compare current HR records with identities. Detect missing, divergent or incorrectly deprovisioned records. Deduplicate findings for review.
Detection only. No writes back to HR.Every 15 minutes
Ascendra ↔ Entra account state
Read accountEnabled through Graph. If an account should be disabled but is enabled, disable it. If an active account is unexpectedly disabled, flag it for review instead of re-enabling it.
Missing accounts are recorded. Group drift is outside this check.On poll / sync
Health, quarantine and audit
An HTTP failure is recorded in integration health. An invalid event is quarantined. Graph results are tracked separately from ingest progress.
Cursor progress ≠ successful provisioning.
Scheduled dates and other downstream work
Elytra runs a daily transition job at 02:00 UTC. Due start and end dates become actual employment transitions and produce outbox events through the same HR mutation path.
For a termination, Ascendra also schedules FinanceApp SCIM synchronization and evaluation of non-human identities owned by the departing employee. These are separate effects of the identity change; Microsoft Graph is the Entra provisioning path, while SCIM is the downstream application path.
Operator sessions authenticate each app's human users. The shared Bearer secret authenticates the HR-to-IGA HTTP integration. Ascendra's Entra client credentials authenticate its Graph calls. These are three distinct authentication boundaries.
Explore the Anatomy message-queue model
Anatomy's interactive figure illustrates the producer → buffer → consumer idea. Elytra is the producer and Ascendra is the consumer. Pause consumers in the figure to see why buffering matters.