Bulk actions in MENA portals: selection and safe retries
A practical design for Arabic-English work queues: define selection across pages, check each change and recover without repeating completed work.

A supervisor filters a work queue, checks the box above the rows and chooses "Assign". Does that mean the visible page, every matching record, or the records that matched when the screen first loaded? If the application cannot answer precisely, the confirmation dialog is asking the user to approve an unknown operation.
For Arabic-English operations portals serving teams in Saudi Arabia and the UAE, bulk actions deserve their own execution design. This guide proposes one for assigning independent service tickets. It covers selection across pages, changes during review and retries after a lost response. It is not a payment-approval design or a claim about local regulatory requirements.
Cover: original SultanByte artwork showing a reviewed selection becoming a recorded bulk operation.
Give "select all" a defined scope
Start with two distinct controls: "Select this page" and "Select all matching results". Do not let the second meaning hide inside the first checkbox. Display the selected scope near the action, including exclusions and the active customer workspace.
For a small selection, retain stable record identifiers, not row positions. Sorting, pagination and Arabic-English label changes must not turn the third visible row into a different selected ticket. For this proposed interface, changing the filter clears the selection with a visible explanation. Changing only the display language preserves it because language is not record identity.
A large matching selection needs a server-side representation. Before confirmation, resolve the authorised query into a bounded selection record containing the exact ticket IDs and their relevant versions. Include the tenant, action parameters, requester and expiry. Return an opaque selection identifier, a count and a reviewable summary. If materialising the set takes time, show that preparation state before enabling confirmation.
Do not rerun an unrestricted live filter after the user confirms. Newly arriving tickets would silently expand the operation. Conversely, freezing the IDs does not freeze the tickets' contents or guarantee continued permission to change them. Those checks belong at execution.
Set a maximum batch size and a retention policy for the selection record. Large selections may need a separate queued workflow, but they should not acquire vaguer approval semantics merely because they are large.
Make selection usable without a mouse
The W3C checkbox pattern describes checked, unchecked and mixed states, with Space changing a focused checkbox's state. Use that model for the visible-page control: mixed means some eligible rows on this page are selected, not an unspecified state somewhere in the entire dataset.
Give each row checkbox an accessible name that identifies its ticket. Prefer native controls and keep the selected count visible. A colour change alone is insufficient communication for this design.
Do not add role="grid" just because the table contains checkboxes. W3C's table guidance distinguishes a static table containing independently focusable widgets from a composite grid with its own interaction model. A native table with labelled checkboxes is a reasonable starting point. Choose a grid only when the team will implement and test its keyboard behaviour.
Test the complete selection flow in Arabic and English with keyboard and screen-reader users. Keep the workspace name, action and exclusions understandable in both versions. A UAE workspace and a Saudi workspace remain distinct selections even when the same supervisor can access both; the interface language must never decide the execution scope.
Bind confirmation to the reviewed operation
Present the action in concrete terms: assign the selected tickets to the named team, with a link to review the selected records and any exclusions. If the assignee changes, create a new review state rather than reusing the previous approval.
OWASP's transaction-authorisation guidance recommends showing significant transaction data, enforcing the process on the server and tying the final authorisation check to execution. Applying that principle here does not mean every ticket assignment needs a banking-style second factor. It means the action the server accepts must be the action the user reviewed.
The proposed server contract binds the selection identifier to an immutable action payload. Confirmation references that record; it does not submit a fresh, freely editable filter. Reject expired selections and mismatched action parameters. Treat an opaque identifier as a locator, not permission.
A saved selection also needs a clear owner. Another user must not be able to execute it merely by copying its URL. If the product supports delegated approval, implement that as an explicit permission and review flow rather than an accidental consequence of sharing a link.
Original infographic: SultanByte. Proposed engineering framework informed by OWASP, PostgreSQL and W3C guidance, October 2026. The states describe a design, not measured production results.
Recheck each ticket where the change happens
OWASP recommends checking permissions on every request. For this batch design, extend the review to every item and to the execution worker: a permitted batch endpoint does not make every supplied ID permissible.
Use the verified tenant and current permissions when locating each ticket. Check that the proposed assignee remains eligible. Protect the result endpoint too, so the operation receipt cannot become a second way to read records after access is removed. SultanByte's tenant-isolation guide covers the wider request and worker boundary.
Prevent a change between validation and mutation from bypassing the checks. For a ticket-local assignment, the proposed implementation uses a conditional update against the expected version and permitted current state, with the version advanced on success. Keep mutable permission and assignee checks consistent with that write through an explicit locking or transaction strategy; a version field on the ticket does not protect unrelated policy tables.
PostgreSQL 18's isolation documentation explains why a preliminary read is insufficient: under Read Committed, successive queries can see different committed data. It also describes re-evaluation of an update's condition after a concurrent update. Design and test the actual transaction rather than assuming that surrounding several statements with BEGIN freezes everything they depend on.
If a relevant version changed, return a conflict for review instead of silently overwriting newer work. Where the failure concerns lost access, avoid disclosing the record's current details in the explanation.
Choose atomic or partial execution before building retries
For independent ticket assignments, this guide recommends explicit per-item outcomes. One ticket changing during review need not stop every unrelated ticket, provided the product owner accepts partial completion and the interface makes it clear.
That recommendation does not apply to an operation whose items must satisfy a shared invariant. If all changes must happen together, use a genuinely atomic boundary and reject the whole operation on failure. Do not advertise "all or nothing" while committing each item separately. Cross-system side effects need their own recovery design; a database rollback cannot recall an email already sent.
For the proposed partial mode, store each successful mutation and its durable item receipt in the same transaction. Enforce uniqueness for the operation-and-item pair. Two workers must not both execute the same item because each saw an earlier "pending" value. The exact locking and uniqueness implementation needs concurrency tests, including a worker crash at commit.
Keep "not started", "succeeded", "needs review" and "outcome unresolved" distinct. A timeout is not evidence that the ticket stayed unchanged. If an external dependency participates, reconcile its outcome before deciding whether another call is safe.
Retry the operation, not the current screen
When the browser loses the response, it should recover the existing operation by its identifier. It must not collect the now-visible rows and submit a new batch. Keep a client-generated request identifier before submission and scope server deduplication to the verified tenant and actor, with a fingerprint of the approved payload.
For this design, a repeated identifier with the same payload returns the existing operation. A changed payload is rejected. Retain that mapping for the documented recovery window and define what happens after expiry; do not imply indefinite duplicate protection.
Provider semantics need separate inspection. Stripe's idempotency reference distinguishes API v1, which returns a stored response after execution begins, from API v2's handling of failed or partially failed work. That is a useful warning against assuming every service interprets an idempotency key identically. It is an example of an API contract, not a recommendation to route ticket assignments through Stripe.
A "retry unresolved items" action should resolve the existing receipts first. A "retry conflicts" action should build a new selection from the still-permitted failed subset, fetch current versions and request fresh confirmation. Keep successful items out of that new attempt.
Report what changed, not just that the request finished
Show a persistent operation result with per-item outcomes and safe next actions. Separate accepted work from completed work. Do not collapse a partly completed batch into a green success toast, or label every item failed because the final browser request timed out.
WCAG's status-message guidance explains how progress and result messages can be exposed to assistive technology without moving focus. Announce useful milestones and the final summary rather than every background update. Keep a result view available after a toast disappears.
For release testing, use synthetic records and exercise selection across pages, a filter change, an excluded row, a changed ticket and a removed permission. Submit the same confirmed operation concurrently, interrupt a worker around commit and lose the browser response. Verify both stored records and receipts, including what the restricted user can still read.
The product owner's approval should state whether partial completion is acceptable and what "all matching" means. Engineering's evidence should demonstrate that a reviewed set stays bounded and that recovery does not repeat completed work. Those decisions make a bulk-action button usable under real interruptions, rather than merely convenient when every request succeeds.
About the author
- I have lead the Engineering for multiple startups in UAE. I also have my own agency qualascend.com.
Comments
Join the discussionNo comments yet. Be the first to comment.
Builder Guides
Practical architecture, engineering, security and implementation guides for teams building technology in MENA.




