Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 10m3s
Added rate limiting to APIs, cleaned up docs, implemented fallback logic for reviews without text, and added comprehensive n8n guide.
590 lines
17 KiB
Markdown
590 lines
17 KiB
Markdown
# 🚀 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`
|
|
|
|
```sql
|
|
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
|
|
|
|
```json
|
|
{
|
|
"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)
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```json
|
|
{
|
|
"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)
|
|
|
|
```json
|
|
{
|
|
"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)
|
|
|
|
```json
|
|
{
|
|
"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`
|
|
|
|
```typescript
|
|
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`
|
|
|
|
```typescript
|
|
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`:
|
|
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
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:**
|
|
```bash
|
|
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! 🎉 |