753 lines
13 KiB
Markdown
753 lines
13 KiB
Markdown
# 📡 API Referenz
|
||
|
||
Vollständige Dokumentation der REST API des Ninja Cross Parkour Systems.
|
||
|
||
## 📋 Inhaltsverzeichnis
|
||
|
||
- [🔐 Authentifizierung](#-authentifizierung)
|
||
- [🌐 Public API](#-public-api)
|
||
- [🔒 Private API](#-private-api)
|
||
- [🖥️ Web API](#️-web-api)
|
||
- [👑 Admin API](#-admin-api)
|
||
- [🏆 Achievements API](#-achievements-api)
|
||
- [📊 Datenmodelle](#-datenmodelle)
|
||
- [❌ Fehlerbehandlung](#-fehlerbehandlung)
|
||
|
||
## 🔐 Authentifizierung
|
||
|
||
### API-Key Authentifizierung
|
||
Für private Endpoints wird ein API-Key im Authorization Header benötigt:
|
||
|
||
```http
|
||
Authorization: Bearer YOUR_API_KEY_HERE
|
||
```
|
||
|
||
### Session-basierte Authentifizierung
|
||
Für Web-Endpoints wird eine Session-basierte Authentifizierung verwendet.
|
||
|
||
### Admin-Authentifizierung
|
||
Für Admin-Endpoints wird eine erweiterte Authentifizierung mit Admin-Rechten benötigt.
|
||
|
||
## 🌐 Public API
|
||
|
||
Öffentliche Endpoints ohne Authentifizierung.
|
||
|
||
### 🔑 Authentifizierung
|
||
|
||
#### Login
|
||
```http
|
||
POST /api/v1/public/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "admin",
|
||
"password": "admin123"
|
||
}
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Login erfolgreich",
|
||
"user": {
|
||
"id": 1,
|
||
"username": "admin",
|
||
"is_active": true
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Logout
|
||
```http
|
||
POST /api/v1/public/logout
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "Logout erfolgreich"
|
||
}
|
||
```
|
||
|
||
### 👥 Spieler Management
|
||
|
||
#### Spieler erstellen
|
||
```http
|
||
POST /api/v1/public/players
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"firstname": "Max",
|
||
"lastname": "Mustermann",
|
||
"birthdate": "1990-01-01",
|
||
"rfiduid": "AA:BB:CC:DD"
|
||
}
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": "uuid",
|
||
"firstname": "Max",
|
||
"lastname": "Mustermann",
|
||
"birthdate": "1990-01-01",
|
||
"rfiduid": "AA:BB:CC:DD",
|
||
"created_at": "2024-01-01T00:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Spieler verknüpfen
|
||
```http
|
||
POST /api/v1/public/link-player
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"rfiduid": "AA:BB:CC:DD",
|
||
"supabase_user_id": "uuid-here"
|
||
}
|
||
```
|
||
|
||
#### Spieler per RFID verknüpfen
|
||
```http
|
||
POST /api/v1/public/link-by-rfid
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"rfiduid": "AA:BB:CC:DD",
|
||
"supabase_user_id": "uuid-here"
|
||
}
|
||
```
|
||
|
||
### 📍 Standorte
|
||
|
||
#### Alle Standorte abrufen
|
||
```http
|
||
GET /api/v1/public/locations
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": [
|
||
{
|
||
"id": "uuid",
|
||
"name": "Standort 1",
|
||
"latitude": 48.1351,
|
||
"longitude": 11.5820,
|
||
"time_threshold": {
|
||
"seconds": 120
|
||
},
|
||
"created_at": "2024-01-01T00:00:00Z"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### ⏱️ Zeiten
|
||
|
||
#### Alle Zeiten abrufen
|
||
```http
|
||
GET /api/v1/public/times
|
||
```
|
||
|
||
#### Zeiten mit Details abrufen
|
||
```http
|
||
GET /api/v1/public/times-with-details
|
||
```
|
||
|
||
#### Beste Zeiten abrufen
|
||
```http
|
||
GET /api/v1/public/best-times
|
||
```
|
||
|
||
#### Benutzer-Zeiten abrufen
|
||
```http
|
||
GET /api/v1/public/user-times/{supabase_user_id}
|
||
```
|
||
|
||
#### Benutzer-Spieler abrufen
|
||
```http
|
||
GET /api/v1/public/user-player/{supabase_user_id}
|
||
```
|
||
|
||
### 📊 Statistiken
|
||
|
||
#### Seitenaufruf verfolgen
|
||
```http
|
||
POST /api/v1/public/track-page-view
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"page": "/dashboard",
|
||
"user_agent": "Mozilla/5.0...",
|
||
"ip_address": "192.168.1.1"
|
||
}
|
||
```
|
||
|
||
### 🔔 Push Notifications
|
||
|
||
#### Push-Benachrichtigung abonnieren
|
||
```http
|
||
POST /api/v1/public/subscribe
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
|
||
"keys": {
|
||
"p256dh": "key-here",
|
||
"auth": "auth-key-here"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Push-Benachrichtigung testen
|
||
```http
|
||
POST /api/v1/public/test-push
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"title": "Test",
|
||
"body": "Test-Nachricht",
|
||
"icon": "/icon.png"
|
||
}
|
||
```
|
||
|
||
#### Push-Status abrufen
|
||
```http
|
||
GET /api/v1/public/push-status
|
||
```
|
||
|
||
## 🔒 Private API
|
||
|
||
Private Endpoints mit API-Key Authentifizierung.
|
||
|
||
### 🎫 Token Management
|
||
|
||
#### Token speichern
|
||
```http
|
||
POST /api/v1/private/save-token
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"token": "GENERATED_TOKEN",
|
||
"description": "Beschreibung",
|
||
"standorte": "München, Berlin"
|
||
}
|
||
```
|
||
|
||
#### Alle Token abrufen
|
||
```http
|
||
GET /api/v1/private/tokens
|
||
Authorization: Bearer YOUR_API_KEY
|
||
```
|
||
|
||
#### Token validieren
|
||
```http
|
||
POST /api/v1/private/validate-token
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"token": "TOKEN_TO_VALIDATE"
|
||
}
|
||
```
|
||
|
||
### 📍 Standort Management
|
||
|
||
#### Standort erstellen
|
||
```http
|
||
POST /api/v1/private/create-location
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "München",
|
||
"latitude": 48.1351,
|
||
"longitude": 11.5820
|
||
}
|
||
```
|
||
|
||
#### Alle Standorte abrufen
|
||
```http
|
||
GET /api/v1/private/locations
|
||
Authorization: Bearer YOUR_API_KEY
|
||
```
|
||
|
||
#### Standort-Schwelle aktualisieren
|
||
```http
|
||
PUT /api/v1/private/locations/{id}/threshold
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"threshold_seconds": 120
|
||
}
|
||
```
|
||
|
||
### 👥 Spieler Management
|
||
|
||
#### Spieler erstellen
|
||
```http
|
||
POST /api/v1/private/create-player
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"firstname": "Max",
|
||
"lastname": "Mustermann",
|
||
"birthdate": "1990-01-01",
|
||
"rfiduid": "AA:BB:CC:DD"
|
||
}
|
||
```
|
||
|
||
#### Benutzer suchen
|
||
```http
|
||
POST /api/v1/private/users/find
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"search_term": "Max"
|
||
}
|
||
```
|
||
|
||
### ⏱️ Zeit Management
|
||
|
||
#### Zeit erstellen
|
||
```http
|
||
POST /api/v1/private/create-time
|
||
Authorization: Bearer YOUR_API_KEY
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"player_id": "RFIDUID",
|
||
"location_id": "Name",
|
||
"recorded_time": "01:23.456"
|
||
}
|
||
```
|
||
|
||
## 🖥️ Web API
|
||
|
||
Web-API-Endpoints für das Frontend.
|
||
|
||
### 🔑 API-Key generieren
|
||
```http
|
||
POST /api/v1/web/generate-api-key
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"description": "Mein API Key",
|
||
"standorte": "München, Berlin"
|
||
}
|
||
```
|
||
|
||
### 📍 Standort erstellen
|
||
```http
|
||
POST /api/v1/web/create-location
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "München",
|
||
"latitude": 48.1351,
|
||
"longitude": 11.5820
|
||
}
|
||
```
|
||
|
||
### 🎫 Token speichern
|
||
```http
|
||
POST /api/v1/web/save-token
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"token": "GENERATED_TOKEN",
|
||
"description": "Beschreibung",
|
||
"standorte": "München, Berlin"
|
||
}
|
||
```
|
||
|
||
### 🔍 Session prüfen
|
||
```http
|
||
GET /api/v1/web/check-session
|
||
```
|
||
|
||
## 👑 Admin API
|
||
|
||
Admin-API-Endpoints für Verwaltung.
|
||
|
||
### 📊 Statistiken
|
||
|
||
#### Admin-Statistiken
|
||
```http
|
||
GET /api/v1/admin/stats
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
#### Seiten-Statistiken
|
||
```http
|
||
GET /api/v1/admin/page-stats
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
### 👥 Spieler Verwaltung
|
||
|
||
#### Alle Spieler abrufen
|
||
```http
|
||
GET /api/v1/admin/players
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
#### Spieler erstellen
|
||
```http
|
||
POST /api/v1/admin/players
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"firstname": "Max",
|
||
"lastname": "Mustermann",
|
||
"birthdate": "1990-01-01",
|
||
"rfiduid": "AA:BB:CC:DD"
|
||
}
|
||
```
|
||
|
||
#### Spieler aktualisieren
|
||
```http
|
||
PUT /api/v1/admin/players/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"firstname": "Max",
|
||
"lastname": "Mustermann",
|
||
"birthdate": "1990-01-01",
|
||
"rfiduid": "AA:BB:CC:DD"
|
||
}
|
||
```
|
||
|
||
#### Spieler löschen
|
||
```http
|
||
DELETE /api/v1/admin/players/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
### 🏃♂️ Läufe Verwaltung
|
||
|
||
#### Alle Läufe abrufen
|
||
```http
|
||
GET /api/v1/admin/runs
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
#### Lauf abrufen
|
||
```http
|
||
GET /api/v1/admin/runs/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
#### Lauf erstellen
|
||
```http
|
||
POST /api/v1/admin/runs
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"player_id": "uuid",
|
||
"location_id": "uuid",
|
||
"recorded_time": "01:23.456"
|
||
}
|
||
```
|
||
|
||
#### Lauf aktualisieren
|
||
```http
|
||
PUT /api/v1/admin/runs/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"recorded_time": "01:20.000"
|
||
}
|
||
```
|
||
|
||
#### Lauf löschen
|
||
```http
|
||
DELETE /api/v1/admin/runs/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
### 📍 Standort Verwaltung
|
||
|
||
#### Alle Standorte abrufen
|
||
```http
|
||
GET /api/v1/admin/locations
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
#### Standort erstellen
|
||
```http
|
||
POST /api/v1/admin/locations
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "München",
|
||
"latitude": 48.1351,
|
||
"longitude": 11.5820,
|
||
"time_threshold": 120
|
||
}
|
||
```
|
||
|
||
#### Standort aktualisieren
|
||
```http
|
||
PUT /api/v1/admin/locations/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "München Updated",
|
||
"latitude": 48.1351,
|
||
"longitude": 11.5820,
|
||
"time_threshold": 120
|
||
}
|
||
```
|
||
|
||
#### Standort löschen
|
||
```http
|
||
DELETE /api/v1/admin/locations/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
### 👤 Admin-Benutzer Verwaltung
|
||
|
||
#### Alle Admin-Benutzer abrufen
|
||
```http
|
||
GET /api/v1/admin/adminusers
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
#### Admin-Benutzer erstellen
|
||
```http
|
||
POST /api/v1/admin/adminusers
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "newadmin",
|
||
"password": "securepassword"
|
||
}
|
||
```
|
||
|
||
#### Admin-Benutzer aktualisieren
|
||
```http
|
||
PUT /api/v1/admin/adminusers/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "updatedadmin",
|
||
"is_active": true
|
||
}
|
||
```
|
||
|
||
#### Admin-Benutzer löschen
|
||
```http
|
||
DELETE /api/v1/admin/adminusers/{id}
|
||
Authorization: Bearer ADMIN_TOKEN
|
||
```
|
||
|
||
## 🏆 Achievements API
|
||
|
||
Achievement-System Endpoints.
|
||
|
||
### 🏆 Achievements abrufen
|
||
```http
|
||
GET /api/achievements
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": [
|
||
{
|
||
"id": "uuid",
|
||
"name": "Erster Lauf",
|
||
"description": "Absolviere deinen ersten Lauf",
|
||
"category": "consistency",
|
||
"condition_type": "runs_count",
|
||
"condition_value": 1,
|
||
"icon": "🏃♂️",
|
||
"points": 10,
|
||
"is_active": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 👤 Spieler-Achievements
|
||
```http
|
||
GET /api/achievements/player/{playerId}
|
||
```
|
||
|
||
### 📊 Spieler-Statistiken
|
||
```http
|
||
GET /api/achievements/player/{playerId}/stats
|
||
```
|
||
|
||
### ✅ Achievement prüfen
|
||
```http
|
||
POST /api/achievements/check/{playerId}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"achievement_id": "uuid"
|
||
}
|
||
```
|
||
|
||
### 📅 Tägliche Prüfung
|
||
```http
|
||
POST /api/achievements/daily-check
|
||
```
|
||
|
||
### 🏃♂️ Beste Zeit prüfen
|
||
```http
|
||
POST /api/achievements/best-time-check
|
||
```
|
||
|
||
### 🏅 Leaderboard
|
||
```http
|
||
GET /api/achievements/leaderboard
|
||
```
|
||
|
||
## 📊 Datenmodelle
|
||
|
||
### Player
|
||
```json
|
||
{
|
||
"id": "string (uuid)",
|
||
"firstname": "string",
|
||
"lastname": "string",
|
||
"birthdate": "string (date)",
|
||
"rfiduid": "string (XX:XX:XX:XX)",
|
||
"supabase_user_id": "string (uuid)",
|
||
"created_at": "string (date-time)"
|
||
}
|
||
```
|
||
|
||
### Time
|
||
```json
|
||
{
|
||
"id": "string (uuid)",
|
||
"player_id": "string (uuid)",
|
||
"location_id": "string (uuid)",
|
||
"recorded_time": {
|
||
"seconds": "number",
|
||
"minutes": "number",
|
||
"milliseconds": "number"
|
||
},
|
||
"created_at": "string (date-time)"
|
||
}
|
||
```
|
||
|
||
### Location
|
||
```json
|
||
{
|
||
"id": "string (uuid)",
|
||
"name": "string",
|
||
"latitude": "number (float)",
|
||
"longitude": "number (float)",
|
||
"time_threshold": {
|
||
"seconds": "number",
|
||
"minutes": "number"
|
||
},
|
||
"created_at": "string (date-time)"
|
||
}
|
||
```
|
||
|
||
### Achievement
|
||
```json
|
||
{
|
||
"id": "string (uuid)",
|
||
"name": "string",
|
||
"description": "string",
|
||
"category": "string (consistency|improvement|seasonal|monthly)",
|
||
"condition_type": "string",
|
||
"condition_value": "integer",
|
||
"icon": "string (emoji)",
|
||
"points": "integer",
|
||
"is_active": "boolean"
|
||
}
|
||
```
|
||
|
||
### PlayerAchievement
|
||
```json
|
||
{
|
||
"id": "string (uuid)",
|
||
"player_id": "string (uuid)",
|
||
"achievement_id": "string (uuid)",
|
||
"progress": "integer",
|
||
"is_completed": "boolean",
|
||
"earned_at": "string (date-time)"
|
||
}
|
||
```
|
||
|
||
## ❌ Fehlerbehandlung
|
||
|
||
### Standard-Fehlerantwort
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "Fehlermeldung",
|
||
"error": "DETAILED_ERROR_INFO"
|
||
}
|
||
```
|
||
|
||
### HTTP-Status-Codes
|
||
|
||
- **200 OK** - Erfolgreiche Anfrage
|
||
- **201 Created** - Ressource erfolgreich erstellt
|
||
- **400 Bad Request** - Ungültige Anfrage
|
||
- **401 Unauthorized** - Nicht authentifiziert
|
||
- **403 Forbidden** - Keine Berechtigung
|
||
- **404 Not Found** - Ressource nicht gefunden
|
||
- **500 Internal Server Error** - Serverfehler
|
||
|
||
### Häufige Fehlermeldungen
|
||
|
||
- `"API-Key erforderlich"` - Fehlender oder ungültiger API-Key
|
||
- `"Ungültige Anmeldedaten"` - Falsche Login-Daten
|
||
- `"Ressource nicht gefunden"` - Angeforderte Ressource existiert nicht
|
||
- `"Ungültige Daten"` - Validierungsfehler bei Eingabedaten
|
||
- `"Keine Berechtigung"` - Unzureichende Rechte für die Aktion
|
||
|
||
## 🔧 Entwicklung
|
||
|
||
### Lokale Entwicklung
|
||
```bash
|
||
# Server starten
|
||
npm run dev
|
||
|
||
# API-Dokumentation anzeigen
|
||
# Swagger UI verfügbar unter: http://localhost:3000/api-docs
|
||
```
|
||
|
||
### Produktionsumgebung
|
||
```bash
|
||
# Server starten
|
||
npm start
|
||
|
||
# API-Dokumentation: https://ninja.reptilfpv.de/api-docs
|
||
```
|
||
|
||
---
|
||
|
||
**Version:** 1.0.0
|
||
**Base URL:** `https://ninja.reptilfpv.de/api`
|
||
**Autor:** Carsten Graf
|