Skip to main content

Event-driven search and schedule views

Mailbox views use events to refresh search history, results, saved searches, schedules, and autonomous-sort progress. Sync Center operation/conflict refresh and passive-sort status refresh have separate behavior.

When the browser reads data​

DataInitial readLater reads
Search historyAfter account event subscriptionUnknown-search authorization, local action, reconnection
Search resultsWhen opening the selected searchLive event, gap/completion backfill, reconnection
Saved searchesWhen search opensSave, rename, delete, local action, reconnection
SchedulesWhen opening the account viewschedule.changed, sync.recovered, local action, reconnection
Autonomous-sort progressInitial account-scoped status readappProcessProgress, reconnection

These event-driven views have no fallback polling during a WebSocket outage. They display the last known state. On reconnection, authenticated HTTP reads restore observed accounts. Browser disconnection does not stop backend processing.

Passive search components observe the cache through useSyncExternalStore without an active QueryObserver. An empty search ID starts no search. They do not create a passive skipToken observer on an active query's key. Local subscription-readiness state remains separate. Stable autonomous-sort callbacks prevent a mail-list rerender from restarting status reads.

Another account's event, an old response, or an old completion timer cannot replace newer state.

Recover search results​

The connected-account ID identifies the browser's authenticated account selection. A search event's userId is the backend mailbox user ID. They are not interchangeable. For an unknown search, an authenticated BFF history response must establish access before the event enters that account's cache.

The live cursor records the latest observed event state. The backfill cursor advances only after the client reads durable result pages. WebSocket arrival order and a higher live cursor do not prove that all results arrived.

The client pages through durable results on completion, detected gaps, opening, and reconnection. Older responses cannot regress newer event state. Within one QueryClient, an account shares its listener and deleted-search record.

Event-driven HTTP reads coalesce. An event during a read causes a trailing read. Deleted searches cannot return through an older response.

Returning to an account rereads history and saved searches once because events could arrive while unsubscribed. Opening the schedule view also reads current state. This is an entry read, not timed polling.

Schedule event contract​

UserRealtimeSyncEventV1.eventType uses schedule.changed.

Payload fieldMeaning
scheduleIdSchedule UUID
draftIdStable draft identity
statusCurrent schedule state
revisionRequested schedule revision

Envelope scope includes tenant, mailbox, and user identity. correlationId is the schedule ID. The event excludes message content and recipients.

The state change and outbox entry share a transaction. Delivery passes through graphSyncNotifications, InterfaceNotifier, appRealtime, and the authenticated BFF WebSocket. The BFF resolves the connected account on the server and refreshes its email-schedules cache.

Events cover acceptance, rescheduling, cancellation, worker transitions, sending, failures, recovery, and Outlook projection. Conditional writes retain revision and lock predicates. Rollback removes the event too. Rechecking unchanged visible state does not emit another event. A failed send prerequisite persists failure and notification before the processor throws.

For Outlook cancellation/rescheduling, the client reads once after acceptance, then checks the requested revision on events or reconnection. The 45-second deadline returns pending. It starts no extra mutation and does not report unconfirmed work as success. See change a schedule.