Files
portfolio/docs/N8N_INTEGRATION.md
2026-01-07 14:30:00 +01:00

17 KiB

🚀 n8n Integration Guide - Complete Setup

Übersicht

Dieses Portfolio nutzt n8n für:

  • Echtzeit-Aktivitätsanzeige (Coding, Musik, Gaming, etc.)
  • 💬 AI-Chatbot (mit OpenAI/Anthropic)
  • 📊 Aktivitäts-Tracking (GitHub, Spotify, Netflix, etc.)
  • 🎮 Gaming-Status (Steam, Discord)
  • 📧 Automatische Benachrichtigungen

🎨 Coole Ideen für Integrationen

1. GitHub Activity Feed 🔨

Was es zeigt:

  • "Currently coding: Portfolio Website"
  • "Last commit: 5 minutes ago"
  • "Working on: feature/n8n-integration"
  • Programming language (TypeScript, Python, etc.)

n8n Workflow:

GitHub Webhook → Extract Data → Update Database → Display on Site

2. Spotify Now Playing 🎵

Was es zeigt:

  • Aktueller Song + Artist
  • Album Cover (rotierend animiert!)
  • Fortschrittsbalken
  • "Listening to X since Y minutes"

n8n Workflow:

Cron (every 30s) → Spotify API → Parse Track Data → Update Database

3. Netflix/YouTube/Twitch Watching 📺

Was es zeigt:

  • "Watching: Breaking Bad S05E14"
  • "Streaming: Coding Tutorial"
  • Platform badges (Netflix/YouTube/Twitch)

n8n Workflow:

Trakt.tv API → Get Current Watching → Update Database
Discord Rich Presence → Extract Activity → Update Database

4. Gaming Activity 🎮

Was es zeigt:

  • "Playing: Elden Ring"
  • Platform: Steam/PlayStation/Xbox
  • Play time
  • Achievement notifications

n8n Workflow:

Steam API → Get Current Game → Update Database
Discord Presence → Parse Game → Update Database

5. Mood & Custom Status 😊

Was es zeigt:

  • Emoji mood (😊, 💻, 🏃, 🎮, 😴)
  • Custom message: "Focused on DevOps"
  • Auto-status based on time/activity

n8n Workflow:

Schedule → Determine Status (work hours/break/sleep) → Update Database
Manual Webhook → Set Custom Status → Update Database

6. Smart Notifications 📬

Was es zeigt:

  • "New email from X"
  • "GitHub PR needs review"
  • "Calendar event in 15 min"

n8n Workflow:

Email/Calendar/GitHub → Filter Important → Create Notification → Display

📦 Setup: Datenbank Schema

PostgreSQL Table: activity_status

CREATE TABLE activity_status (
  id SERIAL PRIMARY KEY,
  
  -- Activity
  activity_type VARCHAR(50), -- 'coding', 'listening', 'watching', 'gaming', 'reading'
  activity_details TEXT,
  activity_project VARCHAR(255),
  activity_language VARCHAR(50),
  activity_repo VARCHAR(255),
  
  -- Music
  music_playing BOOLEAN DEFAULT FALSE,
  music_track VARCHAR(255),
  music_artist VARCHAR(255),
  music_album VARCHAR(255),
  music_platform VARCHAR(50), -- 'spotify', 'apple'
  music_progress INTEGER, -- 0-100
  music_album_art TEXT,
  
  -- Watching
  watching_title VARCHAR(255),
  watching_platform VARCHAR(50), -- 'youtube', 'netflix', 'twitch'
  watching_type VARCHAR(50), -- 'video', 'stream', 'movie', 'series'
  
  -- Gaming
  gaming_game VARCHAR(255),
  gaming_platform VARCHAR(50), -- 'steam', 'playstation', 'xbox'
  gaming_status VARCHAR(50), -- 'playing', 'idle'
  
  -- Status
  status_mood VARCHAR(10), -- emoji
  status_message TEXT,
  
  updated_at TIMESTAMP DEFAULT NOW()
);

🔧 n8n Workflows

Workflow 1: GitHub Activity Tracker

Trigger: Webhook bei Push/Commit Frequenz: Echtzeit

