N8N Integration
N8N is used as the workflow orchestration engine for document processing, AI extraction, and embedding generation.
Architecture
sequenceDiagram
participant App as PIP AI Server
participant N8N as N8N Workflow
participant AI as OpenAI / LLM
participant DB as Supabase DB
participant Store as Supabase Storage
App->>N8N: Webhook trigger (with secret)
N8N->>Store: Download document (signed URL)
N8N->>AI: OCR / Extract / Embed
N8N->>DB: Upsert structured data
N8N->>App: Callback (status + results)Workflows
1. Spec Processing
Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-spec-upsert
Payload:
{
"spec_upload_id": "uuid",
"document_id": "uuid",
"storage_path": "specs/brand/upload_id/file.pdf",
"brand_name": "Holiday Inn Express",
"area": "guest-room",
"property_name": "San Francisco Airport",
"job_id": "uuid"
}Steps:
- Download spec PDF via signed URL
- OCR/LLM extraction → structured sections
- Upsert
pip_ai_spec_sectionswith unique(spec_upload_id, spec_number) - Generate embeddings via OpenAI
text-embedding-3-small - Update processing status
- Callback to app
2. PIP Processing
Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-pip-processor
Payload:
{
"document_id": "uuid",
"project_id": "uuid",
"storage_path": "pips/project_id/doc_id/file.pdf",
"job_id": "uuid",
"callback_url": "https://app.example/api/pip/callback"
}Steps:
- Resolve the Supabase project from the
Supabase Projectsdata table bycallback_url.extractDomain() - Validate inbound
x-webhook-secretagainstSupabase Projects.Webhook_Secret - Download PIP PDF
- OCR/LLM extraction → structured line items
- Upsert
pip_ai_pip_itemswith unique(document_id, code) - For each item, query
pip_ai_search_specs()(filtered by brand + areas) - Upsert candidate matches into
pip_ai_matcheswith unique(pip_item_id, spec_section_id) - Update processing status
- Callback to app with
x-webhook-secretand{ document_id, project_id, job_id, status, items_count }
The PIP workflow resolves Supabase config from the Supabase Projects data table by callback_url.extractDomain(). The row must include Webhook_Secret, which must match the app-side N8N_WEBHOOK_SECRET. The workflow intentionally does not read $env.* in n8n.
3. Floor Plan Processing
Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-floor-plan-processor
Steps:
- Download floor plan
- Render to PNG + generate thumbnail
- OCR visible labels → extract spec codes
- Update
pip_ai_floor_plans.extracted_spec_codes[] - Link to known spec sections
- Callback to app
4. Submittal PDF Export
Trigger: POST {N8N_BASE_URL}/webhook/pip-ai-submittal-exportWorkflow JSON: instructions/n8n-workflows/pip-ai-submittal-export.json
Payload:
{
"job_id": "uuid",
"project_id": "uuid",
"format": "pdf",
"storage_bucket": "pip-ai-docs",
"storage_path": "exports/submittals/project_id/job_id.pdf",
"callback_url": "https://app.example/api/submittal-export/callback"
}Worker contract:
- Resolve the Supabase project from the
Supabase Projectsdata table bycallback_url.extractDomain() - Validate
x-webhook-secretagainstSupabase Projects.Webhook_Secret - Load
pip_ai_submittal_export_jobsbyjob_idthroughPIP AI - Supabase Router - Read
manifest_snapshotas the immutable export source - Render the PDF through
Supabase Projects.Gotenberg_URLand upload it tostorage_bucket/storage_path - Mark
pip_ai_submittal_export_jobsascompletedorfailedthroughPIP AI - Supabase Router - Call
callback_urlwithx-webhook-secretas a best-effort notification
The Supabase Projects data-table row for the callback domain must include Domain, Supabase_URL, Webhook_Secret, and Gotenberg_URL. The workflow intentionally does not read $env.* in n8n. The direct Supabase Router update is the authoritative job state; callback delivery must not turn a successful storage upload into a failed export.
Callback payloads:
{
"job_id": "uuid",
"project_id": "uuid",
"status": "completed",
"storage_path": "exports/submittals/project_id/job_id.pdf"
}{
"job_id": "uuid",
"project_id": "uuid",
"status": "failed",
"error": "Renderer failed"
}The callback also accepts status: "processing" and normalizes legacy N8N status: "succeeded" to completed.
5. Legacy Document Builder PDF Export
Handles the original document builder PDF generation.
6. AI Image Generation (Nano Banana)
Webhook Security
All webhooks use a shared secret for authentication:
Header: x-webhook-secret: <N8N_WEBHOOK_SECRET>Use the same header in both directions: Nuxt server routes send it when triggering n8n workers, and n8n sends it back when calling Nuxt callbacks. Never expose N8N webhook URLs or secrets through NUXT_PUBLIC_* runtime config.
Job Queue Pattern
N8N can also poll the pip_ai_upload_jobs table:
-- Claim a job
UPDATE pip_ai_upload_jobs
SET status = 'processing', locked_at = now(), locked_by = 'n8n-worker'
WHERE id = '<job_id>' AND status = 'queued'
RETURNING *;Idempotency
All N8N workflows are designed to be safely re-runnable:
- Upserts use unique constraints
- Job status tracking prevents double-processing
retry_counttracks reprocessing attempts
Configuration
N8N_BASE_URL=https://your-n8n-instance.com
N8N_WEBHOOK_SPEC_PROCESSOR=/webhook/pip-ai-spec-upsert
N8N_WEBHOOK_PIP_PROCESSOR=/webhook/pip-ai-pip-processor
N8N_WEBHOOK_FLOOR_PLAN_PROCESSOR=/webhook/pip-ai-floor-plan-processor
N8N_WEBHOOK_SUBMITTAL_EXPORT=/webhook/pip-ai-submittal-export
N8N_WEBHOOK_SECRET=your-shared-secret
SUPABASE_SERVICE_ROLE_KEY=server-only-service-role-keyThese Nuxt variables are server-side only. The submittal export n8n workflow itself does not use $env.*; configure the matching secret in the n8n Supabase Projects data table.