Vercel Logo

Record and approve the decision

Vendor Review can now separate policy from model judgment and test both. It still needs to preserve what happened and wait safely when Procurement or Security must decide.

Save the evidence

Stay on course-work. Follow Storage on Vercel Marketplace to provision a Postgres integration such as Neon and connect it to the project. Confirm that the integration created DATABASE_URL for Preview and Production. For local work, copy that value into .env.local without committing it.

Open the provider’s SQL console and run scripts/schema.sql. Start the app and submit one request; the vendor_requests table should contain a row before the model assessment completes.

Store each source of evidence separately:

  • Original request and creator identity
  • Policy route and policy version
  • Structured model assessment
  • Model and assessment version
  • Workflow status and run identifier
  • Human decision and verified reviewer identity
  • Created and updated timestamps

Avoid one generic reasoning column. It erases whether a statement came from policy, a model, or a person.

Persist the request before calling the model. A failed assessment should leave a recoverable record:

submitted → assessing → waiting_for_review → approved | rejected
                      └→ assessment_failed

Wait without keeping a request open

A sensitive request may wait several days for Security. An HTTP request, process variable, or scheduled retry cannot reliably hold that wait.

The scaffold configures Workflow SDK in next.config.ts, provides retry-safe steps, and leaves the orchestration in workflows/process-vendor-request.ts unfinished. Implement this sequence:

persist request
  → run structured assessment
  → save policy and model evidence
  → complete when no review is required
  → otherwise wait for a human decision
  → save the verified decision

The workflow should load the persisted request, run the assessment inside a try block, save assessment_failed before rethrowing an assessment error, and stop immediately with screened when policy requires no reviewer. Otherwise create a hook from the stored random review token, wait for a HumanDecision, save it, and return the final status.

External work belongs in retry-safe steps. Use stable request identifiers and upserts so a retry cannot create a second assessment or approval. The route that starts the workflow also needs an idempotency key; repeated submission should return the existing run.

Create a random token for resuming the review workflow and store it with the request. Never derive a public resume token from a predictable request ID.

Start a request that requires review on the course-work preview. Commit and push a harmless change so Vercel creates a new preview deployment, then confirm that the same workflow remains in waiting_for_review.

Verify the reviewer

A reviewer name sent in a request body is user input, not identity. The browser does not get to nominate its own authority. Resolve identity and group membership from the authenticated request context. The code calls this trusted identity a verified principal:

type VerifiedPrincipal = {
  subject: string;
  email: string;
  groups: string[];
};

Authentication establishes who the person is. Authorization checks whether that person belongs to the required reviewer group. Operating the Vercel project does not automatically grant Procurement or Security authority.

Before resuming the workflow:

  1. Validate the request body
  2. Resolve the verified principal
  3. Load the pending request and required reviewer groups
  4. Authorize the principal
  5. Atomically record the decision if none exists
  6. Resume the stored workflow hook

A repeated click should return the existing decision. A conflicting second decision should fail visibly. The fast tests cover the pure decision gate; the API exercise below verifies the behavior through the running application.

The course app keeps one final decision. When both policy rules match, its demo reviewer must have both groups. If your process requires a separate Procurement decision and Security decision, store two approval records and wait for both. Do not compress two accountable decisions into one merely because the demo has one button.

For local development, use a clearly labeled development-only identity adapter with an environment guard. Record enterprise identity integration as planned or demonstrated unless you actually configured it.

Know when this becomes an agent

Vendor Review is currently a durable application workflow: a person submits a request, code follows a known process, and a person makes the final decision.

It becomes agentic if it begins pursuing an open-ended goal—for example, choosing whom to contact, deciding when to follow up, consulting several systems, and continuing until the review packet is complete.

That change requires an explicit inventory of:

  • Typed tools and their permissions
  • State and history retained across steps
  • Scoped access to company systems
  • How retries avoid duplicate work, plus stop conditions
  • Actions that require human approval

Do not call a scheduled loop with broad credentials a governed agent. Autonomy changes the controls the system needs.

Before opening the comparison, classify each behavior as a workflow, an agent, or not authorized:

  1. Follow a fixed sequence and wait for a Procurement decision.
  2. Send one templated reminder after a fixed delay.
  3. Choose which people and systems to consult, gather missing evidence, and decide when the packet is complete.
  4. Purchase the vendor when the model reports low risk.
Compare the boundary

The first two are fixed workflows because their steps and stop conditions are predetermined. The third is agentic because the system chooses actions while pursuing an open-ended goal. The fourth is not authorized: autonomy does not grant purchasing authority, and a model classification is not approval.

Complete Agent job in docs/readiness.md for the third behavior. Name its goal, typed tools, retained state, stop conditions, retry key, and actions that require approval. The next lesson implements only the intake portion. It does not grant approval or purchasing authority.

Commit the durable-review checkpoint:

git add workflows docs/readiness.md
git commit -m "feat: add durable vendor review"

Summary

Workflow makes long-running work durable. Verified identity records who made the human decision. Together they let an application pause for review without losing state, duplicating work, or trusting a name supplied by the browser.

Check your work

Submit one restricted-data request, then confirm it reaches waiting_for_review. Submit the same idempotency key again and confirm no second workflow appears. Try an unauthorized reviewer, an authorized decision, the same decision again, and the opposite decision. The expected responses are deny, accept, return the existing result, then conflict. For a request matching both rules, use the course demo identity with both reviewer groups.

While the request waits, deploy a harmless change. The same request should still be waiting because its state belongs to the workflow and database, not the process that happened to receive the first HTTP request.

Compare your orchestration with process-vendor-request.ts on complete.

Was this helpful?

supported.