{
  "nodes": [
    {
      "name": "GitHub Webhook",
      "type": "n8n-nodes-base.webhook",
      "parameters": {
        "path": "github-activity",
        "method": "POST"
      }
    },
    {
      "name": "Extract Commit Data",
      "type": "n8n-nodes-base.function",
      "parameters": {
        "functionCode": "const commit = items[0].json;\nreturn [\n  {\n    json: {\n      activity_type: 'coding',\n      activity_details: commit.head_commit.message,\n      activity_project: commit.repository.name,\n      activity_language: 'TypeScript',\n      activity_repo: commit.repository.html_url,\n      updated_at: new Date().toISOString()\n    }\n  }\n];"
      }
    },
    {
      "name": "Update Database",
      "type": "n8n-nodes-base.postgres",
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO activity_status (activity_type, activity_details, activity_project, activity_language, activity_repo, updated_at) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO UPDATE SET activity_type = $1, activity_details = $2, activity_project = $3, activity_language = $4, activity_repo = $5, updated_at = $6 WHERE activity_status.id = 1"
      }
    }
  ]
}

Setup in GitHub:

  1. Gehe zu deinem Repository → Settings → Webhooks
  2. Add webhook: https://your-n8n-instance.com/webhook/github-activity
  3. Content type: application/json
  4. Events: Push events

Workflow 2: Spotify Now Playing

Trigger: Cron (alle 30 Sekunden)

{
  "nodes": [
    {
      "name": "Schedule",
      "type": "n8n-nodes-base.cron",
      "parameters": {
        "cronExpression": "*/30 * * * * *"
      }
    },
    {
      "name": "Spotify API",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "url": "https://api.spotify.com/v1/me/player/currently-playing",
        "method": "GET",
        "authentication": "oAuth2",
        "headers": {
          "Authorization": "Bearer {{$credentials.spotify.accessToken}}"
        }
      }
    },
    {
      "name": "Parse Track Data",
      "type": "n8n-nodes-base.function",
      "parameters": {
        "functionCode": "const track = items[0].json;\nif (!track || !track.is_playing) {\n  return [{ json: { music_playing: false } }];\n}\n\nreturn [\n  {\n    json: {\n      music_playing: true,\n      music_track: track.item.name,\n      music_artist: track.item.artists[0].name,\n      music_album: track.item.album.name,\n      music_platform: 'spotify',\n      music_progress: Math.round((track.progress_ms / track.item.duration_ms) * 100),\n      music_album_art: track.item.album.images[0].url,\n      updated_at: new Date().toISOString()\n    }\n  }\n];"
      }
    },
    {
      "name": "Update Database",
      "type": "n8n-nodes-base.postgres",
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE activity_status SET music_playing = $1, music_track = $2, music_artist = $3, music_album = $4, music_platform = $5, music_progress = $6, music_album_art = $7, updated_at = $8 WHERE id = 1"
      }
    }
  ]
}

Spotify API Setup:

  1. Gehe zu https://developer.spotify.com/dashboard
  2. Create App
  3. Add Redirect URI: https://your-n8n-instance.com/oauth/callback
  4. Kopiere Client ID & Secret in n8n Credentials
  5. Scopes: user-read-currently-playing, user-read-playback-state

Workflow 3: AI Chatbot mit OpenAI

Trigger: Webhook bei Chat-Message

{
  "nodes": [
    {
      "name": "Chat Webhook",
      "type": "n8n-nodes-base.webhook",
      "parameters": {
        "path": "chat",
        "method": "POST"
      }
    },
    {
      "name": "Build Context",
      "type": "n8n-nodes-base.function",
      "parameters": {
        "functionCode": "const userMessage = items[0].json.message;\n\nconst context = `You are Dennis Konkol's AI assistant. Here's information about Dennis:\n\n- Student in Osnabrück, Germany\n- Passionate self-hoster and DevOps enthusiast\n- Skills: Next.js, Flutter, Docker Swarm, Traefik, CI/CD, n8n\n- Runs own infrastructure on IONOS and OVHcloud\n- Projects: Clarity (Flutter dyslexia app), Self-hosted portfolio with Docker Swarm\n- Hobbies: Gaming, Jogging, Experimenting with tech\n- Fun fact: Uses pen & paper for calendar despite automating everything\n\nAnswer questions about Dennis professionally and friendly. Keep answers concise (2-3 sentences).\n\nUser question: ${userMessage}`;\n\nreturn [{ json: { context, userMessage } }];"
      }
    },
    {
      "name": "OpenAI Chat",
      "type": "n8n-nodes-base.openAi",
      "parameters": {
        "resource": "chat",
        "operation": "message",
        "model": "gpt-4",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "={{$node[\"Build Context\"].json[\"context\"]}}"
            },
            {
              "role": "user",
              "content": "={{$node[\"Build Context\"].json[\"userMessage\"]}}"
            }
          ]
        }
      }
    },
    {
      "name": "Return Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "parameters": {
        "responseBody": "={{ { reply: $json.message.content } }}"
      }
    }
  ]
}

