{
  "name": "ShopAnalyticsVersionFinal",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 6 * * *"
            }
          ]
        }
      },
      "id": "46733ac4-4db2-445e-aa87-f2110e704624",
      "name": "D\u00e9clencheur 6h00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        -1328,
        144
      ]
    },
    {
      "parameters": {
        "jsCode": "await new Promise(r => setTimeout(r, 500));\nreturn [{\n  json: {\n    status: 'trained',\n    model_version: '1.0.0',\n    trained_at: new Date().toISOString(),\n    samples_used: 142\n  }\n}];"
      },
      "id": "37109df6-9a9d-4d4a-8d93-e36663a8de61",
      "name": "R\u00e9entra\u00eenement Mod\u00e8le ML",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1104,
        144
      ],
      "notes": "\u26a0\ufe0f MOCK \u2014 Remplacer par HTTP Request POST /api/train"
    },
    {
      "parameters": {
        "jsCode": "const profiles = ['Familles', 'Jeunes adultes', 'Seniors', 'Professionnels'];\nconst niveaux = ['Faible', 'Mod\u00e9r\u00e9', '\u00c9lev\u00e9', 'Tr\u00e8s \u00e9lev\u00e9'];\nconst visiteurs = Math.floor(Math.random() * 300) + 350;\n\nreturn [{\n  json: {\n    visiteurs_prevus: visiteurs,\n    profil_dominant: profiles[Math.floor(Math.random() * profiles.length)],\n    niveau_affluence: niveaux[Math.floor(Math.random() * niveaux.length)],\n    heure_pointe_debut: '14:00',\n    heure_pointe_fin: '18:00',\n    date_prevision: new Date().toISOString().split('T')[0]\n  }\n}];"
      },
      "id": "6065d42e-a37c-4c97-a035-004dc66eed62",
      "name": "Pr\u00e9diction Visiteurs",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -880,
        144
      ],
      "notes": "\u26a0\ufe0f MOCK \u2014 Remplacer par HTTP Request POST /api/predict"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst prompt = `Tu es l assistant analytique de ShopAnalytics pour Anavid Store 360. Voici les predictions de frequentation pour aujourd hui (${data.date_prevision}) : Visiteurs prevus : ${data.visiteurs_prevus}. Profil dominant : ${data.profil_dominant}. Niveau d affluence : ${data.niveau_affluence}. Heure de pointe : ${data.heure_pointe_debut} a ${data.heure_pointe_fin}. Redige un message professionnel et concis de 4 a 5 phrases en francais a destination de l equipe du magasin. Mentionne le nombre de visiteurs, le profil dominant, le niveau d affluence et donne 1 a 2 recommandations concretes sur la gestion du personnel ou des caisses.`;\n\nreturn [{\n  json: {\n    prompt: prompt,\n    prediction: data\n  }\n}];"
      },
      "id": "fc7c823d-2696-45f3-a1be-5854df761833",
      "name": "Pr\u00e9parer Prompt Ollama",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -656,
        144
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $('Pr\u00e9parer Prompt Ollama').item.json.prompt }}"
      },
      "id": "5c36f2f4-3aa3-46bb-9eab-71f015d03fa2",
      "name": "Basic LLM Chain",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.4,
      "position": [
        -432,
        144
      ]
    },
    {
      "parameters": {
        "model": "=llama3.2:3b-instruct-q4_K_M",
        "options": {
          "temperature": 0.1,
          "numCtx": 4096,
          "numPredict": 300
        }
      },
      "id": "41ebc6ab-d1fc-4907-8965-6e56cc2a83d7",
      "name": "Ollama Model",
      "type": "@n8n/n8n-nodes-langchain.lmOllama",
      "typeVersion": 1,
      "position": [
        -352,
        368
      ],
      "credentials": {
        "ollamaApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Formate le payload attendu par Django SSE (receive_daily_report)\n// et par le Dashboard.tsx (PredictionData interface)\nconst llmText = $input.first().json.text?.trim();\nconst pred = $('Pr\u00e9parer Prompt Ollama').first().json.prediction;\n\nconst payload = {\n  type: 'llm_report',\n  date: pred.date_prevision,\n  generated_at: new Date().toISOString(),\n  message: llmText,\n  prediction: {\n    visiteurs_prevus: pred.visiteurs_prevus,\n    profil_dominant:  pred.profil_dominant,\n    niveau_affluence: pred.niveau_affluence,\n    heure_pointe:     `${pred.heure_pointe_debut} - ${pred.heure_pointe_fin}`\n  }\n};\n\nreturn [{ json: payload }];"
      },
      "id": "08b12b16-2b6b-42b5-a2af-4e32a65ef770",
      "name": "Formater Payload SSE",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -80,
        144
      ],
      "notes": "Formate exactement le PredictionData attendu par Dashboard.tsx et Django SSE"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://shopanalytics-django-api:8000/api/daily-report/",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json) }}",
        "options": {
          "timeout": 10000
        }
      },
      "id": "c28cff01-6ec5-4a9e-b5dc-088d20cf6e5c",
      "name": "Push SSE \u2192 Django",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        144,
        -48
      ],
      "notes": "POST /api/daily-report/ \u2192 Django notifie tous les clients SSE connect\u00e9s (Dashboard + ChatIA)"
    },
    {
      "parameters": {
        "jsCode": "// Appel HTTP via $http natif de N8N (fetch et http sont bloqu\u00e9s)\nconst llmText = $input.first().json.text?.trim();\nconst prediction = $('Pr\u00e9parer Prompt Ollama').first().json.prediction;\n\nlet chatAnswer = llmText;\n\ntry {\n  const response = await $http.request({\n    method: 'POST',\n    url: 'http://django_api:8000/api/chat/',\n    headers: { 'Content-Type': 'application/json' },\n    body: {\n      question: `Rapport quotidien automatique du ${prediction.date_prevision} : ${llmText}`\n    },\n    json: true\n  });\n  chatAnswer = response.answer || llmText;\n} catch (err) {\n  console.log('Django indisponible, fallback LLM : ' + err.message);\n}\n\nconst notification = {\n  id: Date.now(),\n  date: prediction.date_prevision,\n  generated_at: new Date().toISOString(),\n  visiteurs_prevus: prediction.visiteurs_prevus,\n  profil_dominant: prediction.profil_dominant,\n  niveau_affluence: prediction.niveau_affluence,\n  heure_pointe: `${prediction.heure_pointe_debut} - ${prediction.heure_pointe_fin}`,\n  message: chatAnswer,\n  model: 'llama3.2:3b-instruct-q4_K_M',\n  type: 'daily_report'\n};\n\nreturn [{ json: notification }];"
      },
      "id": "6835e565-0baa-423b-828b-aa34e521f783",
      "name": "Envoyer au Chatbot",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        144,
        336
      ],
      "notes": "Envoie le message LLM au RAG Django \u2192 chatbot Ionic"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://shopanalytics-django-api:8000/api/send-fcm/",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "=json",
        "bodyParameters": {
          "parameters": [
            {}
          ]
        },
        "jsonBody": "={{\n{\n  title: \"\ud83d\udcca Rapport Quotidien - \" + $json.date,\n  body: $json.message,\n  data: {\n    type: $json.type,\n    date: $json.date,\n    visiteurs_prevus: $json.prediction.visiteurs_prevus,\n    profil_dominant: $json.prediction.profil_dominant,\n    niveau_affluence: $json.prediction.niveau_affluence,\n    heure_pointe: $json.prediction.heure_pointe\n  }\n}\n}}",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        144,
        144
      ],
      "id": "ae892a54-366b-44ed-806c-4b59a9330412",
      "name": "Envoyer FCM"
    }
  ],
  "connections": {
    "D\u00e9clencheur 6h00": {
      "main": [
        [
          {
            "node": "R\u00e9entra\u00eenement Mod\u00e8le ML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "R\u00e9entra\u00eenement Mod\u00e8le ML": {
      "main": [
        [
          {
            "node": "Pr\u00e9diction Visiteurs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pr\u00e9diction Visiteurs": {
      "main": [
        [
          {
            "node": "Pr\u00e9parer Prompt Ollama",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pr\u00e9parer Prompt Ollama": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Formater Payload SSE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formater Payload SSE": {
      "main": [
        [
          {
            "node": "Envoyer au Chatbot",
            "type": "main",
            "index": 0
          },
          {
            "node": "Envoyer FCM",
            "type": "main",
            "index": 0
          },
          {
            "node": "Push SSE \u2192 Django",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "6a1669e0-7e1c-4cd9-a2ab-a0bcbe209008",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodeGroups": [],
  "id": "haD6hCVYA8oVdIAB",
  "tags": [
    {
      "updatedAt": "2026-06-17T22:52:38.300Z",
      "createdAt": "2026-06-17T22:52:38.300Z",
      "id": "8mEYfMeCjGpMZEBP",
      "name": "ShopAnalytics"
    },
    {
      "updatedAt": "2026-06-17T22:52:38.337Z",
      "createdAt": "2026-06-17T22:52:38.337Z",
      "id": "S9YsIgrS8BAcLO13",
      "name": "Sprint1"
    }
  ]
}