| Author: Abdullah Ahmed | Category: Custom Web Application Development
A reviewer approves an AI-prepared change, but a background worker executes a newer version of the proposal. The interface recorded the click correctly; the backend failed to connect that decision to the exact operation. This is the kind of bug that appears when human review is added as a flag instead of designed as part of the application's state model.
Human-in-the-loop automation requires durable proposals, explicit decisions, authorisation, concurrency handling, and recoverable execution. The model prepares or interprets work, while the application preserves what was reviewed and controls what may happen next.
This guide describes a backend design for a web application that prepares account updates for review. The concepts are framework-independent and should be adapted to the application's transaction model and supported external interfaces. They are an implementation blueprint, not a claim that one schema fits every business process.
Define the domain objects before the queue
Start with a task or case that represents the business goal. It should reference the initiating actor, affected business record, task type, and source context. This gives the workflow an identity independent of a chat session or worker process.
Represent a proposal as a versioned object containing the intended operation, material values, evidence references, and unresolved conditions. Treat a reviewed version as immutable for decision purposes.
Represent approval as a separate decision linked to that version, actor, role context, and time. Rejection, requested changes, and withdrawal may also need explicit records rather than overwriting one boolean field.
Represent execution attempts and confirmed outcomes separately. A proposal can be approved without execution completing, and an attempted operation can have an uncertain outcome. The data model should preserve those distinctions.
Design a state machine around business transitions
Useful task states may include preparing, awaiting review, changes requested, approved, executing, confirmed, failed, and uncertain. Choose only states that correspond to meaningful decisions or recovery behaviour.
Define allowed transitions and the actor or service permitted to request each one. The model may submit a proposal, a reviewer may approve it, and an execution worker may report a result. These authorities should not be interchangeable.
Store transition reasons and relevant references. A failure caused by invalid input needs a different response from an unavailable dependency. The exception path should be understandable without reading model prose.
Keep state transitions in one maintained domain service or equivalent boundary. Scattered updates from controllers and workers make it easy for one path to bypass a required check.
Make proposals immutable once reviewed
When the model produces a draft, validate and store it with a version identifier or content fingerprint suitable for the application. The approval endpoint should reference that exact version.
If a reviewer edits the proposal, create a new version and apply the appropriate review policy. Do not mutate the approved payload in place and expect an old approval to describe the new content accurately.
Include all material execution fields in the reviewed representation. A hidden recipient, destination, or amount outside the proposal can change the action without changing what the user saw.
Keep evidence and source versions with the proposal. A later source update may make the proposal stale, but it should not erase the record of what the reviewer actually assessed.
Enforce approval authorisation on the server
The server must verify the authenticated actor, role, resource scope, and allowed decision. Hiding an approve button in the interface does not prevent an unauthorised request to the endpoint.
Check the current task and proposal state. An approval for a withdrawn, superseded, or already executed proposal should follow explicit policy rather than succeeding because the identifier exists.
Apply the application's usual request protections and input validation. AI involvement does not remove ordinary web security requirements around sessions, cross-site requests, and resource access.
Record the decision atomically with the relevant state transition where possible. A stored approval without the matching task state, or vice versa, creates ambiguity for the worker that executes later.
Revalidate before execution
Approval establishes a decision about a proposal, but current business conditions may still need checking. The account may have changed, the actor's authority may have been revoked, or an external record may no longer accept the operation.
Use optimistic version checks, locks, or other concurrency mechanisms appropriate to the domain. The aim is to prevent a stale proposal from overwriting a newer valid change.
Define which changes invalidate approval. A refreshed source timestamp alone may be harmless, while a changed recipient or price may require a new proposal and decision. Keep that policy explicit.
Return stale work to a reviewable state with an explanation. Do not silently regenerate and execute a materially different operation under the old approval.
Separate the decision transaction from remote execution
A local database transaction cannot generally include an external API call as though both systems shared one atomic commit. Design the handoff so approved work is not lost if the process stops between saving the decision and scheduling execution.
A transactional outbox is one possible pattern: store the execution intent with the domain change, then let a worker publish or process it. Evaluate the pattern against the application's existing messaging infrastructure rather than introducing it automatically.
The important property is durable intent and recoverable delivery. A successful approval response should not depend on an in-memory job that disappears if the web process exits.
Keep the worker responsible for revalidation and controlled execution, not for deciding whether the user's approval was meaningful. That relationship should already be represented in the stored proposal and decision.
Use idempotency at the business-operation boundary
Workers can retry after crashes or lost acknowledgements. Assign a stable operation identity that remains the same for retries of the same approved action, and use the destination's supported idempotency mechanism where available.
Do not use a new random identifier for every retry if the destination relies on that identifier to detect duplicates. Distinguish a retry from a genuinely new approved operation.
Protect local execution claims with concurrency-safe constraints. A check followed by an unprotected insert can race when two workers process the same task simultaneously.
Test the crash point after the remote action may have succeeded but before local confirmation is stored. Recovery should query or reconcile the destination rather than blindly repeat a consequential write.
Represent uncertain outcomes explicitly
A timeout means the application lacks a response; it does not establish that the destination did nothing. Store an uncertain state with the request reference and the evidence available for reconciliation.
Provide a supported status check or operator procedure. The next action may be to query the destination, wait for a callback, or inspect a business record. It should not default to retry in every case.
Keep partial success visible when a workflow has several side effects. An account update may be confirmed while a notification remains unresolved. Recovery should target the unfinished component.
Do not let the model narrate uncertainty away. The user-facing status should be derived from application state and confirmed results, even if the assistant can produce a confident completion message.
Design cancellation and approval expiry
Some proposals should expire after a defined period or when relevant source state changes. Store the expiry condition and enforce it at approval and execution as appropriate.
Cancellation before execution can stop pending work. Cancellation after submission may require reconciliation or a compensating action. These are different transitions and should not share a misleading cancelled flag.
Define who can withdraw an approval or cancel a task. The initiating user, reviewer, and operator may have different authority under the business process.
Keep the history of completed actions. Reversal is often a new operation that corrects the business state rather than deletion of the original event. This distinction supports audit and incident investigation.
Keep model output outside the trusted execution core
The model should return a constrained proposal, not arbitrary executable instructions. Validate its schema, references, and allowed operation type before storing it as eligible for review.
The execution service should map approved proposal fields to a known application command. It should not interpret a new free-text plan at the moment of execution.
Enforce permissions, destination restrictions, and business rules independently. The OWASP AI agent security guidance is relevant to keeping untrusted instructions and tool use from expanding authority.
Treat retrieved documents and user messages as data throughout the workflow. A proposal containing an instruction to bypass approval should be rejected by the application contract, not merely discouraged in a prompt.
Expose a stable API for the review interface
The frontend needs the proposal version, affected record, evidence, current state, allowed decisions, and relevant execution status. Return these through a clear application contract rather than requiring the browser to infer state from conversation text.
Use structured validation errors that identify the failed condition. A stale proposal, missing permission, and invalid field need different user responses.
When the user submits a decision, require the proposal version they reviewed. If the current version differs, return a conflict or equivalent response that prompts a fresh inspection.
Make status updates available through polling, events, or another supported mechanism appropriate to the application. The interface should display actual transitions without inventing progress based on elapsed time.
Build an operational exception view
Operators need to find tasks awaiting information, stale approvals, exhausted retries, and uncertain writes. Show the affected business record, current state, attempt history, and safe next actions.
Restrict repair capabilities according to role. Replaying an operation or applying a compensating change can be consequential and should pass the same relevant validation as normal execution.
Preserve correlations across model requests, proposals, decisions, jobs, and destination operations. This makes one case traceable without retaining every sensitive payload in an unfiltered log.
Define ownership for business and technical exceptions. A missing customer mapping may belong to operations, while an authentication error belongs to the integration owner. Routing improves recovery time and reduces unnecessary escalation.
Test the concurrency and crash boundaries
Tests should cover duplicate approvals, simultaneous reviewers, a proposal changed before approval, a record changed before execution, and revoked authority. Assert the resulting domain state and permitted transitions.
Exercise worker retries and crash points around the remote call. Verify that confirmed operations are not repeated and uncertain outcomes remain inspectable.
Test partial completion and cancellation at several stages. A task cancelled while awaiting review differs from one cancelled after a destination accepted the request.
Keep model evaluation separate from these invariant tests. Even a deliberately malformed or adversarial proposal should not bypass the execution boundary. The application controls must hold without assuming model cooperation.
Evaluate the complete assisted workflow
Use representative business cases to measure proposal quality, reviewer effort, correction patterns, and accepted outcomes. Include cases that should stop for missing evidence or authority.
Review whether the interface exposes enough information for the stored approval to be meaningful. Backend correctness cannot compensate for a screen that hides the actual recipient or changed values.
Rerun evaluations when the model, prompt, source selection, or tool schema changes. These changes can affect what reviewers see even if the state machine remains stable.
Monitor the production queue and recovery workload. A technically correct system may still be impractical if too many proposals become stale or require extensive manual investigation.
## Specify the minimal persisted relationships
A practical schema review can begin with four relationships: the task references its business object; the proposal references the task and source version; the decision references the proposal version and actor; the execution record references the approved operation. The exact tables may differ, but these relationships should remain unambiguous.
Add uniqueness and integrity constraints where they protect the domain. For example, the same operation identity should not create two independent execution intents. A decision should not reference a proposal from another task.
Keep mutable progress fields separate from immutable decision evidence. Operators may update an attempt's status, but the values a person approved should remain reconstructable.
Review the schema using a failed operation and a revised proposal. If the team cannot explain which approval applies to which payload after both events, the model needs refinement before implementation.
Plan retention without breaking the audit
Tasks, drafts, decisions, and diagnostic payloads may have different retention needs. Define those policies with the appropriate owners and preserve the minimal relationships needed to explain consequential actions.
Removing an old generated draft should not leave an execution record whose approved values can no longer be established when the business requires that evidence. Conversely, retaining every source document indefinitely may be unnecessary.
Keep access to audit data role-appropriate. A support operator may need the operation state and reference without seeing all personal details included in the original request.
Test archival and deletion procedures as part of maintenance planning. Human-in-the-loop systems accumulate state, and lifecycle management should preserve correctness rather than become an afterthought.
Deliver one durable approval-to-outcome path
Begin with a single operation and model its proposal, decision, execution, and recovery explicitly. Use the application's existing infrastructure where it provides the required durability and concurrency guarantees.
Prove that the reviewed values are the executed values, that stale authority is rejected, and that interruption does not lose or duplicate work. Then add further task types with their own domain rules.
Human-in-the-loop automation becomes dependable when a person's decision is preserved as application state and connected to a controlled operation. That backend foundation lets the interface offer genuine review and gives operators a path through the failures that real systems inevitably encounter.