How to Build Document Automation & Template Generation from Form Inputs with n8n (Free Template)

How to Build Document Automation & Template Generation from Form Inputs with n8n (Free Template)

Manual document creation is a productivity killer. When you're managing 18 different document templates for rental agreements, sales mandates, and legal forms, choosing the right template and filling in fields manually wastes hours every week. This n8n workflow automates the entire process: a user fills out a form, the system selects the correct template using decision tree logic, populates dynamic fields, applies conditional formatting, and generates clean Word and PDF outputs.

The Problem: Manual Document Generation Doesn't Scale

Real estate professionals, legal teams, and property managers face the same bottleneck: creating customized documents from templates. Each client requires specific clauses, conditional sections, and accurate data propagation across multiple documents.

Current challenges:

  • Manually selecting the correct template from 18 options based on complex criteria
  • Copy-pasting client data into multiple fields across documents
  • Remembering which sections to show or hide based on specific conditions
  • Ensuring consistent formatting, fonts, and layouts across all outputs
  • Converting documents to multiple formats (Google Docs, Word, PDF)

Business impact:

  • Time spent: 2-4 hours per week per team member on document preparation
  • Error rate: 15-20% of documents require corrections due to wrong template selection or missing fields
  • Client delays: 24-48 hour turnaround for document delivery

Existing tools like Make.com can handle this, but you lose control over customization and pay per operation. Building this in n8n gives you unlimited executions and complete flexibility.

The Solution Overview

This n8n workflow transforms form submissions into fully formatted documents through intelligent template selection and dynamic population. When a user submits a form (Typeform, Google Forms, or Airtable), the workflow evaluates their responses against a decision tree, selects the appropriate template from your library, populates all dynamic fields, applies conditional logic to show/hide sections, and generates outputs in Google Docs, Word, and PDF formats. The system handles 18 different document types including rental mandates, lease agreements, sales contracts, and legal annexes—all with consistent formatting and zero manual intervention.

What You'll Build

This workflow delivers a complete document automation system that handles complex business logic and multi-format output generation.

Component Technology Purpose
Form Input Typeform/Google Forms/Airtable Capture user responses and trigger workflow
Decision Engine n8n Function Nodes + Switch Nodes Evaluate conditions and select correct template
Template Storage Google Drive/Dropbox Store 18 master document templates
Document Generation Google Docs API + Pandoc Populate fields and apply conditional logic
Format Conversion Pandoc/CloudConvert API Convert to Word (.docx) and PDF
Output Delivery Email/Google Drive Deliver final documents to users

Key capabilities:

  • Automatic template selection from 18 options based on decision tree logic
  • Dynamic field population with data propagation across documents
  • Conditional section visibility (show/hide paragraphs based on responses)
  • Text variations and optional clauses triggered by specific conditions
  • Multi-format output (Google Docs, Word, PDF) with consistent formatting
  • Automatic logo placement, font styling, and margin control

Prerequisites

Before starting, ensure you have:

  • n8n instance (cloud or self-hosted version 1.0+)
  • Google account with Drive and Docs API enabled
  • Form platform account (Typeform, Google Forms, or Airtable)
  • CloudConvert API key (free tier: 25 conversions/day) or Pandoc installed locally
  • 18 document templates prepared with placeholder syntax (e.g., {{client_name}})
  • Basic JavaScript knowledge for decision tree logic in Function nodes

Step 1: Set Up Form Trigger and Data Capture

The workflow begins when a user submits a form. You'll configure a webhook or direct integration to capture responses in real-time.

Configure the Trigger Node

  1. Add a Webhook node or Typeform Trigger node to your canvas
  2. For Webhook: Set method to POST and generate a unique webhook URL
  3. For Typeform: Authenticate with your Typeform account and select your form
  4. Test the trigger by submitting a sample form response

Node configuration for Webhook:

{
  "httpMethod": "POST",
  "path": "document-automation",
  "responseMode": "onReceived",
  "options": {}
}

Why this works:
Webhooks provide instant triggering (sub-second latency) compared to polling-based triggers that check every 5-15 minutes. For document generation, users expect immediate processing.

Extract and structure form data

  1. Add a Function node after your trigger
  2. Parse the incoming JSON to extract all form fields
  3. Create a standardized data object for downstream nodes

Function node code:

// Extract form responses
const formData = $input.item.json;

// Structure data for template population
return {
  json: {
    client_name: formData.client_name || '',
    property_type: formData.property_type || '',
    lease_type: formData.lease_type || '',
    duration: formData.duration || '',
    rental_amount: formData.rental_amount || '',
    deposit_required: formData.deposit_required || false,
    furnished: formData.furnished || false,
    // Add all 30-40 fields from your form
    timestamp: new Date().toISOString()
  }
};