OpenAI API Setup:

  1. Gehe zu https://platform.openai.com/api-keys
  2. Create API Key
  3. Add zu n8n Credentials
  4. Wähle Model: gpt-4 oder gpt-3.5-turbo

Workflow 4: Discord/Steam Gaming Status

Trigger: Cron (alle 60 Sekunden)

{
  "nodes": [
    {
      "name": "Schedule",
      "type": "n8n-nodes-base.cron",
      "parameters": {
        "cronExpression": "0 * * * * *"
      }
    },
    {
      "name": "Discord API",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "url": "https://discord.com/api/v10/users/@me",
        "method": "GET",
        "authentication": "oAuth2",
        "headers": {
          "Authorization": "Bot {{$credentials.discord.token}}"
        }
      }
    },
    {
      "name": "Parse Gaming Status",
      "type": "n8n-nodes-base.function",
      "parameters": {
        "functionCode": "const user = items[0].json;\nconst activity = user.activities?.find(a => a.type === 0); // 0 = Playing\n\nif (!activity) {\n  return [{ json: { gaming_game: null, gaming_status: 'idle' } }];\n}\n\nreturn [\n  {\n    json: {\n      gaming_game: activity.name,\n      gaming_platform: 'discord',\n      gaming_status: 'playing',\n      updated_at: new Date().toISOString()\n    }\n  }\n];"
      }
    },
    {
      "name": "Update Database",
      "type": "n8n-nodes-base.postgres",
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE activity_status SET gaming_game = $1, gaming_platform = $2, gaming_status = $3, updated_at = $4 WHERE id = 1"
      }
    }
  ]
}

Workflow 5: Smart Status (Auto-Detect)

Trigger: Cron (alle 5 Minuten)

{
  "nodes": [
    {
      "name": "Schedule",
      "type": "n8n-nodes-base.cron",
      "parameters": {
        "cronExpression": "*/5 * * * *"
      }
    },
    {
      "name": "Determine Status",
      "type": "n8n-nodes-base.function",
      "parameters": {
        "functionCode": "const hour = new Date().getHours();\nconst day = new Date().getDay(); // 0 = Sunday, 6 = Saturday\n\nlet mood = '💻';\nlet message = 'Working on projects';\n\n// Sleep time (0-7 Uhr)\nif (hour >= 0 && hour < 7) {\n  mood = '😴';\n  message = 'Sleeping (probably dreaming of code)';\n}\n// Morning (7-9 Uhr)\nelse if (hour >= 7 && hour < 9) {\n  mood = '☕';\n  message = 'Morning coffee & catching up';\n}\n// Work time (9-17 Uhr, Mo-Fr)\nelse if (hour >= 9 && hour < 17 && day >= 1 && day <= 5) {\n  mood = '💻';\n  message = 'Deep work mode - coding & learning';\n}\n// Evening (17-22 Uhr)\nelse if (hour >= 17 && hour < 22) {\n  mood = '🎮';\n  message = 'Relaxing - gaming or watching shows';\n}\n// Late night (22-24 Uhr)\nelse if (hour >= 22) {\n  mood = '🌙';\n  message = 'Late night coding session';\n}\n// Weekend\nif (day === 0 || day === 6) {\n  mood = '🏃';\n  message = 'Weekend vibes - exploring & experimenting';\n}\n\nreturn [\n  {\n    json: {\n      status_mood: mood,\n      status_message: message,\n      updated_at: new Date().toISOString()\n    }\n  }\n];"
      }
    },
    {
      "name": "Update Database",
      "type": "n8n-nodes-base.postgres",
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE activity_status SET status_mood = $1, status_message = $2, updated_at = $3 WHERE id = 1"
      }
    }
  ]
}

🔌 Frontend API Integration

Update /app/api/n8n/status/route.ts

