Events
:::info Source
Sourced from services/sync-service/EVENT_SCHEMAS.md in the documentation repo.
:::
1. Envelope
Standard. retentionClass = operational (30 days hot; no long-term archive for sync operational events).
2. Events Published
2.1 sync.mutation.applied.v1
interface MutationAppliedV1 { clientMutationId: string; tenantId: TenantId; userId: UserId; deviceId: DeviceId; service: string; entityType: string; entityId: string; op: string; appliedAt: ISODate; }
2.2 sync.mutation.conflicted.v1
interface MutationConflictedV1 { clientMutationId: string; conflictId: ULID; tenantId: TenantId; userId: UserId; entityType: string; entityId: string; conflictPolicy: string; baseVersion: number; serverVersion: number; conflictedAt: ISODate; }
2.3 sync.mutation.rejected.v1
interface MutationRejectedV1 { clientMutationId: string; tenantId: TenantId; userId: UserId; entityType: string; entityId: string; reason: string; rejectedAt: ISODate; }
2.4 sync.delta.projected.v1
interface DeltaProjectedV1 { scope: string; tenantId: TenantId; newLamport: number; entityCount: number; projectedAt: ISODate; }
2.5 sync.conflict.resolved.v1
interface ConflictResolvedV1 { conflictId: ULID; tenantId: TenantId; userId: UserId; entityType: string; resolution: string; resolvedBy?: UserId; resolvedAt: ISODate; }
2.6 sync.push.applied.v1 (outbox)
Emitted alongside sync.mutation.applied.v1 on successful push apply (backlog / analytics alias; see SyncEvents.PUSH_APPLIED in implementation).
interface PushAppliedV1 { clientMutationId: string; tenantId: TenantId; userId: UserId; deviceId: DeviceId; appliedAt: ISODate; }
2.7 sync.pull.completed.v1
One emission per completed pull projection (EP-20 / US-100).
interface PullCompletedV1 { tenantId: TenantId; userId: UserId; deviceId: DeviceId; scope: string; lamport: number; deltaCount: number; completedAt: ISODate; }
2.8 sync.device.wiped.v1
Remote wipe recorded; consumer devices must evict and stop sync until re-bound.
interface DeviceWipedV1 { tenantId: TenantId; userId: UserId; deviceId: DeviceId; wipeRequestId: ULID; wipedAt: ISODate; }
2.9 content.play_package.bundle.revoked.v1
Published by content flows; sync-service re-emits on admin revoke path when recording revoked_bundles for pull (EP-17 / EP-20 alignment).
interface BundleRevokedV1 { tenantId: TenantId; bundleId: string; licenseId: string; revokedAt: ISODate; reason?: string; }
2.10 identity.device.removed.v1
Emitted when a device row is removed after wipe (may originate from sync-service outbox in coordinated wipe flow; identity-service remains owner of identity events).
interface DeviceRemovedV1 { tenantId: TenantId; userId: UserId; deviceId: DeviceId; removedAt: ISODate; }
2.11 sync.full_resync.initiated.v1
interface FullResyncInitiatedV1 { tenantId: TenantId; userId: UserId; deviceId: DeviceId; scope: string; reason: 'cursor_out_of_range' | 'admin_force' | 'device_rebound'; initiatedAt: ISODate; }
3. Events Consumed (ALL replicable domain events)
enrollment.created.v1,.completed.v1,.revoked.v1— project enrollment deltas.progress.statement.stored.v1,.attempt.closed.v1,.completion.recorded.v1— project progress deltas.certification.certificate.issued.v1,.revoked.v1— project cert deltas.content.play_package.bundle.published.v1,.revoked.v1— project bundle deltas.marketplace.license.granted.v1,.revoked.v1— project license deltas.assignment.window.opened.v1,.completed.v1,.overdue.v1— project assignment deltas.authoring.course_draft.updated.v1(M5 — offline authoring Yjs deltas).identity.device.bound_for_offline.v1— register device for sync.gdpr.subject_request.received.v1— erase all sync data for user.notification.sent.v1— project in-app notification deltas.
4. Versioning
v1 additive. New entity types additive.
5. Idempotency
clientMutationIdPK dedups.- Delta projections idempotent on (scope, lamport).
6. Outbox / Inbox
Standard.
7. Partition Key
(tenantId, userId)for per-user ordering.
8. DLQ
sync.dlq — alerts on non-empty.