# 🏆 Achievement System Umfassende Dokumentation des Achievement-Systems für das Ninja Cross Parkour System. ## 📊 System-Übersicht Das Achievement-System besteht aus: - **32 verschiedene Achievements** in 4 Kategorien - **Automatische tägliche Vergabe** am Ende des Tages - **REST API Endpoints** für Frontend-Integration - **PostgreSQL Funktionen** für effiziente Verarbeitung ## 🎯 Achievement-Kategorien ### 1. Konsistenz-basierte Achievements - **Erste Schritte** 👶 - Erste Zeit aufgezeichnet (5 Punkte) - **Durchhalter** 💪 - 3 Versuche an einem Tag (10 Punkte) - **Fleißig** 🔥 - 5 Versuche an einem Tag (15 Punkte) - **Besessen** 😤 - 10 Versuche an einem Tag (25 Punkte) - **Regelmäßig** 📅 - 5 verschiedene Tage gespielt (20 Punkte) - **Stammgast** ⭐ - 10 verschiedene Tage gespielt (30 Punkte) - **Treue** 💎 - 20 verschiedene Tage gespielt (50 Punkte) - **Veteran** 🏆 - 50 verschiedene Tage gespielt (100 Punkte) ### 2. Verbesserungs-basierte Achievements - **Fortschritt** 📈 - Persönliche Bestzeit um 5 Sekunden verbessert (15 Punkte) - **Durchbruch** ⚡ - Persönliche Bestzeit um 10 Sekunden verbessert (25 Punkte) - **Transformation** 🔄 - Persönliche Bestzeit um 15 Sekunden verbessert (40 Punkte) - **Perfektionist** ✨ - Persönliche Bestzeit um 20 Sekunden verbessert (60 Punkte) ### 3. Saisonale Achievements - **Wochenend-Krieger** 🏁 - Am Wochenende gespielt (10 Punkte) - **Nachmittags-Sportler** ☀️ - Zwischen 14-18 Uhr gespielt (10 Punkte) - **Frühaufsteher** 🌅 - Vor 10 Uhr gespielt (15 Punkte) - **Abend-Sportler** 🌙 - Nach 18 Uhr gespielt (10 Punkte) ### 4. Monatliche Achievements - **Januar-Krieger** ❄️ bis **Dezember-Dynamo** 🎄 (je 20 Punkte) ### 5. Jahreszeiten-Achievements - **Frühjahrs-Fighter** 🌱 - Im Frühling gespielt (30 Punkte) - **Sommer-Sportler** ☀️ - Im Sommer gespielt (30 Punkte) - **Herbst-Held** 🍂 - Im Herbst gespielt (30 Punkte) - **Winter-Warrior** ❄️ - Im Winter gespielt (30 Punkte) ## 🗄️ Datenbank-Schema ### Tabelle: `achievements` ```sql - id (uuid, PK) - name (varchar) - Achievement-Name - description (text) - Beschreibung - category (varchar) - Kategorie - condition_type (varchar) - Bedingungstyp - condition_value (integer) - Bedingungswert - icon (varchar) - Emoji-Icon - points (integer) - Punkte - is_active (boolean) - Aktiv - created_at (timestamp) ``` ### Tabelle: `player_achievements` ```sql - id (uuid, PK) - player_id (uuid, FK) - Verweis auf players.id - achievement_id (uuid, FK) - Verweis auf achievements.id - earned_at (timestamp) - Wann erreicht - progress (integer) - Fortschritt - is_completed (boolean) - Abgeschlossen - created_at (timestamp) ``` ## 🔧 PostgreSQL Funktionen ### `check_consistency_achievements(player_uuid)` Überprüft alle Konsistenz-basierten Achievements für einen Spieler. **Logik:** - Zählt Gesamtläufe des Spielers - Zählt Läufe pro Tag - Zählt verschiedene Spieltage - Vergibt entsprechende Achievements ### `check_improvement_achievements(player_uuid)` Überprüft alle Verbesserungs-basierten Achievements für einen Spieler. **Logik:** - Ermittelt persönliche Bestzeit - Berechnet Verbesserung seit erster Zeit - Vergibt entsprechende Achievements ### `check_seasonal_achievements(player_uuid)` Überprüft alle saisonalen und monatlichen Achievements für einen Spieler. **Logik:** - Prüft Wochentag (Wochenende) - Prüft Tageszeit (morgens, nachmittags, abends) - Prüft Monat (Januar bis Dezember) - Prüft Jahreszeit (Frühling, Sommer, Herbst, Winter) ### `check_all_achievements(player_uuid)` Führt alle Achievement-Überprüfungen für einen Spieler aus. ## 🚀 API Endpoints ### GET `/api/achievements` Alle verfügbaren Achievements abrufen. **Response:** ```json { "success": true, "data": [ { "id": "uuid", "name": "Erste Schritte", "description": "Absolviere deinen ersten Lauf", "category": "consistency", "condition_type": "runs_count", "condition_value": 1, "icon": "👶", "points": 5, "is_active": true } ] } ``` ### GET `/api/achievements/player/:playerId` Achievements eines bestimmten Spielers abrufen. **Response:** ```json { "success": true, "data": [ { "id": "uuid", "achievement_id": "uuid", "name": "Erste Schritte", "description": "Absolviere deinen ersten Lauf", "icon": "👶", "points": 5, "progress": 1, "is_completed": true, "earned_at": "2024-01-01T00:00:00Z" } ] } ``` ### GET `/api/achievements/player/:playerId/stats` Achievement-Statistiken eines Spielers abrufen. **Response:** ```json { "success": true, "data": { "total_achievements": 32, "completed_achievements": 5, "total_points": 150, "earned_points": 75, "completion_percentage": 15.6 } } ``` ### POST `/api/achievements/check/:playerId` Achievements für einen Spieler manuell überprüfen. **Request:** ```json { "achievement_id": "uuid" } ``` ### POST `/api/achievements/daily-check` Tägliche Achievement-Überprüfung für alle Spieler ausführen. **Response:** ```json { "success": true, "message": "Daily achievement check completed", "players_checked": 150, "achievements_awarded": 25 } ``` ### GET `/api/achievements/leaderboard?limit=10` Bestenliste der Spieler nach Achievement-Punkten. **Response:** ```json { "success": true, "data": [ { "player_id": "uuid", "firstname": "Max", "lastname": "Mustermann", "total_points": 500, "completed_achievements": 15, "rank": 1 } ] } ``` ## 📅 Automatisierung ### Tägliches Script ```bash # Manuell ausführen node scripts/daily_achievements.js # Cron-Job einrichten node scripts/setup_cron.js setup # Cron-Job Status prüfen node scripts/setup_cron.js status # Cron-Job entfernen node scripts/setup_cron.js remove ``` ### Cron-Schedule - **Zeit**: Täglich um 23:59 Uhr - **Log**: `/var/log/ninjaserver_achievements.log` ### Script-Details ```javascript // scripts/daily_achievements.js const { checkAllAchievements } = require('../models/Achievement'); async function dailyCheck() { try { // Alle Spieler abrufen const players = await getAllPlayers(); let totalAwarded = 0; for (const player of players) { const awarded = await checkAllAchievements(player.id); totalAwarded += awarded; } console.log(`Daily check completed: ${totalAwarded} achievements awarded`); } catch (error) { console.error('Daily check failed:', error); } } ``` ## 🎮 Frontend-Integration ### Beispiel: Achievement-Liste laden ```javascript async function loadAchievements(playerId) { try { const response = await fetch(`/api/achievements/player/${playerId}`); const data = await response.json(); if (data.success) { data.data.forEach(achievement => { const status = achievement.is_completed ? '✅' : '❌'; console.log(`${achievement.icon} ${achievement.name}: ${status}`); }); } } catch (error) { console.error('Error loading achievements:', error); } } ``` ### Beispiel: Statistiken anzeigen ```javascript async function loadStats(playerId) { try { const response = await fetch(`/api/achievements/player/${playerId}/stats`); const data = await response.json(); if (data.success) { const stats = data.data; document.getElementById('total-points').textContent = stats.total_points; document.getElementById('completed').textContent = `${stats.completed_achievements}/${stats.total_achievements}`; document.getElementById('percentage').textContent = `${stats.completion_percentage}%`; } } catch (error) { console.error('Error loading stats:', error); } } ``` ### Beispiel: Achievement-Animation ```javascript function showAchievementNotification(achievement) { const notification = document.createElement('div'); notification.className = 'achievement-notification'; notification.innerHTML = `
${achievement.icon}