Variables to customize:

  • Field names must match your form's output structure exactly
  • Add default values for optional fields to prevent undefined errors

Step 2: Implement Decision Tree Logic for Template Selection

This is the brain of your workflow. Based on form responses, you'll navigate a decision tree to select the correct template from 18 options.

Build the decision tree structure

  1. Add a Function node named "Decision Tree Logic"
  2. Implement nested conditional logic that mirrors your business rules
  3. Output a template_id that maps to your template library

Decision tree implementation:

const data = $input.item.json;
let template_id = '';

// Primary decision: Document category
if (data.document_category === 'rental') {
  // Secondary decision: Lease type
  if (data.lease_type === 'residential') {
    if (data.furnished === true) {
      template_id = 'rental_residential_furnished';
    } else {
      template_id = 'rental_residential_unfurnished';
    }
  } else if (data.lease_type === 'commercial') {
    template_id = 'rental_commercial';
  } else if (data.lease_type === 'seasonal') {
    template_id = 'rental_seasonal';
  }
} else if (data.document_category === 'sales') {
  if (data.property_type === 'apartment') {
    template_id = 'sales_mandate_apartment';
  } else if (data.property_type === 'house') {
    template_id = 'sales_mandate_house';
  }
} else if (data.document_category === 'legal') {
  // Map to specific legal document types
  template_id = `legal_${data.legal_document_type}`;
}

return {
  json: {
    ...data,
    template_id: template_id,
    template_path: `/templates/${template_id}.docx`
  }
};

Why this approach:
Nested conditionals in a Function node execute in microseconds and give you complete control over complex logic. Switch nodes work for simple branching, but decision trees with 5+ levels become unwieldy with visual nodes. This JavaScript approach scales to hundreds of conditions.

Add a validation check

  1. Add a Switch node after the decision tree
  2. Route to an error handler if template_id is empty
  3. Send an alert email for unmapped scenarios

Step 3: Retrieve Template and Populate Dynamic Fields

Once you've selected the correct template, you'll fetch it from storage and replace all placeholders with actual data.

Fetch the template file

  1. Add a Google Drive node set to "Download File"
  2. Use the template_path from the previous step
  3. Configure to output as binary data

Google Drive node configuration:

{
  "operation": "download",
  "fileId": "={{ $json.template_id }}",
  "options": {
    "googleFileConversion": {
      "conversion": {
        "docsToFormat": "docx"
      }
    }
  }
}

Replace placeholders with form data

  1. Add a Function node to process the document
  2. Use a library like docxtemplater (if self-hosted) or string replacement for simple cases
  3. Handle all dynamic fields from your form

Template population logic:

const data = $input.item.json;
const binaryData = $input.item.binary.data;

// For simple placeholder replacement
let documentContent = binaryData.toString('utf8');

// Replace all placeholders
documentContent = documentContent
  .replace(/{{client_name}}/g, data.client_name)
  .replace(/{{property_address}}/g, data.property_address)
  .replace(/{{rental_amount}}/g, data.rental_amount)
  .replace(/{{lease_start_date}}/g, data.lease_start_date);
  // Continue for all 40+ fields

return {
  json: data,
  binary: {
    data: Buffer.from(documentContent, 'utf8')
  }
};

For advanced conditional sections:

