Documentation

Review workflows.

Last updated

Review plans

What it is. The approval policy attached to a datasource — it decides how a submitted query gets from "submitted" to "executed". Use it to require AI scoring, one or more human sign-offs, or both, and to auto-approve low-risk reads. Each plan is a sequence of stages; each stage names approvers (by role or specific user) and a minimum number of approvals before the query advances.

Configure it. Build plans at /admin/review-plans — start from a built-in template or from scratch:

Review plans admin page with the create-from-template dropdown open, listing four templates — Strict (writes need 2 approvals), Lenient (reads auto-approved), AI-only (no human approval), and Standard (AI plus one reviewer).
/admin/review-plans → caret next to Add review plan exposes four built-in templates that prefill the create modal.
Add review plan modal with name and description fields, AI-review and human-approval toggles enabled, minimum approvals set to 1, approval timeout 24 hours, and an approver row defaulting to the REVIEWER role at stage 1.
/admin/review-plansAdd review plan. Stack approver rows to build multi-stage chains.
  1. Open /admin/review-plans and click Add review plan, or pick a built-in template from the dropdown caret next to it (Strict — writes need 2 approvals, Lenient — reads auto-approved, AI-only — no human approval, Standard — AI + 1 reviewer) to prefill the modal with sensible defaults.
  2. Name and describe the policy — e.g. "Production writes — two reviewers".
  3. Pick the gates. Toggle Require AI review to score every query before it queues for humans; toggle Require human approval to demand at least one reviewer sign-off. Auto-approve LOW-risk reads lets SELECTs skip humans entirely when AI risk is below the threshold.
  4. Set thresholds. Minimum approvals is the number of distinct reviewers needed before the query advances; Approval timeout (hours) is when AccessFlow auto-rejects an idle PENDING_REVIEW query (it scans on a cadence set by ACCESSFLOW_WORKFLOW_TIMEOUT_POLL_INTERVAL, default PT5M).
  5. Build the approver chain. Click Add approver for each stage; each row names a role (or a specific user) and a stage number. Stages advance sequentially, and a single REJECTED decision at any stage terminates the query.

What can a review plan control?

A review plan is six settings plus an approver chain. Together they decide whether a query needs AI scoring, how many humans must sign off, which of them, and what happens if nobody does. Every setting below is per-plan, and a plan attaches to a datasource.

Setting What it does When disabled / unset
Require AI review Every query is scored for risk before it queues for humans. The query skips PENDING_AI and goes straight to review.
Require human approval At least one reviewer must sign off before execution. The query is approved without a human — AI-only gating.
Auto-approve LOW-risk reads SELECTs below the AI risk threshold skip human approval. Reads queue for review like any other statement.
Minimum approvals How many distinct reviewers must approve before the query advances. Defaults to one approval per stage.
Approval timeout (hours) How long an idle PENDING_REVIEW query waits before auto-rejection. The query waits indefinitely for a decision.
Approver chain Ordered stages, each naming a role or a specific user as approver. No chain means no staged escalation — one flat approval step.

Stages advance sequentially and a single Reject at any stage terminates the query. A user can never approve their own query, whatever their role.

Reviewer decisions. Reviewers can Approve, Reject, or Request changes. Reject and Request changes both require a non-empty comment — the server enforces this (HTTP 400 VALIDATION_ERROR), and the UI disables the confirm button until the textarea is populated. The comment is persisted on the decision row, rendered on the rejected stage of the timeline on /queries/<id>, and surfaced to the submitter as a "Changes requested" alert whenever the latest decision is REQUESTED_CHANGES and the query is still PENDING_REVIEW. Approve still treats the comment as optional.

Query status transitions. A query moves through these states:

PENDING_AI → PENDING_REVIEW → APPROVED → EXECUTED
                           ↘ REJECTED   (manual reviewer rejection)
                           ↘ TIMED_OUT  (approval-timeout auto-reject)
PENDING_REVIEW → CANCELLED (submitter only)
APPROVED → FAILED (execution error)

A single REJECTED decision at any stage terminates the query. If a query sits in PENDING_REVIEW past the plan's approval timeout, AccessFlow auto-rejects it (it scans on a cadence set by ACCESSFLOW_WORKFLOW_TIMEOUT_POLL_INTERVAL, default PT5M). Auto-approve reads lets SELECTs skip human approval entirely; Require AI review still scores the read but won't block on a human.

Routing policies