import { NextResponse } from 'next/server';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export async function GET() {
  try {
    // Fetch from your activity_status table
    const status = await prisma.$queryRaw`
      SELECT * FROM activity_status WHERE id = 1 LIMIT 1
    `;

    if (!status || status.length === 0) {
      return NextResponse.json({
        activity: null,
        music: null,
        watching: null,
        gaming: null,
        status: null,
      });
    }

    const data = status[0];

    return NextResponse.json({
      activity: data.activity_type ? {
        type: data.activity_type,
        details: data.activity_details,
        project: data.activity_project,
        language: data.activity_language,
        repo: data.activity_repo,
        timestamp: data.updated_at,
      } : null,
      music: data.music_playing ? {
        isPlaying: data.music_playing,
        track: data.music_track,
        artist: data.music_artist,
        album: data.music_album,
        platform: data.music_platform,
        progress: data.music_progress,
        albumArt: data.music_album_art,
      } : null,
      watching: data.watching_title ? {
        title: data.watching_title,
        platform: data.watching_platform,
        type: data.watching_type,
      } : null,
      gaming: data.gaming_game ? {
        game: data.gaming_game,
        platform: data.gaming_platform,
        status: data.gaming_status,
      } : null,
      status: data.status_mood ? {
        mood: data.status_mood,
        customMessage: data.status_message,
      } : null,
    });
  } catch (error) {
    console.error('Error fetching activity status:', error);
    return NextResponse.json({
      activity: null,
      music: null,
      watching: null,
      gaming: null,
      status: null,
    }, { status: 500 });
  }
}

Create /app/api/n8n/chat/route.ts

import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const { message } = await request.json();

    // Call your n8n chat webhook
    const response = await fetch(`${process.env.N8N_WEBHOOK_URL}/webhook/chat`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ message }),
    });

    if (!response.ok) {
      throw new Error('n8n webhook failed');
    }

    const data = await response.json();
    return NextResponse.json({ reply: data.reply });
  } catch (error) {
    console.error('Chat API error:', error);
    return NextResponse.json(
      { reply: 'Sorry, I encountered an error. Please try again later.' },
      { status: 500 }
    );
  }
}

🌟 Zusätzliche coole Ideen

1. Live Coding Stats

  • Lines of code today
  • Most used language this week
  • GitHub contribution graph
  • Pull requests merged

2. Coffee Counter

  • Button in n8n Dashboard: "I had coffee"
  • Displays: "3 coffees today"
  • Funny messages bei > 5 cups

3. Mood Tracker

  • Manual mood updates via Discord Bot
  • Shows emoji + custom message
  • Persists über den Tag

4. Auto-DND Status

  • Wenn du in einem Meeting bist (Calendar API)
  • Wenn du fokussiert arbeitest (Pomodoro Timer)
  • Custom status: "🔴 In Deep Work - Back at 15:00"

5. Project Highlights

  • "Currently building: X"
  • "Deployed Y minutes ago"
  • "Last successful build: Z"

6. Social Activity

  • "New blog post: Title"
  • "Trending on Twitter: X mentions"
  • "LinkedIn: Y profile views this week"

📝 Environment Variables

Add to .env.local:

# n8n
N8N_WEBHOOK_URL=https://your-n8n-instance.com
N8N_API_KEY=your_n8n_api_key

# Spotify
SPOTIFY_CLIENT_ID=your_spotify_client_id
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret

# OpenAI
OPENAI_API_KEY=your_openai_api_key

# Discord (optional)
DISCORD_BOT_TOKEN=your_discord_bot_token

# GitHub (optional)
GITHUB_WEBHOOK_SECRET=your_github_webhook_secret

🚀 Quick Start

  1. Setup Database:

    psql -U postgres -d portfolio_dev -f setup_activity_status.sql
    
  2. Create n8n Workflows:

    • Import workflows via n8n UI
    • Configure credentials
    • Activate workflows
  3. Update API Routes:

    • Add status/route.ts and chat/route.ts
    • Set environment variables
  4. Test:

    npm run dev
    
    • Check bottom-right corner for activity bubbles
    • Click chat button to test AI

🎯 Best Practices

  1. Caching: Cache API responses für 30s (nicht bei jedem Request neu fetchen)
  2. Error Handling: Graceful fallbacks wenn n8n down ist
  3. Rate Limiting: Limitiere Chat-Requests (max 10/minute)
  4. Privacy: Zeige nur das, was du teilen willst
  5. Performance: Nutze Webhooks statt Polling wo möglich

🤝 Community Ideas

Teile deine coolen n8n-Integrationen!

  • Discord: Zeig deinen Setup
  • GitHub: Share deine Workflows
  • Blog: Write-up über dein System

Happy automating! 🎉