{
  "name": "Automatyzacja dokumentacji API z commit\u00f3w",
  "nodes": [
    {
      "id": "1",
      "name": "GitHub Trigger (push)",
      "type": "n8n-nodes-base.githubTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "parameters": {
        "owner": "twoj-login",
        "repository": "nazwa-repo",
        "events": [
          "push"
        ]
      },
      "notes": "Uruchamia workflow przy ka\u017cdym pushu do ga\u0142\u0119zi g\u0142\u00f3wnej. W wersji demo mo\u017cna zamieni\u0107 na Manual Trigger."
    },
    {
      "id": "2",
      "name": "Filtruj: tylko pliki tras/kontroler\u00f3w",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "parameters": {
        "language": "javaScript",
        "jsCode": "// Bierze list\u0119 zmienionych plik\u00f3w z payloadu GitHub Trigger\n// i przepuszcza dalej tylko te, kt\u00f3re faktycznie definiuj\u0105 endpointy API\nconst commits = $input.first().json.commits || [];\nconst wzorzec = /routes\\/|controllers\\/|api\\//i;\n\nconst zmienionePliki = new Set();\nfor (const commit of commits) {\n  (commit.added || []).forEach(f => zmienionePliki.add(f));\n  (commit.modified || []).forEach(f => zmienionePliki.add(f));\n}\n\nconst istotne = [...zmienionePliki].filter(f => wzorzec.test(f));\n\nif (istotne.length === 0) {\n  // Nic istotnego si\u0119 nie zmieni\u0142o \u2014 zatrzymaj workflow, nie generuj dokumentacji na pr\u00f3\u017cno\n  return [];\n}\n\nreturn istotne.map(plik => ({ json: { plik } }));"
      },
      "notes": "Kluczowy krok jako\u015bciowy: bez tego filtra AI dostawa\u0142oby do analizy KA\u017bDY commit (tak\u017ce zmiany w CSS czy README), co marnuje wywo\u0142ania API i psuje trafno\u015b\u0107 dokumentacji."
    },
    {
      "id": "3",
      "name": "Pobierz zawarto\u015b\u0107 pliku (GitHub)",
      "type": "n8n-nodes-base.github",
      "typeVersion": 1,
      "position": [
        440,
        0
      ],
      "parameters": {
        "resource": "file",
        "operation": "get",
        "owner": "twoj-login",
        "repository": "nazwa-repo",
        "filePath": "={{$json.plik}}"
      },
      "notes": "Pobiera aktualn\u0105 (po commicie) zawarto\u015b\u0107 zmienionego pliku z endpointami, \u017ceby AI dokumentowa\u0142o stan po zmianie, nie diff."
    },
    {
      "id": "4",
      "name": "Wygeneruj dokumentacj\u0119 (AI)",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1,
      "position": [
        660,
        0
      ],
      "parameters": {
        "resource": "chat",
        "model": "gpt-4o",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "Jeste\u015b generatorem dokumentacji API. Odpowiadasz WY\u0141\u0104CZNIE poprawnym Markdownem, bez komentarzy poza tre\u015bci\u0105 dokumentacji."
            },
            {
              "role": "user",
              "content": "Udokumentuj poni\u017csze endpointy API w sp\u00f3jnym formacie.\n\nKod / lista endpoint\u00f3w:\n{{$json.content}}\n\nDla ka\u017cdego endpointu podaj:\n- Metoda i \u015bcie\u017cka\n- Opis (jedno zdanie, po co ten endpoint istnieje, nie tylko co robi)\n- Parametry / body: tabela nazwa | typ | wymagany | opis\n- Przyk\u0142adowe \u017c\u0105danie (JSON)\n- Przyk\u0142adowa odpowied\u017a sukcesu (JSON + kod statusu)\n- Mo\u017cliwe b\u0142\u0119dy: kody statusu + kiedy wyst\u0119puj\u0105\n- Wymagana autoryzacja: tak/nie + poziom uprawnie\u0144\n\nNa ko\u0144cu dodaj tabel\u0119 zbiorcz\u0105 wszystkich endpoint\u00f3w jako szybki spis tre\u015bci."
            }
          ]
        }
      },
      "notes": "To jest dok\u0142adnie prompt z prompts/dokumentacja/dokumentacja-api.md \u2014 ten sam plik markdown jest tu 'wklejony' jako tre\u015b\u0107 wiadomo\u015bci. Baza prompt\u00f3w i ten workflow u\u017cywaj\u0105 jednego, wsp\u00f3lnego \u017ar\u00f3d\u0142a prawdy."
    },
    {
      "id": "5",
      "name": "Waliduj i sformatuj wynik",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        880,
        0
      ],
      "parameters": {
        "language": "javaScript",
        "jsCode": "// Prosta walidacja: czy AI faktycznie zwr\u00f3ci\u0142o markdown z nag\u0142\u00f3wkami,\n// a nie np. przeprosiny albo pust\u0105 odpowied\u017a.\nconst tresc = $json.message?.content || $json.text || '';\n\nif (!tresc.includes('#') || tresc.length < 50) {\n  throw new Error('Wygenerowana dokumentacja wygl\u0105da podejrzanie kr\u00f3tko/niepoprawnie \u2014 zatrzymuj\u0119 workflow zamiast commitowa\u0107 \u015bmieci.');\n}\n\nreturn [{ json: { dokumentacja: tresc, plikZrodlowy: $('Filtruj: tylko pliki tras/kontroler\u00f3w').item.json.plik } }];"
      },
      "notes": "To jest node z Metodologii projektu: 'walidacja przed commitem' \u2014 zabezpieczenie przed automatycznym zapisaniem halucynacji do repozytorium bez nadzoru cz\u0142owieka."
    },
    {
      "id": "6",
      "name": "Zapisz docs/API.md (commit)",
      "type": "n8n-nodes-base.github",
      "typeVersion": 1,
      "position": [
        1100,
        0
      ],
      "parameters": {
        "resource": "file",
        "operation": "edit",
        "owner": "twoj-login",
        "repository": "nazwa-repo",
        "filePath": "docs/API.md",
        "fileContent": "={{$json.dokumentacja}}",
        "commitMessage": "docs: automatyczna aktualizacja dokumentacji API ({{$json.plikZrodlowy}})",
        "branch": "docs/auto-api-update"
      },
      "notes": "Commit idzie na osobn\u0105 ga\u0142\u0105\u017a, nie prosto na main \u2014 \u015bwiadome ograniczenie automatyzacji, patrz punkt 3 w opisie workflow (human-in-the-loop przez PR)."
    },
    {
      "id": "7",
      "name": "Powiadom zesp\u00f3\u0142 (Slack)",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        1320,
        0
      ],
      "parameters": {
        "resource": "message",
        "operation": "post",
        "channel": "#dev-docs",
        "text": "\ud83d\udcc4 Dokumentacja API zaktualizowana automatycznie na podstawie ostatniego commita ({{$json.plikZrodlowy}}). Sprawd\u017a i zmerguj ga\u0142\u0105\u017a docs/auto-api-update."
      },
      "notes": "Powiadomienie zamiast cichej automatyzacji \u2014 zesp\u00f3\u0142 zawsze wie, \u017ce co\u015b si\u0119 zmieni\u0142o i musi to zatwierdzi\u0107."
    }
  ],
  "connections": {
    "GitHub Trigger (push)": {
      "main": [
        [
          {
            "node": "Filtruj: tylko pliki tras/kontroler\u00f3w",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filtruj: tylko pliki tras/kontroler\u00f3w": {
      "main": [
        [
          {
            "node": "Pobierz zawarto\u015b\u0107 pliku (GitHub)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pobierz zawarto\u015b\u0107 pliku (GitHub)": {
      "main": [
        [
          {
            "node": "Wygeneruj dokumentacj\u0119 (AI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wygeneruj dokumentacj\u0119 (AI)": {
      "main": [
        [
          {
            "node": "Waliduj i sformatuj wynik",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Waliduj i sformatuj wynik": {
      "main": [
        [
          {
            "node": "Zapisz docs/API.md (commit)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Zapisz docs/API.md (commit)": {
      "main": [
        [
          {
            "node": "Powiadom zesp\u00f3\u0142 (Slack)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}