${achievement.name}

${achievement.description}

+${achievement.points} Punkte
`; document.body.appendChild(notification); // Animation setTimeout(() => { notification.classList.add('show'); }, 100); // Entfernen nach 5 Sekunden setTimeout(() => { notification.remove(); }, 5000); } ``` ## 🔍 Monitoring ### Logs überwachen ```bash # Live-Logs anzeigen tail -f /var/log/ninjaserver_achievements.log # Letzte Ausführung prüfen grep "Daily achievement check completed" /var/log/ninjaserver_achievements.log | tail -1 # Fehler-Logs anzeigen grep "ERROR" /var/log/ninjaserver_achievements.log ``` ### Datenbank-Status prüfen ```sql -- Achievement-Statistiken SELECT COUNT(*) as total_achievements, COUNT(CASE WHEN is_active = true THEN 1 END) as active_achievements FROM achievements; -- Spieler-Statistiken SELECT COUNT(DISTINCT player_id) as players_with_achievements, COUNT(*) as total_earned_achievements FROM player_achievements WHERE is_completed = true; -- Top-Spieler SELECT p.firstname, p.lastname, COUNT(pa.id) as achievements, SUM(a.points) as total_points FROM players p JOIN player_achievements pa ON p.id = pa.player_id JOIN achievements a ON pa.achievement_id = a.id WHERE pa.is_completed = true GROUP BY p.id, p.firstname, p.lastname ORDER BY total_points DESC LIMIT 10; ``` ## 🛠️ Wartung ### Neue Achievements hinzufügen 1. Achievement in `achievements` Tabelle einfügen: ```sql INSERT INTO achievements (name, description, category, condition_type, condition_value, icon, points) VALUES ('Neues Achievement', 'Beschreibung', 'consistency', 'runs_count', 5, '🏆', 25); ``` 2. Logik in entsprechenden PostgreSQL Funktionen erweitern 3. API Endpoints testen ### Achievement deaktivieren ```sql UPDATE achievements SET is_active = false WHERE name = 'Achievement-Name'; ``` ### Daten zurücksetzen ```sql -- Alle Spieler-Achievements löschen DELETE FROM player_achievements; -- Achievement-Statistiken zurücksetzen UPDATE achievements SET created_at = NOW(); ``` ### Achievement-Import/Export ```bash # Export pg_dump -t achievements -t player_achievements ninjaserver > achievements_backup.sql # Import psql ninjaserver < achievements_backup.sql ``` ## 📈 Performance ### Indizierung ```sql -- Performance-Indizes CREATE INDEX CONCURRENTLY idx_player_achievements_player_id ON player_achievements(player_id); CREATE INDEX CONCURRENTLY idx_player_achievements_achievement_id ON player_achievements(achievement_id); CREATE INDEX CONCURRENTLY idx_player_achievements_completed ON player_achievements(is_completed) WHERE is_completed = true; ``` ### Batch-Processing - **Effiziente Verarbeitung** aller Spieler in einem Durchgang - **Transaktionale Sicherheit** für Datenkonsistenz - **Fehlerbehandlung** für einzelne Spieler ### Caching - **Achievement-Definitionen** werden gecacht - **Spieler-Statistiken** werden bei Änderungen neu berechnet - **Leaderboard** wird periodisch aktualisiert ### Zeitzone-Behandlung - **Korrekte Zeitzone** (Europe/Berlin) für alle Zeitberechnungen - **Saisonale Achievements** berücksichtigen lokale Zeit - **Tägliche Prüfung** erfolgt zur richtigen Zeit ## 🔒 Sicherheit ### API-Schutz - **Alle Endpoints** über bestehende Authentifizierung - **Admin-Endpoints** erfordern erweiterte Berechtigung - **Rate Limiting** für häufige Anfragen ### SQL-Injection - **Parametrisierte Queries** in allen Funktionen - **Input-Validierung** vor Datenbankzugriff - **Escape-Funktionen** für dynamische Inhalte ### Datenvalidierung - **Eingabe-Validierung** in allen API-Endpoints - **Typ-Überprüfung** für alle Parameter - **Bereichs-Validierung** für numerische Werte ### Fehlerbehandlung - **Umfassende Error-Handling** in allen Funktionen - **Logging** aller Fehler und Warnungen - **Graceful Degradation** bei Systemfehlern ## 🎯 Best Practices ### Achievement-Design - **Klare Bedingungen** für alle Achievements - **Angemessene Punkte** basierend auf Schwierigkeit - **Motivierende Beschreibungen** für Spieler ### Performance-Optimierung - **Batch-Processing** für große Datenmengen - **Indizierung** für häufige Abfragen - **Caching** für statische Daten ### Wartbarkeit - **Modulare Struktur** für einfache Erweiterungen - **Dokumentation** aller Funktionen - **Tests** für kritische Komponenten --- **Erstellt am**: $(date) **Version**: 1.0.0 **Autor**: Ninja Cross Parkour System