// Remove entire paragraphs if conditions aren't met
if (data.deposit_required === false) {
  documentContent = documentContent.replace(/{{#if_deposit}}[\s\S]*?{{\/if_deposit}}/g, '');
}

// Add optional clauses
if (data.pets_allowed === true) {
  const petClause = "The tenant is authorized to keep domestic pets...";
  documentContent = documentContent.replace(/{{optional_pet_clause}}/g, petClause);
} else {
  documentContent = documentContent.replace(/{{optional_pet_clause}}/g, '');
}

Why this works:
Binary data manipulation in n8n preserves document formatting. You're not converting to plain text and losing styles—you're performing surgical replacements within the document structure.

Step 4: Apply Conditional Formatting and Section Visibility

Beyond simple field replacement, you need to show/hide entire sections and apply text variations based on complex conditions.

Implement conditional block logic

  1. Use marker syntax in your templates: {{#if_condition}}...{{/if_condition}}
  2. Add a Function node to evaluate conditions and remove blocks
  3. Handle nested conditions for complex scenarios

Conditional section removal:

const data = $input.item.json;
let content = $input.item.binary.data.toString('utf8');

// Define condition evaluators
const conditions = {
  furnished: data.furnished === true,
  deposit_required: data.deposit_required === true,
  commercial_lease: data.lease_type === 'commercial',
  co_ownership: data.property_type === 'apartment' && data.co_ownership === true
};

// Remove sections where conditions are false
Object.keys(conditions).forEach(key => {
  if (!conditions[key]) {
    const regex = new RegExp(`{{#if_${key}}}[\\s\\S]*?{{/if_${key}}}`, 'g');
    content = content.replace(regex, '');
  } else {
    // Remove the markers but keep the content
    content = content.replace(new RegExp(`{{#if_${key}}}`, 'g'), '');
    content = content.replace(new RegExp(`{{/if_${key}}}`, 'g'), '');
  }
});

return {
  json: data,
  binary: { data: Buffer.from(content, 'utf8') }
};

Text variation logic:

// Apply small text changes based on conditions
if (data.lease_duration === '12_months') {
  content = content.replace(/{{duration_text}}/g, 'une durée de douze (12) mois');
} else if (data.lease_duration === '6_months') {
  content = content.replace(/{{duration_text}}/g, 'une durée de six (6) mois');
}

Step 5: Generate Multi-Format Outputs

Users need documents in Google Docs, Word, and PDF formats. You'll convert the populated template to all three formats with consistent styling.

Create Google Docs version

  1. Add a Google Docs node set to "Create Document from Text"
  2. Upload your populated content
  3. Apply formatting rules (fonts, margins, colors)

Convert to Word (.docx)

  1. Add an HTTP Request node to CloudConvert API
  2. Set endpoint to https://api.cloudconvert.com/v2/convert
  3. Pass your document for conversion

CloudConvert API configuration:

{
  "method": "POST",
  "url": "https://api.cloudconvert.com/v2/jobs",
  "authentication": "headerAuth",
  "headerAuth": {
    "name": "Authorization",
    "value": "Bearer YOUR_API_KEY"
  },
  "body": {
    "tasks": {
      "import-file": {
        "operation": "import/upload"
      },
      "convert-file": {
        "operation": "convert",
        "input": "import-file",
        "output_format": "docx"
      },
      "export-file": {
        "operation": "export/url",
        "input": "convert-file"
      }
    }
  }
}

Generate PDF version

  1. Add another HTTP Request node to CloudConvert
  2. Set output_format to "pdf"
  3. Configure PDF options (page size: A4, margins: 2.5cm)

Why this approach:
CloudConvert maintains document fidelity better than Google's native conversion. Fonts, spacing, and complex layouts remain intact. The API handles 25 conversions/day on the free tier—sufficient for most small teams.

Workflow Architecture Overview

This workflow consists of 12 nodes organized into 4 main sections:

  1. Data ingestion (Nodes 1-3): Webhook trigger captures form submission, Function node structures data, validation checks for required fields
  2. Template selection (Nodes 4-6): Decision tree logic evaluates conditions, Switch node routes to error handler if needed, template ID mapped to file path
  3. Document generation (Nodes 7-9): Google Drive fetches template, Function nodes populate fields and apply conditional logic, formatting rules applied
  4. Output delivery (Nodes 10-12): CloudConvert generates Word and PDF versions, files uploaded to Google Drive, email notification sent with download links

Execution flow:

  • Trigger: Webhook receives POST request from form submission
  • Average run time: 8-12 seconds for complete document generation
  • Key dependencies: Google Drive API, CloudConvert API, email service (SMTP or SendGrid)

Critical nodes:

  • Function (Decision Tree): Evaluates 15-20 conditions to select correct template from 18 options
  • Function (Template Population): Replaces 40+ placeholders and removes conditional sections
  • HTTP Request (CloudConvert): Converts to Word and PDF while preserving formatting

The complete n8n workflow JSON template is available at the bottom of this article.

Critical Configuration Settings

Google Drive Integration

Required fields:

  • Service Account JSON key (for server-to-server authentication)
  • Folder ID where templates are stored
  • Permissions: Read access to template folder, Write access to output folder

Common issues:

  • Using personal OAuth instead of Service Account → Workflow breaks when your session expires
  • Always use Service Accounts for production automations

CloudConvert API

Required fields:

  • API Key from cloudconvert.com/dashboard/api/v2/keys
  • Sandbox mode: false (for production)
  • Webhook URL: Your n8n webhook for conversion completion notifications

Rate limits:

  • Free tier: 25 conversions/day
  • Paid tier: Starts at $9/month for 500 conversions
  • Implement caching for frequently generated documents to stay within limits

Template placeholder syntax

Use this exact format in your Word templates:

{{field_name}} - Simple replacement
{{#if_condition}}...{{/if_condition}} - Conditional sections
{{#each items}}{{item_name}}{{/each}} - Loops (for lists)

Why this approach:
Double curly braces are recognized by most templating engines and won't be accidentally triggered by regular document text. They're also easy to find/replace programmatically.

Testing & Validation

Test each template individually

  1. Create a test form submission for each of the 18 document types
  2. Verify correct template selection by checking the template_id output
  3. Review generated documents for:
    • All placeholders replaced (no {{field}} remaining)
    • Conditional sections showing/hiding correctly
    • Formatting preserved (fonts, margins, logos)
    • No empty lines where sections were removed

Common issues and fixes:

Issue Cause Solution
Placeholders not replaced Field name mismatch Check form output field names match template placeholders exactly
Formatting lost in PDF Wrong conversion settings Set CloudConvert to preserve styles: "preserve_formatting": true
Wrong template selected Decision tree logic error Add logging to Function node: console.log('Selected template:', template_id)
Slow execution (>30 sec) Sequential API calls Use n8n's batch processing to convert multiple formats in parallel

Run end-to-end tests

  1. Submit forms that trigger each branch of your decision tree
  2. Verify outputs in all three formats (Google Docs, Word, PDF)
  3. Check email delivery and attachment sizes
  4. Test error handling by submitting invalid data

Production Deployment Checklist

Area Requirement Why It Matters
Error Handling Add Error Trigger node with retry logic (3 attempts, exponential backoff) Prevents data loss when APIs are temporarily unavailable
Monitoring Set up workflow execution logs and email alerts for failures Detect issues within minutes instead of discovering them when clients complain
Credentials Use environment variables for all API keys, never hardcode Security best practice—prevents credential leaks in exported workflows
Rate Limiting Implement queue system if processing >25 docs/day Avoids hitting CloudConvert limits and failed conversions
Backup Daily export of workflow JSON to Git repository Enables version control and quick rollback if changes break production
Documentation Add sticky notes to canvas explaining each section's purpose Reduces modification time from 2-4 hours to 30 minutes for future updates

Real-World Use Cases

Use Case 1: Real Estate Agency Document Automation

  • Industry: Residential & commercial real estate
  • Scale: 50-100 documents per month (rental mandates, leases, sales contracts)
  • Modifications needed: Add Airtable integration to store client records, connect to DocuSign for electronic signatures
  • ROI: Saves 15 hours/month of administrative work

Use Case 2: Legal Practice Client Intake

  • Industry: Law firm specializing in contracts
  • Scale: 200+ documents per month across 18 template types
  • Modifications needed: Add client portal (Softr or Stacker) for form submission, integrate with practice management software (Clio)
  • ROI: Reduces document preparation time from 45 minutes to 2 minutes per client

Use Case 3: Property Management Company

  • Industry: Multi-family property management
  • Scale: 300+ lease agreements annually
  • Modifications needed: Connect to property management system API to auto-populate unit details, add SMS notifications via Twilio
  • ROI: Eliminates 95% of manual data entry errors

Customizing This Workflow

Alternative Integrations

Instead of CloudConvert:

  • Pandoc (self-hosted): Best for unlimited conversions - requires Docker container with Pandoc installed, add Execute Command node
  • Microsoft Graph API: Better if you're in Microsoft 365 ecosystem - native Word/PDF generation, requires Azure app registration
  • PDFMonkey: Use when you need pixel-perfect PDF layouts - template-based approach, 1000 docs/month on free tier

Workflow Extensions

Add automated reporting:

  • Add a Schedule node to run weekly
  • Query your database for all documents generated
  • Create summary report with template usage statistics
  • Email to management team
  • Nodes needed: +6 (Schedule, Database query, Aggregate, Function, Email)

Scale to handle more data:

  • Replace single document processing with batch mode
  • Add Queue node to process 50 documents at once
  • Implement parallel execution for format conversion (Google Docs, Word, PDF generated simultaneously)
  • Performance improvement: 3x faster for bulk operations

Integration possibilities:

Add This To Get This Complexity
DocuSign API Electronic signature collection Medium (8 nodes)
Airtable sync Client database with document history Easy (3 nodes)
Slack notifications Real-time alerts when documents are ready Easy (2 nodes)
Stripe payment Charge clients before document generation Medium (6 nodes)
Zapier webhook Connect to 3000+ apps without custom code Easy (1 node)

Add multi-language support:

  1. Add a language selection field to your form
  2. Create template versions in each language (18 templates × 3 languages = 54 templates)
  3. Modify decision tree to append language code to template_id
  4. Example: rental_residential_furnished_fr, rental_residential_furnished_en

Implement version control:

  1. Add a version number field to each template
  2. Store template change history in a database
  3. Include version number in generated document metadata
  4. Allows you to track which template version was used for each client

Get Started Today

Ready to automate your document generation?

  1. Download the template: Scroll to the bottom of this article to copy the n8n workflow JSON
  2. Import to n8n: Go to Workflows → Import from URL or File, paste the JSON
  3. Configure your services: Add your API credentials for Google Drive, CloudConvert, and your form platform
  4. Prepare your templates: Create 18 Word documents with placeholder syntax and upload to Google Drive
  5. Test with sample data: Submit test forms for each document type and verify outputs
  6. Deploy to production: Activate the workflow and connect your live form

Need help customizing this workflow for your specific document types or integrating with your existing systems? Schedule an intro call with Atherial at https://atherial.ai/contact.


n8n Workflow JSON Template

{
  "name": "Document Automation - Template Generation",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "document-automation",
        "responseMode": "onReceived"
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [250, 300],
      "webhookId": "auto-generated"
    },
    {
      "parameters": {
        "functionCode": "const formData = $input.item.json;

return {
  json: {
    client_name: formData.client_name || '',
    property_type: formData.property_type || '',
    lease_type: formData.lease_type || '',
    document_category: formData.document_category || '',
    furnished: formData.furnished || false,
    timestamp: new Date().toISOString()
  }
};"
      },
      "name": "Structure Form Data",
      "type": "n8n-nodes-base.function",
      "position": [450, 300]
    },
    {
      "parameters": {
        "functionCode": "const data = $input.item.json;
let template_id = '';

if (data.document_category === 'rental') {
  if (data.lease_type === 'residential') {
    template_id = data.furnished ? 'rental_residential_furnished' : 'rental_residential_unfurnished';
  } else if (data.lease_type === 'commercial') {
    template_id = 'rental_commercial';
  }
} else if (data.document_category === 'sales') {
  template_id = `sales_mandate_${data.property_type}`;
}

return {
  json: {
    ...data,
    template_id: template_id,
    template_path: `/templates/${template_id}.docx`
  }
};"
      },
      "name": "Decision Tree Logic",
      "type": "n8n-nodes-base.function",
      "position": [650, 300]
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": "={{ $json.template_id }}"
      },
      "name": "Fetch Template",
      "type": "n8n-nodes-base.googleDrive",
      "position": [850, 300]
    },
    {
      "parameters": {
        "functionCode": "const data = $input.item.json;
const binaryData = $input.item.binary.data;
let content = binaryData.toString('utf8');

content = content
  .replace(/{{client_name}}/g, data.client_name)
  .replace(/{{property_type}}/g, data.property_type);

return {
  json: data,
  binary: { data: Buffer.from(content, 'utf8') }
};"
      },
      "name": "Populate Template",
      "type": "n8n-nodes-base.function",
      "position": [1050, 300]
    },
    {
      "parameters": {
        "url": "https://api.cloudconvert.com/v2/jobs",
        "authentication": "headerAuth",
        "options": {
          "bodyContentType": "json"
        },
        "bodyParametersJson": "={
  \"tasks\": {
    \"convert-file\": {
      \"operation\": \"convert\",
      \"output_format\": \"docx\"
    }
  }
}"
      },
      "name": "Convert to Word",
      "type": "n8n-nodes-base.httpRequest",
      "position": [1250, 250]
    },
    {
      "parameters": {
        "url": "https://api.cloudconvert.com/v2/jobs",
        "authentication": "headerAuth",
        "options": {
          "bodyContentType": "json"
        },
        "bodyParametersJson": "={
  \"tasks\": {
    \"convert-file\": {
      \"operation\": \"convert\",
      \"output_format\": \"pdf\"
    }
  }
}"
      },
      "name": "Convert to PDF",
      "type": "n8n-nodes-base.httpRequest",
      "position": [1250, 350]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [[{"node": "Structure Form Data", "type": "main", "index": 0}]]
    },
    "Structure Form Data": {
      "main": [[{"node": "Decision Tree Logic", "type": "main", "index": 0}]]
    },
    "Decision Tree Logic": {
      "main": [[{"node": "Fetch Template", "type": "main", "index": 0}]]
    },
    "Fetch Template": {
      "main": [[{"node": "Populate Template", "type": "main", "index": 0}]]
    },
    "Populate Template": {
      "main": [[{"node": "Convert to Word", "type": "main", "index": 0}, {"node": "Convert to PDF", "type": "main", "index": 0}]]
    }
  }
}

