{
  "name": "03 \u2014 G\u00f6rev Takibi (Webhook + G\u00fcnl\u00fck Hat\u0131rlatma)",
  "nodes": [
    {
      "parameters": {
        "content": "## \u2705 G\u00f6rev takibi \u2014 verileriniz yerel dosyada\n\nG\u00f6revler bilgisayar\u0131n\u0131zda `n8n/local-files/gorevler.json`\ndosyas\u0131nda tutulur (konteyner i\u00e7indeki ad\u0131 `/files/gorevler.json`).\n\u00dc\u00e7 b\u00f6l\u00fcmden olu\u015fur:\n\n1. **POST /webhook/gorev** \u2192 g\u00f6rev ekle / tamamla / sil\n2. **GET /webhook/gorevler** \u2192 g\u00fcncel listeyi d\u00f6nd\u00fcr\u00fcr\n3. **Her sabah 08:05** \u2192 a\u00e7\u0131k g\u00f6revleri e-posta ile hat\u0131rlat\u0131r\n\n### Kurulum\n1. Kurulum klas\u00f6r\u00fcnde \u00f6rnek dosyay\u0131 kopyalay\u0131n:\n   `cp local-files/gorevler.ornek.json local-files/gorevler.json`\n2. **Hat\u0131rlatmay\u0131 G\u00f6nder (SMTP)** d\u00fc\u011f\u00fcm\u00fcne SMTP credential\n   ba\u011flay\u0131n ve Kimden/Kime adreslerini de\u011fi\u015ftirin (README \u00a74-A).\n3. Workflow'u **Active** yap\u0131n \u2014 webhook'lar ancak aktifken \u00e7al\u0131\u015f\u0131r.",
        "width": 520,
        "height": 460
      },
      "id": "03b23885-4485-4758-8c31-f6fa1cb36206",
      "name": "Not xu1r4",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -620,
        -60
      ]
    },
    {
      "parameters": {
        "content": "## \ud83d\udcf1 Kullan\u0131m \u2014 istedi\u011finiz uygulamadan\n\nG\u00f6rev ekle:\n```\ncurl -X POST http://localhost:5678/webhook/gorev \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"baslik\":\"S\u00fct al\",\"not\":\"markete u\u011fra\"}'\n```\nTamamla / sil (id listede g\u00f6r\u00fcn\u00fcr):\n```\n{\"islem\":\"tamamla\",\"id\":1}\n{\"islem\":\"sil\",\"id\":1}\n```\nListele:\n```\ncurl http://localhost:5678/webhook/gorevler\n```\n\niPhone K\u0131sayollar, Android Tasker/HTTP Shortcuts veya\nherhangi bir uygulama bu adreslere istek atarak g\u00f6rev\nekleyebilir \u2014 ayr\u0131nt\u0131 ve telefon kurulumu: README \u00a76.",
        "width": 520,
        "height": 560
      },
      "id": "f976e910-52e3-4cba-82ed-3dd430a78d32",
      "name": "Not r4zrf",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -620,
        440
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "gorev",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "62edeefc-f18e-4e34-85f9-85f50d616c54",
      "name": "G\u00f6rev Webhook (POST)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        40,
        120
      ]
    },
    {
      "parameters": {
        "fileSelector": "/files/gorevler.json",
        "options": {}
      },
      "id": "acebb8a7-33e0-4eca-9ce2-eb233768cc27",
      "name": "G\u00f6rev Dosyas\u0131n\u0131 Oku",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        260,
        120
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "fromJson",
        "options": {}
      },
      "id": "e21bcebd-d570-46de-a714-659b6b8cfaee",
      "name": "Dosyadan \u00c7\u0131kar",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        480,
        120
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// Webhook'tan gelen iste\u011fe g\u00f6re g\u00f6rev listesini g\u00fcnceller.\n// Desteklenen i\u015flemler: ekle (varsay\u0131lan), tamamla, sil.\nconst okunan = $input.first().json;\nconst mevcut = (okunan.data && okunan.data.gorevler) || okunan.gorevler || [];\nconst gorevler = Array.isArray(mevcut) ? [...mevcut] : [];\n\nconst govde = $('G\u00f6rev Webhook (POST)').first().json.body || {};\nconst islem = String(govde.islem || 'ekle').toLowerCase();\nlet mesaj = '';\n\nif (islem === 'ekle') {\n  const baslik = String(govde.baslik || '').trim();\n  if (!baslik) {\n    mesaj = 'HATA: \"baslik\" alan\u0131 zorunlu.';\n  } else {\n    const yeniId = gorevler.reduce((m, g) => Math.max(m, Number(g.id) || 0), 0) + 1;\n    gorevler.push({\n      id: yeniId,\n      baslik,\n      not: String(govde.not || ''),\n      durum: 'acik',\n      olusturulma: new Date().toISOString(),\n    });\n    mesaj = `G\u00f6rev eklendi (#${yeniId}): ${baslik}`;\n  }\n} else if (islem === 'tamamla' || islem === 'sil') {\n  const id = Number(govde.id);\n  const gorev = gorevler.find((g) => Number(g.id) === id);\n  if (!gorev) {\n    mesaj = `HATA: #${id} numaral\u0131 g\u00f6rev bulunamad\u0131.`;\n  } else if (islem === 'tamamla') {\n    gorev.durum = 'tamam';\n    gorev.tamamlanma = new Date().toISOString();\n    mesaj = `G\u00f6rev tamamland\u0131 (#${id}): ${gorev.baslik}`;\n  } else {\n    gorevler.splice(gorevler.indexOf(gorev), 1);\n    mesaj = `G\u00f6rev silindi (#${id}): ${gorev.baslik}`;\n  }\n} else {\n  mesaj = `HATA: bilinmeyen i\u015flem \"${islem}\". Ge\u00e7erli i\u015flemler: ekle, tamamla, sil.`;\n}\n\nconst acikGorevSayisi = gorevler.filter((g) => g.durum !== 'tamam').length;\nreturn [{ json: { gorevler, mesaj, acikGorevSayisi } }];"
      },
      "id": "012f1b0c-6e96-4a75-bad2-a6ef122e2db4",
      "name": "G\u00f6rev Listesini G\u00fcncelle",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        120
      ]
    },
    {
      "parameters": {
        "jsCode": "// Dosyaya yaln\u0131zca g\u00f6rev listesi yaz\u0131l\u0131r; mesaj gibi alanlar d\u0131\u015far\u0131da kal\u0131r.\nreturn [{ json: { gorevler: $input.first().json.gorevler } }];"
      },
      "id": "98f081bb-c430-4ef6-88db-570a09318d06",
      "name": "Dosya \u0130\u00e7eri\u011fini Haz\u0131rla",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        920,
        120
      ]
    },
    {
      "parameters": {
        "operation": "toJson",
        "mode": "each",
        "options": {
          "format": true,
          "fileName": "gorevler.json"
        }
      },
      "id": "8644c274-9ade-4a51-96df-458847afd0ef",
      "name": "JSON Dosyas\u0131na \u00c7evir",
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        1140,
        120
      ]
    },
    {
      "parameters": {
        "operation": "write",
        "fileName": "/files/gorevler.json",
        "dataPropertyName": "data",
        "options": {}
      },
      "id": "3fb2d43b-64a4-4e71-878f-ad89466090c1",
      "name": "G\u00f6rev Dosyas\u0131n\u0131 Yaz",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        1360,
        120
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ ok: true, mesaj: $('G\u00f6rev Listesini G\u00fcncelle').first().json.mesaj, acikGorevSayisi: $('G\u00f6rev Listesini G\u00fcncelle').first().json.acikGorevSayisi }) }}",
        "options": {}
      },
      "id": "befab8ad-b117-473e-a2ac-2dc60c1a1bad",
      "name": "Yan\u0131t Ver",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1580,
        120
      ]
    },
    {
      "parameters": {
        "httpMethod": "GET",
        "path": "gorevler",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "8b9a0d78-2422-4ac3-9606-4e059e75be36",
      "name": "Liste Webhook (GET)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        40,
        420
      ]
    },
    {
      "parameters": {
        "fileSelector": "/files/gorevler.json",
        "options": {}
      },
      "id": "da2579ea-5b6b-403b-90c5-ec3ca33b9aeb",
      "name": "G\u00f6rev Dosyas\u0131n\u0131 Oku (Liste)",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        260,
        420
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "fromJson",
        "options": {}
      },
      "id": "5362c711-641f-4462-9ed8-60d79d5c117a",
      "name": "Dosyadan \u00c7\u0131kar (Liste)",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        480,
        420
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify(($json.data && $json.data.gorevler) || $json.gorevler || []) }}",
        "options": {}
      },
      "id": "a164fe11-a9d0-4175-83d7-0d9d41190949",
      "name": "Listeyi Yan\u0131tla",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        700,
        420
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "triggerAtHour": 8,
              "triggerAtMinute": 5
            }
          ]
        }
      },
      "id": "0f41b41e-ac1b-4e5d-95ae-8e5a933edc8a",
      "name": "Her Sabah 08:05",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        40,
        680
      ]
    },
    {
      "parameters": {
        "fileSelector": "/files/gorevler.json",
        "options": {}
      },
      "id": "872c9504-15f4-428f-a995-bcbae01465e1",
      "name": "G\u00f6rev Dosyas\u0131n\u0131 Oku (Hat\u0131rlatma)",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        260,
        680
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "fromJson",
        "options": {}
      },
      "id": "9881c2c4-877b-4104-85c1-af6083763345",
      "name": "Dosyadan \u00c7\u0131kar (Hat\u0131rlatma)",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        480,
        680
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// A\u00e7\u0131k g\u00f6revlerden T\u00fcrk\u00e7e bir HTML hat\u0131rlatma maili haz\u0131rlar.\nconst esc = (s) => String(s ?? '').replace(/[&<>]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]));\n\nconst okunan = $input.first().json;\nconst ham = (okunan.data && okunan.data.gorevler) || okunan.gorevler || [];\nconst acik = (Array.isArray(ham) ? ham : []).filter((g) => g && g.durum !== 'tamam');\n\nconst bugun = new Date().toLocaleDateString('tr-TR', {\n  weekday: 'long', day: 'numeric', month: 'long',\n});\n\nlet html;\nif (acik.length === 0) {\n  html = '<div style=\"font-family:sans-serif\"><h2>\u2705 G\u00f6revler</h2><p>Bug\u00fcn i\u00e7in a\u00e7\u0131k g\u00f6rev yok. \ud83c\udf89</p></div>';\n} else {\n  const satirlar = acik\n    .map((g) => `<li style=\"margin:4px 0\"><b>#${g.id}</b> ${esc(g.baslik)}${g.not ? ` \u2014 <span style=\"color:#555\">${esc(g.not)}</span>` : ''}</li>`)\n    .join('');\n  html = [\n    '<div style=\"font-family:sans-serif;max-width:640px\">',\n    `<h2>\u2705 Bug\u00fcn\u00fcn g\u00f6revleri \u2014 ${bugun}</h2>`,\n    `<ol style=\"padding-left:20px\">${satirlar}</ol>`,\n    '<p style=\"color:#999;font-size:12px\">Tamamlamak i\u00e7in: POST http://localhost:5678/webhook/gorev g\u00f6vde: {\"islem\":\"tamamla\",\"id\":1}</p>',\n    '</div>',\n  ].join('');\n}\n\nreturn [{ json: { konu: `[n8n] \u2705 Bug\u00fcn\u00fcn g\u00f6revleri (${acik.length} a\u00e7\u0131k) \u2014 ${bugun}`, html } }];"
      },
      "id": "76ecb001-604d-4d14-8689-d433938d3a4c",
      "name": "Hat\u0131rlatma Metnini Haz\u0131rla",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        680
      ]
    },
    {
      "parameters": {
        "fromEmail": "sizin-adresiniz@gmail.com",
        "toEmail": "sizin-adresiniz@gmail.com",
        "subject": "={{ $json.konu }}",
        "emailFormat": "html",
        "html": "={{ $json.html }}",
        "options": {
          "appendAttribution": false
        }
      },
      "id": "1d6d1ec0-67aa-4a57-9365-c8ed9ca11321",
      "name": "Hat\u0131rlatmay\u0131 G\u00f6nder (SMTP)",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        920,
        680
      ]
    }
  ],
  "connections": {
    "G\u00f6rev Webhook (POST)": {
      "main": [
        [
          {
            "node": "G\u00f6rev Dosyas\u0131n\u0131 Oku",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G\u00f6rev Dosyas\u0131n\u0131 Oku": {
      "main": [
        [
          {
            "node": "Dosyadan \u00c7\u0131kar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dosyadan \u00c7\u0131kar": {
      "main": [
        [
          {
            "node": "G\u00f6rev Listesini G\u00fcncelle",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G\u00f6rev Listesini G\u00fcncelle": {
      "main": [
        [
          {
            "node": "Dosya \u0130\u00e7eri\u011fini Haz\u0131rla",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dosya \u0130\u00e7eri\u011fini Haz\u0131rla": {
      "main": [
        [
          {
            "node": "JSON Dosyas\u0131na \u00c7evir",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JSON Dosyas\u0131na \u00c7evir": {
      "main": [
        [
          {
            "node": "G\u00f6rev Dosyas\u0131n\u0131 Yaz",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G\u00f6rev Dosyas\u0131n\u0131 Yaz": {
      "main": [
        [
          {
            "node": "Yan\u0131t Ver",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Liste Webhook (GET)": {
      "main": [
        [
          {
            "node": "G\u00f6rev Dosyas\u0131n\u0131 Oku (Liste)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G\u00f6rev Dosyas\u0131n\u0131 Oku (Liste)": {
      "main": [
        [
          {
            "node": "Dosyadan \u00c7\u0131kar (Liste)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dosyadan \u00c7\u0131kar (Liste)": {
      "main": [
        [
          {
            "node": "Listeyi Yan\u0131tla",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Her Sabah 08:05": {
      "main": [
        [
          {
            "node": "G\u00f6rev Dosyas\u0131n\u0131 Oku (Hat\u0131rlatma)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "G\u00f6rev Dosyas\u0131n\u0131 Oku (Hat\u0131rlatma)": {
      "main": [
        [
          {
            "node": "Dosyadan \u00c7\u0131kar (Hat\u0131rlatma)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dosyadan \u00c7\u0131kar (Hat\u0131rlatma)": {
      "main": [
        [
          {
            "node": "Hat\u0131rlatma Metnini Haz\u0131rla",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hat\u0131rlatma Metnini Haz\u0131rla": {
      "main": [
        [
          {
            "node": "Hat\u0131rlatmay\u0131 G\u00f6nder (SMTP)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}