What it is. Policy-as-code that decides a query's path automatically, after AI analysis and before reviewers see it. Use it to auto-approve routine reads, hard-block dangerous patterns, or escalate sensitive ones — instead of sending everything through the same review plan. Policies run in ascending priority and the first enabled one whose condition matches wins; anything unmatched falls through to the datasource's review plan exactly as before.

Configure it. Manage them at /admin/routing-policies (the Routing policies entry in the Security nav group):

  1. Open /admin/routing-policies (the Routing policies entry in the Security nav group, next to Review plans) and click Add policy.
  2. Name the policy and optionally scope it to one datasource — leave the datasource blank for an org-wide rule. Set its priority (unique per organisation; lower runs first) and the enabled toggle.
  3. Build the condition with the guided builder: pick match ALL (AND) or match ANY (OR), then add leaf conditions — each can be negated (NOT). Operands include query type, referenced tables (glob, e.g. payroll.*), AI risk level, AI risk score (with a comparison operator), requester role, requester group, time-of-day window, day-of-week, presence of a WHERE clause, presence of a LIMIT clause, the transactional (BEGIN…COMMIT) flag, and the pre-flight cost estimate — estimated rows (comparison against the engine's own EXPLAIN estimate, or the exact affected-row count for UPDATE/DELETE) and scan type (glob match on the plan's root operation, e.g. Seq*) — so a policy can route a 10-million-row sequential-scan DELETE differently from a 10-row indexed one.
  4. Choose the action. Auto-approve (skip human review), Auto-reject (block the query), Require approvals (force human review with an absolute minimum number of approvers), or Escalate (force human review, adding a delta on top of the review plan's minimum). The approver count applies only to the last two actions.
  5. Reorder policies any time with the per-row up/down controls — the order is the evaluation order.
How it routes. Time-of-day and day-of-week conditions are evaluated in the server's local timezone (overnight windows wrap around midnight). On datasources with AI analysis disabled, risk-based conditions never match (there's no AI signal); routing does not run when AI analysis fails — the query goes to a human instead. The cost-estimate conditions likewise never match while no estimate exists (engine without a plan concept, or the estimate failed) — they fail closed rather than auto-approving blind. Every automated decision is recorded in the audit log (QUERY_APPROVED / QUERY_REJECTED with source: "ROUTING_POLICY"), and the query detail page shows which policy matched. Routing policies are managed via the ADMIN-only /api/v1/admin/routing-policies CRUD and /reorder endpoints.
The /admin/routing-policies page listing ordered routing policies by priority — name, scope, condition summary, action (auto-approve / escalate), and per-row reorder controls.
/admin/routing-policies — ordered, attribute-based auto-decision rules; first match by priority wins, unmatched falls through to the review plan.

Access recertification campaigns

What it is. Recurring attestation campaigns that make someone periodically re-confirm who still needs standing datasource access — the review control SOC 2 and ISO 27001 auditors ask for. An admin schedules an org- or datasource-scoped campaign; when it opens it snapshots the current standing grants into one item per grant and notifies the eligible reviewers (multi-channel, plus an attestation.campaign_opened WebSocket event). Reviewers work a certify / revoke worklist that reuses the review-queue patterns (self-review blocked, bulk-certify); a revoke routes through the normal permission-revoke path, so access is actually removed.

Configure it. Manage campaigns from /admin/attestation and certify items from the reviewer worklist at /reviews/attestations. Two clustered-safe jobs run the lifecycle: one opens SCHEDULED campaigns at their scheduled_open_at, the other closes OPEN campaigns at their due_at and applies each campaign's pending-default (KEEP or REVOKE) to anything a reviewer never got to. A completed campaign exports as a CSV evidence file (who reviewed what, decisions, timestamps), and every transition — ATTESTATION_CAMPAIGN_OPENED/CLOSED, ATTESTATION_ITEM_CERTIFIED/REVOKED — lands in the tamper-evident audit log.

Tune it. ACCESSFLOW_ATTESTATION_OPEN_POLL_INTERVAL and ACCESSFLOW_ATTESTATION_CLOSE_POLL_INTERVAL (open / close scan cadence, both default PT5M) and ACCESSFLOW_ATTESTATION_MAX_EVIDENCE_ROWS (row cap before an evidence CSV is marked truncated, default 50000).

The AccessFlow access-recertification campaign list at /admin/attestation, showing scheduled and open attestation campaigns with their due dates and pending-item counts.
/admin/attestation — admins schedule recurring access-recertification campaigns; reviewers certify or revoke each snapshotted grant.