{
  "name": "Paperless School Intake Metadata Enrichment v1.0",
  "active": false,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "school/intake/paperless-enrich",
        "responseMode": "lastNode",
        "responseData": "allEntries"
      },
      "id": "paperless-school-webhook",
      "name": "Paperless School Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -1160,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst input = $input.first().json || {};\nconst body = input.body || input;\nconst candidates = [\n  body.document_id,\n  body.id,\n  body.doc_id,\n  body.pk,\n  body.document_id?.id,\n  body.document?.id,\n  body.document\n].filter(v => v !== undefined && v !== null);\nlet raw = candidates[0];\nif (typeof raw === 'object' && raw !== null) raw = raw.id ?? raw.document_id ?? raw.pk ?? null;\nif (typeof raw === 'string' && /\\{.+\\}/.test(raw)) {\n  throw new Error('Received unresolved template string instead of document id.');\n}\nconst documentId = Number(raw);\nif (!Number.isFinite(documentId) || documentId <= 0) {\n  throw new Error('Could not resolve Paperless document id from webhook payload.');\n}\nreturn [{ json: { document_id: documentId } }];"
      },
      "id": "normalize-paperless-webhook",
      "name": "Normalize Paperless Webhook",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -900,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{($env.PAPERLESS_BASE_URL || 'https://paperless.paccoco.com').replace(/\\/$/, '') + '/api/documents/' + $json.document_id + '/'}}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{'Token ' + $env.PAPERLESS_API_TOKEN}}"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "options": {
          "timeout": 120000
        }
      },
      "id": "fetch-paperless-document",
      "name": "Fetch Paperless Document",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -640,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst doc = $input.first().json || {};\nconst originalFilename = doc.original_file_name || doc.original_filename || '';\nconst baseName = String(originalFilename).replace(/\\.[^.]+$/, '');\nif (!baseName || !baseName.startsWith('school-')) {\n  throw new Error('Document original filename does not contain expected intake id prefix: ' + originalFilename);\n}\nreturn [{ json: {\n  intake_id: baseName,\n  document_id: doc.id,\n  current_title: doc.title || '',\n  current_tags: Array.isArray(doc.tags) ? doc.tags : [],\n  original_filename: originalFilename\n} }];"
      },
      "id": "extract-intake-id",
      "name": "Extract Intake ID",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -380,
        0
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT intake_id, class_name, assignment_name, submission_kind, semester, course_code, paper_kind, notes, source, telegram_chat_id, telegram_message_id, original_filename, stored_filename, checksum_sha256, status, paperless_task_id, paperless_document_id, paperless_title, received_at, uploaded_at, enriched_at FROM school_paperless_intake WHERE intake_id = '{{ $json.intake_id.replace(/'/g, \"''\") }}' LIMIT 1;"
      },
      "id": "pg-fetch-intake-record",
      "name": "Postgres Fetch Intake Record",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -120,
        0
      ],
      "credentials": {
        "postgres": {
          "id": "SETUP_REQUIRED",
          "name": "Shared Postgres"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "\nconst intake = $input.first().json || {};\nif (!intake.intake_id) throw new Error('No intake record found in Postgres.');\nconst doc = $('Fetch Paperless Document').first().json || {};\nconst classTagMap = JSON.parse($env.PAPERLESS_TAG_CLASS_MAP_JSON || '{}');\nconst kindTagMap = JSON.parse($env.PAPERLESS_TAG_SUBMISSION_KIND_MAP_JSON || '{}');\nconst paperKindDocTypeMap = JSON.parse($env.PAPERLESS_DOCUMENT_TYPE_PAPER_KIND_MAP_JSON || '{}');\nconst classCorrespondentMap = JSON.parse($env.PAPERLESS_CORRESPONDENT_CLASS_MAP_JSON || '{}');\nconst currentTags = Array.isArray(doc.tags) ? doc.tags.map(Number).filter(Number.isFinite) : [];\nconst merged = new Set(currentTags);\nfor (const id of [$env.PAPERLESS_TAG_SCHOOL, $env.PAPERLESS_TAG_ASSIGNMENTS, $env.PAPERLESS_TAG_TELEGRAM]) {\n  const n = Number(id);\n  if (Number.isFinite(n) && n > 0) merged.add(n);\n}\nconst classTag = Number(classTagMap[intake.class_name]);\nif (Number.isFinite(classTag) && classTag > 0) merged.add(classTag);\nconst kindKey = String(intake.submission_kind || '').trim().toLowerCase();\nconst kindTag = Number(kindTagMap[kindKey]);\nif (Number.isFinite(kindTag) && kindTag > 0) merged.add(kindTag);\nconst title = [intake.class_name, intake.assignment_name, intake.submission_kind].filter(Boolean).join(' \u2014 ');\nconst payload = { title, tags: Array.from(merged) };\nconst documentType = Number(paperKindDocTypeMap[intake.paper_kind]);\nif (Number.isFinite(documentType) && documentType > 0) payload.document_type = documentType;\nconst correspondent = Number(classCorrespondentMap[intake.class_name]);\nif (Number.isFinite(correspondent) && correspondent > 0) payload.correspondent = correspondent;\nreturn [{ json: {\n  intake_id: intake.intake_id,\n  document_id: doc.id,\n  payload,\n  title,\n  final_tag_ids: payload.tags,\n  class_name: intake.class_name,\n  assignment_name: intake.assignment_name,\n  submission_kind: intake.submission_kind\n} }];"
      },
      "id": "build-paperless-update",
      "name": "Build Paperless Update",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        140,
        0
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "={{($env.PAPERLESS_BASE_URL || 'https://paperless.paccoco.com').replace(/\\/$/, '') + '/api/documents/' + $json.document_id + '/'}}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{'Token ' + $env.PAPERLESS_API_TOKEN}}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "jsonBody": "={{$json.payload}}",
        "options": {
          "timeout": 120000
        }
      },
      "id": "update-paperless-document",
      "name": "Update Paperless Document",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        400,
        0
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE school_paperless_intake SET paperless_document_id = {{ Number($json.id || $('Build Paperless Update').first().json.document_id) }}, paperless_title = '{{ $('Build Paperless Update').first().json.title.replace(/'/g, \"''\") }}', status = 'enriched', enriched_at = NOW(), updated_at = NOW() WHERE intake_id = '{{ $('Build Paperless Update').first().json.intake_id.replace(/'/g, \"''\") }}';"
      },
      "id": "pg-mark-enriched",
      "name": "Postgres Mark Enriched",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        660,
        0
      ],
      "credentials": {
        "postgres": {
          "id": "SETUP_REQUIRED",
          "name": "Shared Postgres"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "\nconst update = $('Build Paperless Update').first().json;\nreturn [{ json: {\n  ok: true,\n  intake_id: update.intake_id,\n  document_id: update.document_id,\n  title: update.title,\n  final_tag_ids: update.final_tag_ids,\n  status: 'enriched'\n} }];"
      },
      "id": "return-enrichment-success",
      "name": "Return Enrichment Success",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        920,
        0
      ]
    }
  ],
  "connections": {
    "Paperless School Webhook": {
      "main": [
        [
          {
            "node": "Normalize Paperless Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Paperless Webhook": {
      "main": [
        [
          {
            "node": "Fetch Paperless Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Paperless Document": {
      "main": [
        [
          {
            "node": "Extract Intake ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Intake ID": {
      "main": [
        [
          {
            "node": "Postgres Fetch Intake Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Fetch Intake Record": {
      "main": [
        [
          {
            "node": "Build Paperless Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Paperless Update": {
      "main": [
        [
          {
            "node": "Update Paperless Document",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Paperless Document": {
      "main": [
        [
          {
            "node": "Postgres Mark Enriched",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Mark Enriched": {
      "main": [
        [
          {
            "node": "Return Enrichment Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "meta": {
    "templateCredsSetupCompleted": false,
    "artifactVersion": "v1.0"
  },
  "pinData": {},
  "tags": [
    {
      "name": "school"
    },
    {
      "name": "paperless"
    },
    {
      "name": "postgres"
    },
    {
      "name": "metadata"
    }
  ]
}
