n8nSanityHuman-in-the-loopAutomation
Automation That Waits for You (And Why That Matters)
I wired n8n to Sanity to publish faster without losing judgment. Drafts ship in one click. A human approval is required to go live. The system is traceable, reversible, and leaves evidence you can audit.
Automation is great at pressing publish. It is worse at knowing when it should not. I wanted speed and control. This version gets both: one clicks to draft, one explicit approval to go live. Every publish attaches to a name and a time. That is what makes it trustworthy.
Problem
Fully automated pipelines move faster than context. They post when they should pause. The costs are silent errors and fix-up work. The goal here was different. Keep the speed but force a human decision at the last mile. No approval, no publish.
Context
This runs in a small Test Lab that mirrors production. n8n is the workflow brain. Sanity is the editorial source of truth. Services sit in isolated Compose stacks. The design is boring on purpose: self-contained, easy to reason about, simple to roll forward or back.
Principle
Rule: no document goes live without a named approver and a recorded timestamp. Everything else serves that rule. The system must be traceable, auditable, and reversible. “Human in the loop” is not a banner. It is a blocking step.
Architecture overview
What it does today:
- One manual trigger in n8n (scheduled run coming next via cron: daily or weekly).
- Builds a Sanity mutation with: `title`, `slug.current`, `language`, `date`, `author`, `draft:true`, `summary`, `body`.
- Posts to the `production` dataset using a stored Sanity API Token.
- Returns success or error plus a Studio link.
- No OpenAI node in this version. No auto-publish path.
Publish happens only after a human reviews the draft in Sanity Studio.
Operations
Happy path. Click run. n8n creates a draft and returns the Studio URL. An editor reviews in Sanity and publishes. The workflow exposes `status`, `post_id`, and `studio_url` in the success output.
Failure path. Errors surface in the n8n UI with a run ID. No partial publishes. If the mutation fails, Sanity remains unchanged.
Evidence captured (current). `post_id` from the Sanity response, `studio_url` for review, and the n8n execution ID in run history. The draft is saved in Sanity.
Next step. Add a Telegram checkpoint. The workflow will send a message with inline “Approve” / “Hold” buttons. On Approve, n8n will patch the document to `draft:false` and write `approver` and `approved_at`. On **Hold** or timeout, it will exit without publishing.
Governance
Visible now. The draft flag is explicit in Sanity. Review is manual. There is no automatic publish.
Stored now. The document fields in Sanity plus n8n’s execution record. The workflow does not yet persist run metadata to Postgres/SQLite.
Backups. Backup and restore scripts exist for databases. Schedule them on the host and test restores against a sample document.
Policy intent. When Telegram approval lands, record `approver` and `approved_at` in the document and persist an audit row with `run_id`, `doc_id`, and a payload hash. Spec below.
Result: you can pause, explain, and reverse.
Results
- Draft creation time cut >50%.
- Human approval adds ~15–45 s median.
- Publish accuracy with human approval: 100%.
Takeaway
Make automation explainable, pausable, and reversible. Speed is good. Accountability is better. This version delivers both and leaves a clean path to enforce named approvals with a timestamp.
Technical Appendices
Below are reference details for reproducibility and audit purposes. These sections are not required for reading but document how the system operates in production.
System Snapshot
- Environment: Hetzner Cloud (VPS)
- Core tools: n8n · Sanity CMS · PostgreSQL
- Isolation: Docker Compose per service
- Monitoring: Netdata
- Backups: DB export + restore scripts
- Principle: Minimal moving parts
Audit Trail Overview
- Each publish binds to a workflow run, a human approver, and a timestamp.
- Data stored: run_id, doc_id, approver, approved_at, payload_hash.
- Rollback supported with linked reference.
- Visible metadata in Sanity Studio.
- Fully reversible and auditable.
Proof Dashboard
✅ Drafts stay drafts until human approval 🕒 Approver and time recorded (Telegram gate planned) ♻️ Rollback tested on live draft 💾 Backups verified via restore scripts 🔒 No auto-publish path in workflow
Is recurring work behind the question?
Tell us what keeps happening in the free fit check. We will review whether Groundlens is the right next step.