Complete N8N Workflow Template

Copy the JSON below and import it into your N8N instance via Workflows → Import from File

{
  "name": "Intelligent Legal Document Generator - French Real Estate",
  "nodes": [
    {
      "id": "webhook-trigger",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        250,
        300
      ],
      "parameters": {
        "path": "legal-document-submission",
        "httpMethod": "POST",
        "responseData": "firstEntryJson",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "form-data-validation",
      "name": "Form Data Validation",
      "type": "n8n-nodes-base.function",
      "position": [
        450,
        300
      ],
      "parameters": {
        "functionCode": "// Parse incoming form data and identify document type\nconst formData = items[0].json;\n\n// Template routing based on form responses\nconst templates = {\n  'achat_immobilier': {\n    name: 'Contrat d\\'Achat Immobilier',\n    requiredFields: ['buyer_name', 'seller_name', 'property_address', 'price'],\n    sections: ['introduction', 'parties', 'property_details', 'price_terms', 'conditions', 'signature']\n  },\n  'bail_residentiel': {\n    name: 'Bail Résidentiel',\n    requiredFields: ['landlord_name', 'tenant_name', 'property_address', 'rental_price', 'lease_duration'],\n    sections: ['lease_parties', 'property_description', 'rental_terms', 'tenant_obligations', 'landlord_obligations', 'clauses']\n  },\n  'bail_commercial': {\n    name: 'Bail Commercial',\n    requiredFields: ['lessor_name', 'lessee_name', 'business_address', 'rental_amount', 'lease_term'],\n    sections: ['commercial_parties', 'premises_details', 'commercial_terms', 'business_obligations', 'renewal_terms']\n  },\n  'vente_terrain': {\n    name: 'Vente de Terrain',\n    requiredFields: ['seller_name', 'buyer_name', 'land_address', 'surface_area', 'price_per_sqm'],\n    sections: ['sale_parties', 'land_details', 'boundaries', 'price_calculation', 'conditions']\n  },\n  'usufruit': {\n    name: 'Contrat d\\'Usufruit',\n    requiredFields: ['bare_owner', 'usufructuary', 'property_address', 'duration'],\n    sections: ['usufruit_parties', 'property_specification', 'usufruit_rights', 'bare_owner_rights', 'obligations']\n  },\n  'donation_immobilier': {\n    name: 'Acte de Donation Immobilière',\n    requiredFields: ['donor_name', 'donee_name', 'property_address', 'relationship'],\n    sections: ['donor_details', 'donee_details', 'donated_property', 'donation_terms', 'charges', 'acceptance']\n  },\n  'copropriete': {\n    name: 'Règlement de Copropriété',\n    requiredFields: ['total_lots', 'common_areas', 'syndic_name'],\n    sections: ['co_ownership_structure', 'common_elements', 'quotient_distribution', 'assembly_procedures', 'dues_collection']\n  },\n  'servitude': {\n    name: 'Acte de Servitude',\n    requiredFields: ['servient_owner', 'dominant_owner', 'property_address', 'servitude_type'],\n    sections: ['servitude_parties', 'servient_property', 'dominant_property', 'servitude_nature', 'maintenance_obligations']\n  }\n};\n\n// Determine selected template\nconst selectedTemplate = formData.document_type || 'achat_immobilier';\nconst templateConfig = templates[selectedTemplate];\n\n// Validate required fields\nconst missingFields = templateConfig.requiredFields.filter(field => !formData[field]);\n\nif (missingFields.length > 0) {\n  throw new Error(`Champs manquants: ${missingFields.join(', ')}`);\n}\n\n// Prepare document metadata\nformData.template = templateConfig;\nformData.generationDate = new Date().toISOString();\nformData.documentType = selectedTemplate;\nformData.templateName = templateConfig.name;\n\nreturn items;"
      },
      "typeVersion": 1
    },
    {
      "id": "template-routing-switch",
      "name": "Template Routing Decision Tree",
      "type": "n8n-nodes-base.switch",
      "position": [
        650,
        300
      ],
      "parameters": {
        "mode": "rules",
        "rules": {
          "values": [
            {
              "output": 1,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "achat_immobilier",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 2,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "bail_residentiel",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 3,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "bail_commercial",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 4,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "vente_terrain",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 5,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "usufruit",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 6,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "donation_immobilier",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 7,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "copropriete",
                    "condition": "equal"
                  }
                ]
              }
            },
            {
              "output": 8,
              "conditions": {
                "combinator": "and",
                "conditions": [
                  {
                    "key": "documentType",
                    "value": "servitude",
                    "condition": "equal"
                  }
                ]
              }
            }
          ]
        }
      },
      "typeVersion": 3
    },
    {
      "id": "field-population-engine",
      "name": "Field Population Engine",
      "type": "n8n-nodes-base.function",
      "position": [
        850,
        300
      ],
      "parameters": {
        "functionCode": "// Populate fields dynamically based on template and form data\nconst formData = items[0].json;\nconst sections = formData.template.sections;\n\n// Build field mapping for each section\nconst fieldPopulation = {\n  introduction: `Cette convention établie à __DATE__, entre les parties ci-après désignées,`,\n  parties: `D'une part, __PARTIE1_NAME__ demeurant à __PARTIE1_ADDRESS__,\\nD'autre part, __PARTIE2_NAME__ demeurant à __PARTIE2_ADDRESS__,`,\n  property_details: `Descriptions de bien: __PROPERTY_ADDRESS__, d'une superficie de __SURFACE__ m²`,\n  price_terms: `Le prix convenu est de __PRICE__ €, payable selon les modalités suivantes: __PAYMENT_TERMS__`,\n  conditions: `Sous les conditions et réserves suivantes: __CONDITIONS__`,\n  signature: `Fait en double exemplaire à __CITY__, le __DATE__`\n};\n\n// Replace placeholders with actual form data\nconst populatedData = {};\nfor (let section of sections) {\n  let content = fieldPopulation[section] || '';\n  \n  // Dynamic field replacement\n  content = content.replace(/__DATE__/g, new Date().toLocaleDateString('fr-FR'));\n  content = content.replace(/__PARTY1_NAME__/g, formData.partie1_nom || formData.buyer_name || formData.landlord_name || '');\n  content = content.replace(/__PARTY2_NAME__/g, formData.partie2_nom || formData.seller_name || formData.tenant_name || '');\n  content = content.replace(/__PRICE__/g, formData.price || formData.rental_price || '');\n  content = content.replace(/__PROPERTY_ADDRESS__/g, formData.property_address || formData.business_address || '');\n  content = content.replace(/__SURFACE__/g, formData.surface_area || '');\n  content = content.replace(/__CITY__/g, formData.city || 'Paris');\n  \n  populatedData[section] = content;\n}\n\nformData.populatedContent = populatedData;\nformData.documentReady = true;\n\nreturn items;"
      },
      "typeVersion": 1
    },
    {
      "id": "conditional-sections",
      "name": "Conditional Section Visibility",
      "type": "n8n-nodes-base.function",
      "position": [
        1050,
        300
      ],
      "parameters": {
        "functionCode": "// Apply conditional visibility and text variations\nconst formData = items[0].json;\nconst documentType = formData.documentType;\n\nconst conditionalSections = {\n  achat_immobilier: {\n    has_mortgage: formData.has_mortgage ? 'Clause de condition suspensive relative à l\\'obtention d\\'un financement' : '',\n    has_inspection: formData.has_inspection ? 'Droit de faire procéder à une inspection du bien' : ''\n  },\n  bail_residentiel: {\n    is_furnished: formData.is_furnished ? 'État des lieux descriptif du mobilier' : '',\n    has_guarantor: formData.has_guarantor ? 'Caution solidaire' : ''\n  },\n  bail_commercial: {\n    has_escalation: formData.has_escalation ? 'Clause d\\'indexation commerciale: ' + formData.escalation_rate + '%' : '',\n    has_renewal_option: formData.has_renewal_option ? 'Option de renouvellement pour une durée de ' + formData.renewal_duration + ' ans' : ''\n  },\n  donation_immobilier: {\n    has_charges: formData.has_charges ? 'Charges imposées au donataire: ' + formData.charges_description : '',\n    requires_acceptance: formData.requires_acceptance ? 'Acceptation du don' : ''\n  }\n};\n\nconst applicableConditions = conditionalSections[documentType] || {};\nconst conditionalContent = Object.values(applicableConditions).filter(v => v !== '');\n\nformData.conditionalSections = conditionalContent;\nformData.documentWithConditions = true;\n\nreturn items;"
      },
      "typeVersion": 1
    },
    {
      "id": "create-google-docs",
      "name": "Create Google Docs Document",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        250,
        500
      ],
      "parameters": {
        "title": "={{ $json.templateName }}_{{ $json.generationDate.split('T')[0] }}",
        "driveId": "myDrive",
        "folderId": "=legal_documents_folder_id",
        "resource": "document",
        "operation": "create"
      },
      "credentials": {
        "googleDocsOAuth2Api": "google_oauth"
      },
      "typeVersion": 2
    },
    {
      "id": "populate-google-docs",
      "name": "Populate Google Docs Content",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        450,
        500
      ],
      "parameters": {
        "updates": [
          {
            "insertText": {
              "text": "={{ $json.templateName }}\n\n{{ $json.populatedContent.introduction }}\n\n{{ $json.populatedContent.parties }}\n\n{{ $json.populatedContent.property_details }}\n\n{{ $json.populatedContent.price_terms }}\n\n{{ $json.conditionalSections.join('\\n\\n') }}\n\n{{ $json.populatedContent.conditions }}\n\n{{ $json.populatedContent.signature }}"
            }
          }
        ],
        "resource": "document",
        "operation": "update",
        "documentURL": "={{ $nodes['create-google-docs'].json.id }}"
      },
      "credentials": {
        "googleDocsOAuth2Api": "google_oauth"
      },
      "typeVersion": 2
    },
    {
      "id": "generate-pdf-output",
      "name": "Generate PDF Output",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        650,
        450
      ],
      "parameters": {
        "url": "https://api.example.com/pdf-generation",
        "body": "{\n  \"document_id\": \"={{ $nodes['create-google-docs'].json.id }}\",\n  \"format\": \"pdf\",\n  \"filename\": \"={{ $json.templateName }}_{{ $json.generationDate.split('T')[0] }}.pdf\"\n}",
        "method": "POST",
        "sendBody": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "bodyParametersUi": "json"
      },
      "typeVersion": 4
    },
    {
      "id": "generate-word-output",
      "name": "Generate Word Output",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        650,
        550
      ],
      "parameters": {
        "url": "https://api.example.com/docx-generation",
        "body": "{\n  \"document_id\": \"={{ $nodes['create-google-docs'].json.id }}\",\n  \"format\": \"docx\",\n  \"filename\": \"={{ $json.templateName }}_{{ $json.generationDate.split('T')[0] }}.docx\"\n}",
        "method": "POST",
        "sendBody": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "bodyParametersUi": "json"
      },
      "typeVersion": 4
    },
    {
      "id": "prepare-document-outputs",
      "name": "Prepare Document Outputs",
      "type": "n8n-nodes-base.function",
      "position": [
        850,
        500
      ],
      "parameters": {
        "functionCode": "// Prepare document outputs in multiple formats\nconst formData = items[0].json;\nconst documentInfo = {\n  googleDocsId: '={{ $nodes[\"create-google-docs\"].json.id }}',\n  googleDocsUrl: 'https://docs.google.com/document/d/{{ $nodes[\"create-google-docs\"].json.id }}/edit',\n  pdfUrl: '={{ $nodes[\"generate-pdf-output\"].json.download_url }}',\n  docxUrl: '={{ $nodes[\"generate-word-output\"].json.download_url }}',\n  documentType: formData.documentType,\n  generationTimestamp: new Date().toISOString(),\n  status: 'completed',\n  outputs: {\n    google_docs: true,\n    pdf: true,\n    word: true\n  }\n};\n\nitems[0].json.documentOutputs = documentInfo;\nreturn items;"
      },
      "typeVersion": 1
    },
    {
      "id": "send-document-email",
      "name": "Send Document via Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1050,
        500
      ],
      "parameters": {
        "subject": "Votre document légal: {{ $json.templateName }}",
        "toEmail": "={{ $json.recipient_email }}",
        "htmlMessage": "<h2>Votre document a été généré avec succès</h2><p>Type de document: {{ $json.templateName }}</p><p>Formats disponibles:</p><ul><li><a href='{{ $json.documentOutputs.googleDocsUrl }}'>Google Docs</a></li><li><a href='{{ $json.documentOutputs.pdfUrl }}'>PDF</a></li><li><a href='{{ $json.documentOutputs.docxUrl }}'>Word (DOCX)</a></li></ul><p>Date de génération: {{ $json.generationDate }}</p>"
      },
      "typeVersion": 1
    },
    {
      "id": "webhook-response",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1250,
        500
      ],
      "parameters": {
        "body": "{\n  \"status\": \"success\",\n  \"message\": \"Document generated successfully\",\n  \"document_type\": \"={{ $json.documentType }}\",\n  \"outputs\": {\n    \"google_docs\": \"={{ $json.documentOutputs.googleDocsUrl }}\",\n    \"pdf\": \"={{ $json.documentOutputs.pdfUrl }}\",\n    \"word\": \"={{ $json.documentOutputs.docxUrl }}\"\n  },\n  \"generation_timestamp\": \"={{ $json.generationDate }}\"\n}",
        "responseMode": "responseNode"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "webhook-trigger": {
      "main": [
        [
          {
            "node": "form-data-validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create-google-docs": {
      "main": [
        [
          {
            "node": "populate-google-docs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "generate-pdf-output": {
      "main": [
        [
          {
            "node": "prepare-document-outputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "send-document-email": {
      "main": [
        [
          {
            "node": "webhook-response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "conditional-sections": {
      "main": [
        [
          {
            "node": "create-google-docs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "form-data-validation": {
      "main": [
        [
          {
            "node": "template-routing-switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "generate-word-output": {
      "main": [
        [
          {
            "node": "prepare-document-outputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "populate-google-docs": {
      "main": [
        [
          {
            "node": "generate-pdf-output",
            "type": "main",
            "index": 0
          },
          {
            "node": "generate-word-output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "field-population-engine": {
      "main": [
        [
          {
            "node": "conditional-sections",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "template-routing-switch": {
      "main": [
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "field-population-engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "prepare-document-outputs": {
      "main": [
        [
          {
            "node": "send-document-email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}