full upgrade to dev

This commit is contained in:
2026-01-07 14:30:00 +01:00
parent 4dc727fcd6
commit 26a8610aa7
34 changed files with 6890 additions and 920 deletions

590
docs/N8N_INTEGRATION.md Normal file
View File

@@ -0,0 +1,590 @@
# 🚀 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! 🎉