Skip to content

Concurrent-Edit Awareness

Feature code: GEN::CEA

Several users can work the same tenant’s data at the same time. The same user can open the same item in two browser tabs. Either case can leave a user looking at data that the backend has already moved on from. Concurrent-Edit Awareness is the platform-wide capability that closes that gap: the system tells the user when the data on screen is no longer current, so they refresh before acting; and when a destructive bulk action is about to fire against a selection that has gone stale, the system catches it before any destructive call is made.

The capability is intentionally a notification, not a merge. Arda does not attempt to reconcile two concurrent edits — that is the user’s job. The platform’s job is to make sure neither user discovers the conflict after clicking the destructive button.


The platform makes three concrete promises against the concurrency surface:

  1. A user with an item open is notified when someone else changes its kanban-card data. The notification appears in the detail panel as a stale-data banner with a Refresh and a Dismiss control. The user can refresh to see the new state or dismiss to keep working with what they have.
  2. A user with two browser tabs open on the same item sees the same notification within sub-second time of the other tab’s edit. Same-browser, cross-tab propagation is in-process; the user does not have to wait for a network round-trip in either tab.
  3. A destructive bulk action against a selection that has gone stale is caught at click time. Before the action proceeds, the system re-reads the affected entities. If any selected entity’s underlying data has changed since the user made their selection, the action is aborted and a stale-selection banner asks the user to refresh and re-attempt.

A fourth, weaker, promise applies to the cross-browser case: when two users are on different browsers (different machines, different networks), the second user sees the banner within a bounded latency, not in sub-second time. The bound is operational and is documented in the runtime tuning notes below.


The capability surfaces in three places:

SurfaceWhat the user sees
Item-details panelA banner at the top of the panel reading “This data has changed elsewhere”, with Refresh and Dismiss buttons. The banner appears when the panel’s view of an item’s kanban cards no longer matches the backend.
Items grid — bulk action confirmationWhen the user clicks a destructive bulk action (Delete) and the selection has gone stale, a banner above the grid replaces the action’s confirmation dialog. The user must Refresh (which re-issues the cards query and clears the banner) or Dismiss (which closes the banner) before the action can be re-attempted.
Order-queue, scan, and card-state surfacesSame banner mechanics as the detail panel, applied through the same underlying mechanism. Any surface that mounts the detail panel for an item gets the banner for free.

The banner copy and controls are deliberately consistent across surfaces, so the user learns one interaction and applies it everywhere.


The capability is governed by the following behavioural rules:

  • No silent data overwrites. If the user dismisses the banner and proceeds to mutate, the per-mutation server check still enforces optimistic locking — a stale mutation will fail with a server-side conflict surfaced as a toast. The banner exists to make that case rare, not to replace the backend check.
  • No false positives from network errors. If the freshness check itself fails (transport error, non-OK response), the banner does not appear. The user keeps seeing what they had, and the next successful check re-evaluates.
  • No interference with the user’s own actions. A user who makes a change in tab 1 does not see their own banner appear in tab 1 — the panel they edited refreshes through its own success path. The banner is only for state the user did not originate.
  • No amplification under burst. A bulk operation that touches dozens of items in quick succession produces a single coalesced refresh, not one per item.
  • Operational kill switch for the cross-process path. The cross-browser polling tick can be disabled per environment without redeploying functional changes; the cross-tab path is unaffected.

The user-flow scenarios that this feature must satisfy are catalogued under the General Behaviours and Reference Data use-case sections:


The mechanism that delivers this capability is documented in the system reference:

The frozen design decisions are recorded as ADRs:


The capability exposes two operational levers that take effect at SPA build time:

Environment variableDefaultEffect
NEXT_PUBLIC_ITEM_CARDS_POLL_MS120000 ms (two minutes)Worst-case latency for the cross-browser case. Any non-positive value disables the cross-process polling entirely (the kill switch). The cross-tab path is unaffected.
NEXT_PUBLIC_ITEM_CARDS_TTL_MS30000 msRead-side freshness floor used by the grid’s per-cell TTL check. Lower values produce more background refreshes; higher values let stale-while-revalidate hold out-of-date data on screen for longer.

The capability currently covers the Item entity and any surface that mounts the item-details panel (items page, order-queue, scan modals, card preview). Extension to other entities is mechanical — the same primitives apply to any entity whose detail surface reads through a cached provider.

EntityRead-side bannerBulk-action preflight
ItemCoveredCovered (Delete)
Item SupplyNot yet coveredNot yet covered
Business AffiliateNot yet coveredNot yet covered
Order, Kanban Card (detail)Covered indirectly through the item-details panel; standalone detail surfaces are not yet on the staleness signal