Record and approve the decision
Procurement or Security may take days to review a request. Vendor Review needs to preserve the request, its assessment, and the eventual human decision throughout that wait.
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_failedWait 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 steps for assessment and database updates, 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 decisionThe 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.
Put external calls in steps and design their side effects for retries. Stable request identifiers and upserts prevent duplicate stored records; they do not guarantee that an external model call runs only once. A retry may repeat that call and incur another charge. The route that starts the workflow also needs an idempotency key so repeated submissions can 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 does not prove who sent it. 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:
- Validate the request body
- Resolve the verified principal
- Load the pending request and required reviewer groups
- Authorize the principal
- Atomically record the decision if none exists
- 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 separate Procurement and Security decisions, store two approval records and wait for both.
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
Before opening the comparison, classify each behavior as a workflow, an agent, or not authorized:
- Follow a fixed sequence and wait for a Procurement decision.
- Send one templated reminder after a fixed delay.
- Choose which people and systems to consult, gather missing evidence, and decide when the packet is complete.
- 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 preserves progress while review waits. Authentication and group checks establish who may decide, and the database records that decision. Idempotency checks handle repeated submissions and approval attempts; external calls still need a retry strategy.
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.
Confirm that the request is still waiting after the preview deployment test above. Its state belongs to the workflow and database, so review can continue after the original process ends.
Compare your orchestration with process-vendor-request.ts on complete.
Was this helpful?