Initial commit: Beisel Rallye Graz Project with full documentation
This commit is contained in:
+174
@@ -0,0 +1,174 @@
|
|||||||
|
# API-Design: Beisel Rallye 🍺
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
Die API ermöglicht server-seitige Speicherung aller Rallye-Einträge und unterstützt echte Multi-User-Funktionalität über verschiedene Geräte hinweg.
|
||||||
|
|
||||||
|
## Endpunkte
|
||||||
|
|
||||||
|
### 1. Bezirk besuchen (POST /api/visit)
|
||||||
|
|
||||||
|
**Zweck:** Neuen Besuch eines Bezirks speichern
|
||||||
|
|
||||||
|
**Request Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user_name": "Gregor",
|
||||||
|
"district": "I. Innere Stadt",
|
||||||
|
"beisel_name": "Schloßhotel Greising"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (201 Created):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Bezirk gespeichert!",
|
||||||
|
"data": {
|
||||||
|
"id": 6,
|
||||||
|
"user_name": "Gregor",
|
||||||
|
"district": "I. Innere Stadt",
|
||||||
|
"beisel_name": "Schloßhotel Greising",
|
||||||
|
"timestamp": "2026-06-29T10:30:00.000Z"
|
||||||
|
},
|
||||||
|
"progress": {
|
||||||
|
"visited_count": 8,
|
||||||
|
"total_districts": 17,
|
||||||
|
"percentage": 47
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fehler (400 Bad Request):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"error": "Ungültige Eingabe",
|
||||||
|
"details": {
|
||||||
|
"user_name": "Pflichtfeld",
|
||||||
|
"district": "Ungültiger Bezirk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Fortschritt abrufen (GET /api/status/:username)
|
||||||
|
|
||||||
|
**Zweck:** Aktuelle Rallye-Statistik für einen Benutzer laden
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"user_name": "Gregor",
|
||||||
|
"progress": {
|
||||||
|
"visited_count": 8,
|
||||||
|
"total_districts": 17,
|
||||||
|
"percentage": 47
|
||||||
|
},
|
||||||
|
"visits": [
|
||||||
|
{
|
||||||
|
"district": "I. Innere Stadt",
|
||||||
|
"beisel_name": "Schloßhotel Greising",
|
||||||
|
"timestamp": "2026-06-29T10:30:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"district": "II. St. Leonhard",
|
||||||
|
"beisel_name": "Jazzkeller",
|
||||||
|
"timestamp": "2026-06-29T11:15:00.000Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_updated": "2026-06-29T11:15:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Alle Teilnehmer anzeigen (GET /api/all-users)
|
||||||
|
|
||||||
|
**Zweck:** Leaderboard mit allen aktiven Teilnehmern
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"user_name": "Gregor",
|
||||||
|
"visited_count": 8,
|
||||||
|
"last_active": "2026-06-29T11:15:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"user_name": "Maria",
|
||||||
|
"visited_count": 12,
|
||||||
|
"last_active": "2026-06-29T10:45:00.000Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_users": 2,
|
||||||
|
"generated_at": "2026-06-29T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Reset für User (DELETE /api/reset/:username)
|
||||||
|
|
||||||
|
**Zweck:** Alle Einträge eines Users löschen
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Alle Einträge für 'Gregor' gelöscht",
|
||||||
|
"deleted_count": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fehlerbehandlung
|
||||||
|
|
||||||
|
### Allgemeine Fehler (4xx/5xx)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error_code": "INTERNAL_ERROR",
|
||||||
|
"message": "Unerwarteter Serverfehler",
|
||||||
|
"timestamp": "2026-06-29T12:00:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validierungsfehler (400)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error_code": "VALIDATION_ERROR",
|
||||||
|
"message": "Ungültige Eingabe",
|
||||||
|
"details": {
|
||||||
|
"field_name": ["Fehlermeldung"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementierungs-Hinweise
|
||||||
|
|
||||||
|
### Datenbank-Operationen
|
||||||
|
- Verwende `sqlite3` Package für asynchrone Operationen
|
||||||
|
- Parameterisierte Queries gegen SQL Injection schützen
|
||||||
|
- Connection Pooling für bessere Performance
|
||||||
|
|
||||||
|
### Rate Limiting
|
||||||
|
- Max. 10 Anfragen pro Minute pro IP
|
||||||
|
- Besonders bei POST /api/visit wichtig
|
||||||
|
|
||||||
|
### Sicherheit
|
||||||
|
- Input Validation auf allen Endpunkten
|
||||||
|
- User-Namen sanitieren (keine Script-Injection)
|
||||||
|
- CORS Headers setzen falls nötig
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- SQLite ist ausreichend für diese Anwendung
|
||||||
|
- Keine komplexen Joins notwendig
|
||||||
|
- Periodische Datenbank-Vacuum Operationen empfohlen
|
||||||
|
|
||||||
|
---
|
||||||
|
*Stand: 2026-06-29 | Version: 1.0*
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
# Architektur-Dokumentation: Beisel Rallye 🍺
|
||||||
|
|
||||||
|
## Systemübersicht
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||||
|
│ Browser │──────→│ Express Server │──────→│ SQLite DB │
|
||||||
|
│ (Client) │ │ (:8083) │ │ │
|
||||||
|
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
||||||
|
↕ ↕
|
||||||
|
Nginx Reverse Proxy beisel_rally.db
|
||||||
|
(aufeins.click.jetzt) :8083
|
||||||
|
```
|
||||||
|
|
||||||
|
## Komponenten
|
||||||
|
|
||||||
|
### 1. Frontend (Browser)
|
||||||
|
- **Technologie:** Vanilla JavaScript + EJS Templates
|
||||||
|
- **Responsibility:** UI-Rendering, User-Interaktion, Client-Side Validation
|
||||||
|
- **Speicherung:** Aktuelle Implementierung nutzt localStorage (→ wird durch Server API ersetzt)
|
||||||
|
|
||||||
|
### 2. Backend (Express.js)
|
||||||
|
- **Port:** 8083
|
||||||
|
- **Routing:** Express Router
|
||||||
|
- **Datenbank:** SQLite via `sqlite3` Package
|
||||||
|
- **Middleware:** body-parser, CORS (geplant)
|
||||||
|
|
||||||
|
### 3. Datenbank (SQLite)
|
||||||
|
- **Datei:** `beisel_rally.db`
|
||||||
|
- **Schema:** Einfache Tabelle `rally_logs`
|
||||||
|
- **Skalierung:** Ausreichend für erwartete User-Anzahl (<1000)
|
||||||
|
|
||||||
|
## Datenfluss
|
||||||
|
|
||||||
|
### Aktuelle Implementierung (localStorage-basiert):
|
||||||
|
```
|
||||||
|
User → Browser UI → localStorage → (keine Server-Kommunikation)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ziel-Implementierung (Server-seitig):
|
||||||
|
```
|
||||||
|
User → Browser UI → API Request → Express Server → SQLite DB
|
||||||
|
↑ |
|
||||||
|
└─────────────── API Response ←────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Datenbank-Schema
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE rally_logs (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_name TEXT NOT NULL,
|
||||||
|
district TEXT NOT NULL,
|
||||||
|
beisel_name TEXT NOT NULL,
|
||||||
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index für häufige Queries
|
||||||
|
CREATE INDEX idx_user_district ON rally_logs(user_name, district);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment-Architektur
|
||||||
|
|
||||||
|
### Nginx Reverse Proxy
|
||||||
|
- **Funktion:** SSL-Terminierung, Load Balancing (geplant)
|
||||||
|
- **Domain:** aufeins.click.jetzt
|
||||||
|
- **Backend:** 192.168.0.187:8083
|
||||||
|
- **SSL:** Let's Encrypt automatisch
|
||||||
|
|
||||||
|
### Server-Setup
|
||||||
|
```bash
|
||||||
|
# Abhängigkeiten installieren
|
||||||
|
cd /home/claw/.openclaw/agents/wisp/workspace/beisel-rally
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Server starten
|
||||||
|
node index.js
|
||||||
|
|
||||||
|
# Im Hintergrund laufen lassen (optional)
|
||||||
|
nohup node index.js > server.log 2>&1 &
|
||||||
|
```
|
||||||
|
|
||||||
|
## Skalierungsbetrachtung
|
||||||
|
|
||||||
|
### Aktuelle Kapazitäten
|
||||||
|
- **SQLite:** Bis ~1M Einträge performant
|
||||||
|
- **Express:** Bis ~100 req/s ohne Optimierung
|
||||||
|
- **Nginx:** Hoch skalierbar
|
||||||
|
|
||||||
|
### Erweiterungsmöglichkeiten
|
||||||
|
1. **PostgreSQL Migration** bei >10k Usern
|
||||||
|
2. **Redis Caching** für statische Daten (Bezirke, Beiseln)
|
||||||
|
3. **Load Balancing** mit mehreren Express Instanzen
|
||||||
|
4. **WebSocket** für Echtzeit-Updates
|
||||||
|
|
||||||
|
## Sicherheitshinweise
|
||||||
|
|
||||||
|
### Aktuelle Schwachstellen
|
||||||
|
- ❌ Keine Input Validation auf Server-Side
|
||||||
|
- ❌ Keine Rate Limiting
|
||||||
|
- ❌ SQL Injection möglich (bei korrekter Implementierung)
|
||||||
|
- ❌ CORS nicht konfiguriert
|
||||||
|
|
||||||
|
### Verbesserungen
|
||||||
|
- ✅ Parameterisierte Queries verwenden
|
||||||
|
- ✅ Rate Limiting implementieren
|
||||||
|
- ✅ CORS Headers setzen
|
||||||
|
- ✅ Input Sanitization hinzufügen
|
||||||
|
- ✅ HTTPS erzwingen (bereits durch Nginx gegeben)
|
||||||
|
|
||||||
|
---
|
||||||
|
*Stand: 2026-06-29 | Version: 1.0*
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
# Entwicklungshandbuch: Beisel Rallye 🍺
|
||||||
|
|
||||||
|
## Schnellstart
|
||||||
|
|
||||||
|
### Voraussetzungen
|
||||||
|
- Node.js v18+
|
||||||
|
- npm oder yarn
|
||||||
|
- SQLite3 (wird via npm installiert)
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
```bash
|
||||||
|
# In das Projektverzeichnis wechseln
|
||||||
|
cd /home/claw/.openclaw/agents/wisp/workspace/beisel-rally
|
||||||
|
|
||||||
|
# Abhängigkeiten installieren
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Server starten
|
||||||
|
node index.js
|
||||||
|
|
||||||
|
# Server läuft auf http://localhost:8083
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code-Struktur
|
||||||
|
|
||||||
|
### Wichtige Dateien
|
||||||
|
- `index.js` - Hauptserver mit Express App
|
||||||
|
- `views/index.ejs` - Frontend Template
|
||||||
|
- `public/css/style.css` - Styling
|
||||||
|
- `beisel_rally.db` - SQLite Datenbank
|
||||||
|
- `package.json` - Dependencies und Scripts
|
||||||
|
|
||||||
|
### Entwicklungs-Wiederholungszyklus
|
||||||
|
1. Code ändern
|
||||||
|
2. Server neu starten (`Ctrl+C`, dann `node index.js`)
|
||||||
|
3. Im Browser testen (Cache leeren!)
|
||||||
|
4. Git commit (wenn fertig)
|
||||||
|
|
||||||
|
## Wichtige Konzepte
|
||||||
|
|
||||||
|
### Express Middleware
|
||||||
|
```javascript
|
||||||
|
// Body Parser für JSON Requests
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Statische Dateien servieren
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
|
// Custom Middleware (z.B. Logging)
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### SQLite Operationen
|
||||||
|
```javascript
|
||||||
|
const sqlite3 = require('sqlite3').verbose();
|
||||||
|
const db = new sqlite3.Database('./beisel_rally.db');
|
||||||
|
|
||||||
|
// Query ausführen
|
||||||
|
db.run("INSERT INTO rally_logs (user_name, district) VALUES (?, ?)",
|
||||||
|
["Gregor", "I. Innere Stadt"], function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('Insert fehlgeschlagen:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('Erfolgreich eingefügt, ID:', this.lastID);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Daten abrufen
|
||||||
|
db.all("SELECT * FROM rally_logs WHERE user_name = ?", ["Gregor"], (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Query fehlgeschlagen:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(rows);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fehlerbehandlung
|
||||||
|
```javascript
|
||||||
|
// Try-Catch für async Operationen
|
||||||
|
try {
|
||||||
|
const result = await someAsyncOperation();
|
||||||
|
res.json({ success: true, data: result });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Interner Serverfehler'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Manuelles Testen
|
||||||
|
1. Server starten
|
||||||
|
2. Browser öffnen: `http://localhost:8083`
|
||||||
|
3. API Endpunkte testen mit curl oder Postman:
|
||||||
|
```bash
|
||||||
|
# New Visit testen
|
||||||
|
curl -X POST http://localhost:8083/api/visit \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"user_name":"Gregor","district":"I. Innere Stadt","beisel_name":"Test"}'
|
||||||
|
|
||||||
|
# Status abrufen
|
||||||
|
curl http://localhost:8083/api/status/Gregor
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datenbank-Checks
|
||||||
|
```bash
|
||||||
|
# SQLite CLI starten
|
||||||
|
sqlite3 beisel_rally.db
|
||||||
|
|
||||||
|
# Alle Einträge anzeigen
|
||||||
|
SELECT * FROM rally_logs;
|
||||||
|
|
||||||
|
# Statistik pro User
|
||||||
|
SELECT user_name, COUNT(*) as visits FROM rally_logs GROUP BY user_name;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
### Häufige Probleme
|
||||||
|
|
||||||
|
**Server startet nicht:**
|
||||||
|
- Port 8083 ist belegt? → `lsof -i :8083` und Prozess killen
|
||||||
|
- Node.js Version zu alt? → `node --version` (braucht v18+)
|
||||||
|
|
||||||
|
**Datenbank Fehler:**
|
||||||
|
- Datei nicht gefunden? → Prüfen ob `beisel_rally.db` existiert
|
||||||
|
- Permission denied? → `chmod 664 beisel_rally.db` und Gruppe prüfen
|
||||||
|
|
||||||
|
**Frontend lädt nicht:**
|
||||||
|
- Cache geleert? → Hard Reload (Ctrl+Shift+R)
|
||||||
|
- CORS Fehler? → Server Logs checken
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Code-Qualität
|
||||||
|
- **ESLint** für JavaScript Linting
|
||||||
|
- **Prettier** für konsistentes Formatting
|
||||||
|
- **Git Commits** mit klaren Nachrichten
|
||||||
|
- **Comments** erklären das "Warum", nicht das "Was"
|
||||||
|
|
||||||
|
### Sicherheit
|
||||||
|
- **Input Validation** auf allen Endpunkten
|
||||||
|
- **Parameterisierte Queries** gegen SQL Injection
|
||||||
|
- **Rate Limiting** für API Endpunkte
|
||||||
|
- **HTTPS** erzwingen (bereits durch Nginx gegeben)
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- **Datenbank-Verbindungen** schließen wenn nicht benötigt
|
||||||
|
- **Caching** für statische Daten (Bezirke, Beiseln)
|
||||||
|
- **Pagination** bei großen Datensätzen
|
||||||
|
- **Lazy Loading** für komplexe Views
|
||||||
|
|
||||||
|
## Deployment Checklist
|
||||||
|
|
||||||
|
Vor dem Deployen prüfen:
|
||||||
|
- [ ] Alle Tests bestanden
|
||||||
|
- [ ] Datenbank-Schema aktuell
|
||||||
|
- [ ] Environment-Variablen gesetzt (falls nötig)
|
||||||
|
- [ ] Logging konfiguriert
|
||||||
|
- [ ] Backup-Mechanismus vorhanden
|
||||||
|
- [ ] Monitoring/Alerting eingerichtet
|
||||||
|
|
||||||
|
## Ressourcen
|
||||||
|
|
||||||
|
### Offizielle Dokumentation
|
||||||
|
- [Express.js](https://expressjs.com/)
|
||||||
|
- [SQLite3 Node.js](https://github.com/TryGhost/node-sqlite3)
|
||||||
|
- [Nginx Documentation](https://nginx.org/en/docs/)
|
||||||
|
|
||||||
|
### Lokale Hilfe
|
||||||
|
- `PROJECT.md` - Projektübersicht
|
||||||
|
- `API_DESIGN.md` - API Spezifikation
|
||||||
|
- `ARCHITECTURE.md` - System-Architektur
|
||||||
|
|
||||||
|
---
|
||||||
|
*Stand: 2026-06-29 | Version: 1.0*
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
# Beisel Rallye Graz 🍺
|
||||||
|
|
||||||
|
## Projektübersicht
|
||||||
|
|
||||||
|
Interaktive Website für eine Bier-Rallye durch 17 Grazer Bezirke. Teilnehmende tragen bei jedem besuchten Bezirk das entsprechende Beisel (Bierlokal) ein und verfolgen ihren Fortschritt.
|
||||||
|
|
||||||
|
### Konzept
|
||||||
|
- **Ziel:** Alle 17 Grazer Bezirke besuchen
|
||||||
|
- **Aktivität:** Für jeden Bezirk ein lokales Beisel finden und eintragen
|
||||||
|
- **Zeitrahmen:** 24 Stunden Rallye
|
||||||
|
- **Multi-User:** Mehrere Teilnehmer können parallel teilnehmen
|
||||||
|
|
||||||
|
## Technologie-Stack
|
||||||
|
|
||||||
|
- **Backend:** Express.js (Node.js)
|
||||||
|
- **Frontend:** EJS Templates + Vanilla JavaScript
|
||||||
|
- **Datenbank:** SQLite (beisel_rally.db)
|
||||||
|
- **Styling:** Custom CSS mit Wirtshaus-Theme
|
||||||
|
- **Deployment:** Nginx Reverse Proxy auf `aufeins.click.jetzt`
|
||||||
|
|
||||||
|
## Architektur
|
||||||
|
|
||||||
|
```
|
||||||
|
beisel-rally/
|
||||||
|
├── index.js # Express Server (Port 8083)
|
||||||
|
├── package.json # Dependencies & Scripts
|
||||||
|
├── beisel_rally.db # SQLite Datenbank
|
||||||
|
├── server.log # Laufzeit-Logs
|
||||||
|
├── PROJECT.md # Diese Dokumentation
|
||||||
|
├── public/
|
||||||
|
│ └── css/
|
||||||
|
│ └── style.css # Responsive Styling
|
||||||
|
└── views/
|
||||||
|
└── index.ejs # Haupttemplate mit Client-Side Logic
|
||||||
|
```
|
||||||
|
|
||||||
|
## Datenbank-Design
|
||||||
|
|
||||||
|
### Tabelle: `rally_logs`
|
||||||
|
```sql
|
||||||
|
CREATE TABLE rally_logs (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_name TEXT NOT NULL,
|
||||||
|
district TEXT NOT NULL,
|
||||||
|
beisel_name TEXT NOT NULL,
|
||||||
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Zweck:** Server-seitige Speicherung aller Rallye-Einträge für persistente Multi-User-Fähigkeit.
|
||||||
|
|
||||||
|
## API-Endpunkte (geplant)
|
||||||
|
|
||||||
|
### Aktuelle Situation
|
||||||
|
Derzeit wird **nur localStorage** im Browser genutzt. Die SQLite-Datenbank ist vorhanden, wird aber nicht integriert.
|
||||||
|
|
||||||
|
### Zu implementierende Endpunkte:
|
||||||
|
- `POST /api/visit` - Neuen Bezirk besuchen
|
||||||
|
- `GET /api/status/:username` - Fortschritt abrufen
|
||||||
|
- `GET /api/all-users` - Alle Teilnehmer anzeigen
|
||||||
|
- `DELETE /api/reset/:username` - Reset für User
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Nginx Konfiguration
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name aufeins.click.jetzt;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/aufeins.click.jetzt/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/aufeins.click.jetzt/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://192.168.0.187:8083;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Server Starten
|
||||||
|
```bash
|
||||||
|
cd /home/claw/.openclaw/agents/wisp/workspace/beisel-rally
|
||||||
|
node index.js
|
||||||
|
# Server läuft auf http://localhost:8083
|
||||||
|
```
|
||||||
|
|
||||||
|
## Entwicklungs-Status
|
||||||
|
|
||||||
|
### ✅ Abgeschlossen
|
||||||
|
- Grundlegende Frontend-Struktur
|
||||||
|
- Responsive Design mit Mobile-Support
|
||||||
|
- User-Auswahl und -Verwaltung (localStorage)
|
||||||
|
- Fortschrittsanzeige
|
||||||
|
- Wirtshaus-Theme Implementierung
|
||||||
|
|
||||||
|
### ❌ Offene Punkte
|
||||||
|
1. **SQLite-Integration** - API-Endpunkte für Datenbank-Zugriff
|
||||||
|
2. **Server-Datenpersistenz** - localStorage → Server-Side Storage
|
||||||
|
3. **Deployment** - Backend-Server auf 192.168.0.187:8083 starten
|
||||||
|
4. **Sicherheit** - Input Validation, Rate Limiting
|
||||||
|
5. **Export/Import** - Backup-Funktionalität
|
||||||
|
|
||||||
|
## Nächste Schritte
|
||||||
|
|
||||||
|
### Kurzfristig (Prio 1)
|
||||||
|
- [ ] API-Endpunkte für SQLite-Datenbank implementieren
|
||||||
|
- [ ] Client-Seite anpassen um API zu nutzen
|
||||||
|
- [ ] Server starten und testen
|
||||||
|
|
||||||
|
### Mittelfristig (Prio 2)
|
||||||
|
- [ ] Authentifizierung hinzufügen
|
||||||
|
- [ ] Leaderboard implementieren
|
||||||
|
- [ ] Export/Import Funktionalität
|
||||||
|
|
||||||
|
### Langfristig (Prio 3)
|
||||||
|
- [ ] Mobile App (Progressive Web App)
|
||||||
|
- [ ] Social Features (Teilen, Einladungen)
|
||||||
|
- [ ] Anbindung an bestehende Beisel-Datenbank
|
||||||
|
|
||||||
|
## Kontakt & Credits
|
||||||
|
|
||||||
|
Projekt erstellt von Gregor. Entwicklung durch Wisp (AI Coding Agent).
|
||||||
|
|
||||||
|
**Domain:** aufeins.click.jetzt
|
||||||
|
**Server:** 192.168.0.187:8083
|
||||||
|
**Gitea:** http://gitea.click.jetzt:3000/clawdia/beisel-rally
|
||||||
|
|
||||||
|
---
|
||||||
|
*Prost! 🍻*
|
||||||
Binary file not shown.
@@ -0,0 +1,26 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = 8083;
|
||||||
|
|
||||||
|
// Kein Caching für HTML
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
||||||
|
res.set('Pragma', 'no-cache');
|
||||||
|
res.set('Expires', '0');
|
||||||
|
res.set('Surrogate-Control', 'no-store');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
app.set('view engine', 'ejs');
|
||||||
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.render('index');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Beisel-Rallye läuft auf http://localhost:${port}`);
|
||||||
|
});
|
||||||
Generated
+1548
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "beisel-rally",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^2.2.2",
|
||||||
|
"ejs": "^6.0.1",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"sqlite3": "^6.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Beisel-Rallye läuft auf http://localhost:8083
|
||||||
Reference in New Issue
Block a user