- 📱 Progressive Web App - Installierbar auf allen Geräten, funktioniert offline
- 🔄 Vollständig Wiederverwendbar - Eine einzige
event.jsonfür jede Veranstaltung - 🌍 Mehrsprachig - Integrierte i18n-Unterstützung (Deutsch/Englisch)
- ⚡ Performance-Optimiert - Cache-Busting, Service Worker, Lazy Loading
- 📊 Event-Features - Sessionpläne, Zeitpläne, Speisekarten, Sponsoren, Voting
- 🎨 Auto-Branding - PWA-Icons werden automatisch aus einem einzigen Quellbild generiert
- 🧪 100% Getestet - Playwright-Tests für Übersetzungen, PWA, UI/UX
- 🐳 Docker Ready - Entwicklungsumgebung mit einem Befehl
Live: https://app.devops-camp.de oder https://app.joomladay.de
- Quick Start
- Screenshots
- Konfiguration
- Voting-System
- Entwicklung
- Internationalisierung (i18n)
- Architektur
- Lizenz
# 1. Repository klonen
git clone <repository-url>
cd pccampapp
# 2. Node.js Dependencies
make install
# 3. Entwicklungsserver starten (Docker)
make dev-up
# 4. Browser öffnen
open http://localhost:5173Das war's! Die App läuft jetzt mit Live-Reload.
# 1. Live-Preview starten (Docker)
make prod-up
# 2. Browser öffnen
open http://localhost:5174
# Build erstellen (/build-Ordner)
# wird auch mit prod-up erstellt
make buildBuild-Inhalt auf Server laden! Die App läuft jetzt als PWA.
Die gesamte App ist konfigurationsgesteuert über eine einzige Datei: event.json
# 1. Event-Konfiguration bearbeiten
vim event.json
# 2. Branding-Assets ersetzen (nur 2 Dateien!)
cp ihr-logo.png src/assets/logo.png
cp ihr-icon.png src/assets/icon.png # PWA-Icons werden automatisch generiert!
# 3. Eventspezifische Inhalte aktualisieren
vim src/sessionplan/sessions.json # Sessionplan-Daten
vim src/timetable/timetable.json # Zeitplan-Daten
vim src/news.json # Event-News
vim src/menu.json # Navigation
vim src/food/menue.json # Speisekarten
vim src/food/allergene.json # Allergen-Informationen
vim src/sponsors/sponsors.json # Sponsoren-Liste
# 4. Bauen & deployen
make buildKeine Code-Änderungen nötig! Das Build-System automatisch:
- Ersetzt alle
{{EVENT_NAME}}-Platzhalter in HTML - Generiert PWA-Manifest aus der Konfiguration
- Erstellt alle PWA-Icons (16x16, 144x144, 192x192, 512x512)
- Wendet Theme-Farben an
Die App verwendet mehrere JSON-Dateien für eventspezifische Inhalte. Diese müssen für jede neue Veranstaltung angepasst werden:
Strukturiert Sessions nach Tagen und Zeitslots:
{
"samstag": {
"11:00 - 12:00": [
{
"id": "10",
"room": "Raum Alpha",
"title": "Einführung in moderne Entwicklungsmethoden",
"host": "Max Mustermann",
"votes": 0,
"cancelled": false
}
]
},
"sonntag": {
"10:00 - 11:00": [
{
"id": "100",
"room": "Raum Beta",
"title": "Erfahrungsaustausch",
"host": "Lisa Schmidt",
"votes": 0,
"cancelled": false
}
]
}
}Zeitplan für das gesamte Event:
{
"freitag": {
"18:00 - 21:00 Uhr": [
{
"room": "Empfangsbereich",
"title": "Check-in und Networking"
}
]
},
"samstag": {
"09:30 Uhr": [
{
"room": "Hauptraum",
"title": "Begrüßung und Vorstellungsrunde"
}
]
}
}Event-News mit Zeitfenstern:
{
"permanent": [
{
"id": "1",
"content": "Willkommen zur Event-Demo!",
"priority": "medium"
}
],
"days": {
"2025-11-15": [
{
"id": "10",
"content": "Die Türen öffnen um 18:00 Uhr.",
"timeFrom": "16:00",
"timeTo": "20:00",
"priority": "high"
}
]
}
}Menü nach Tagen und Mahlzeiten:
{
"samstag": {
"Frühstück": [
{
"name": "Brötchen-Auswahl",
"variants": [
{
"name": "Vollkorn",
"allergens": ["A"]
}
]
}
],
"Mittagessen": [
{
"name": "Pasta-Station",
"variants": [
{
"name": "Bolognese",
"allergens": ["A", "G", "I"]
}
]
}
]
}
}Allergen-Codes und Beschreibungen:
{
"A": "Glutenhaltiges Getreide",
"C": "Eier",
"G": "Milch",
"I": "Fleisch",
"L": "Schwefeldioxid und Sulfite"
}Sponsoren-Liste:
{
"sponsors": [
{
"name": "Sponsor 1",
"logo": "sponsor-placeholder.png",
"url": "https://example.com",
"beschreibung": "Beschreibung des Sponsors"
}
]
}Hauptnavigation der App:
{
"items": [
{
"title": "Sessionplan",
"url": "/sessionplan/",
"description": "",
"icon": "calendar",
"active": true
},
{
"title": "WLAN",
"url": "",
"description": "EventWiFi / test123",
"icon": "wifi",
"active": true
}
]
}Schritt-für-Schritt-Anleitung:
-
Sessionplan aktualisieren (
src/sessionplan/sessions.json):- Tage anpassen (z.B.
samstag,sonntag→freitag,samstag) - Zeitslots anpassen (z.B.
11:00 - 12:00→10:00 - 11:00) - Raum-Namen aktualisieren
- Session-Titel, Hosts und IDs anpassen
- Tage anpassen (z.B.
-
Zeitplan erstellen (
src/timetable/timetable.json):- Event-Tage definieren
- Zeitslots mit Räumen und Aktivitäten hinzufügen
- Struktur:
"Tag": { "Zeit": [{"room": "Raum", "title": "Aktivität"}] }
-
News konfigurieren (
src/news.json):- Permanente News in
permanentArray - Tages-spezifische News in
daysObjekt - Zeitfenster mit
timeFrom/timeTo(optional) - Prioritäten:
high,medium,low
- Permanente News in
-
Speisekarten erstellen (
src/food/menue.json):- Mahlzeiten nach Tagen strukturieren
- Allergen-Codes aus
allergene.jsonverwenden - Varianten für verschiedene Optionen
-
Sponsoren hinzufügen (
src/sponsors/sponsors.json):- Logo-Dateien in
src/sponsors/ablegen - URLs und Beschreibungen anpassen
- Logo-Dateien in
-
Navigation anpassen (
src/menu.json):- Menüpunkte aktivieren/deaktivieren
- URLs und Beschreibungen aktualisieren
- WLAN-Informationen anpassen
Tipp: Alle JSON-Dateien werden automatisch gehasht und gecacht. Nach Änderungen make build ausführen!
Das Voting-System ermöglicht es Teilnehmern, Sessions zu bewerten und die beliebtesten Sessions zu ermitteln.
Das Voting-System kann über event.json die zeitgesteuer aktiviert werden:
{
"features": {
"voting": true,
"votingSchedule": [
{
"day": "samstag",
"dayLabel": "Samstag",
"dayOfWeek": 6,
"startTime": "16:00",
"endTime": "17:45"
}
],
"votingAdminKey": "dein-geheimes-admin-passwort"
}
}Zusätzlich kann das Voting auch über den Admin-Bereich de/aktiviert oder beendet werden.
- voting: Aktiviert/deaktiviert das Voting-System
- votingSchedule: Zeitfenster für Abstimmungen
day: Interner Tag-Name (z.B. "samstag")dayLabel: Anzeige-Name (z.B. "Samstag")dayOfWeek: Wochentag als Zahl (0=Sonntag, 6=Samstag)startTime/endTime: Zeitfenster für Abstimmungen
- votingAdminKey: Geheimes Passwort für Admin-Bereich
Das Voting-Fenster wird nur angezeigt, wenn alle folgenden Bedingungen erfüllt sind:
// event.json
{
"features": {
"voting": true // ← Muss auf true stehen
}
}// src/votes/voting-state.json
{
"status": "active" // ← Mögliche Werte: "inactive", "active", "ended"
}Der Status kann über den Admin-Bereich geändert werden.
Das aktuelle Datum und die Uhrzeit müssen innerhalb eines konfigurierten Zeitfensters liegen:
// event.json
{
"features": {
"votingSchedule": [
{
"dayOfWeek": 6, // Samstag
"startTime": "16:00", // ← Voting öffnet um 16:00 Uhr
"endTime": "17:45" // ← Voting schließt um 17:45 Uhr
}
]
}
}Prüfung: System vergleicht aktuellen Wochentag (0=Sonntag, 6=Samstag) und Uhrzeit mit der Konfiguration.
Für Entwicklung und Tests kann die Zeitfenster-Prüfung übersprungen werden:
?vote=samstag // Zeigt Voting für z. B. Samstag
Wichtig: Feature-Flag und Admin-Status müssen trotzdem aktiv sein!
1. ✓ voting: true in event.json?
└─ Nein → Kein Voting
└─ Ja → Weiter zu Schritt 2
2. ✓ status: "active" in voting-state.json?
└─ Nein (inactive/ended) → Kein Voting
└─ Ja → Weiter zu Schritt 3
3. ✓ GET-Parameter ?vote=... vorhanden?
└─ Ja → Voting anzeigen (Zeitfenster übersprungen)
└─ Nein → Weiter zu Schritt 4
4. ✓ Aktuelles Datum/Uhrzeit in votingSchedule?
└─ Nein → Kein Voting
└─ Ja → Voting anzeigen
Von Teilnehmern:
- Voting-Button erscheint im Sessionplan während der konfigurierten Zeitfenster
- Jeder Teilnehmer kann eine Stimme pro Tag abgeben
- Abstimmung erfolgt via Browser-Fingerprint (anonymisiert)
- Top 3 Sessions werden mit Medaillen (🥇🥈🥉) angezeigt
Zugriff auf Admin-Bereich und Ergebnisse:
http://localhost:5173/votes/admin.php?key=DEIN-ADMIN-PASSWORT
Features:
- Live-Statistik der des Votings
- De/aktivieren und Beenden von Votings
- Übermitteln der Ergebnisse in die
sessions.jsonfür Winner-Badge-Anzeige (TOP3)
Deployment:
Die votes.json und voting-state.json sollten bei einem Deployment nicht überschrieben werden
| Befehl | Beschreibung |
|---|---|
make install |
Node.js Dependencies installieren |
make build |
Produktionsversion bauen (Cache-Busting) |
make clean |
Vollständige Bereinigung (node_modules, build, Docker) |
make generate-icons |
PWA-Icons aus icon.png generieren |
| Befehl | Beschreibung |
|---|---|
make dev-up |
Entwicklungsserver starten |
make dev-down |
Entwicklungsserver stoppen |
make dev-rebuild |
Docker Image neu bauen (ohne Cache) |
make dev-logs |
Live-Logs anzeigen |
make dev-remove |
Container + Volumes entfernen |
| Befehl | Beschreibung |
|---|---|
make prod-up |
Production-Test-Server starten (inkl. Build) |
make prod-down |
Production-Test-Server stoppen |
make prod-rebuild |
Docker Image neu bauen (ohne Cache) |
make prod-logs |
Live-Logs anzeigen |
make prod-remove |
Container + Volumes entfernen |
| Befehl | Beschreibung |
|---|---|
make test |
Standard Tests (119 Tests, Port 5174, nginx + PHP-FPM) |
make test-php |
Voting/PHP Tests (23 Tests, Port 5174, nginx + PHP-FPM) |
make test-translations |
Übersetzungs-Tests (42 Tests, DE + EN) |
make test-translations-de |
Übersetzungs-Tests nur Deutsch (21 Tests) |
make test-translations-en |
Übersetzungs-Tests nur Englisch (21 Tests) |
make test-all |
Alle Tests (142 Tests, Standard + PHP + Translations) |
make test-headed |
Standard Tests mit sichtbarem Browser |
make test-php-headed |
Voting/PHP Tests mit sichtbarem Browser |
make test-report |
HTML Test-Report öffnen |
- 🇩🇪 Deutsch (
de) - 🇬🇧 Englisch (
en)
Sprache in event.json festlegen:
{
"event": {
"locale": "de"
}
}-
Schlüssel zu
src/translations/de.jsonhinzufügen:{ "myFeature": { "title": "Mein Feature" } } -
Denselben Schlüssel zu
src/translations/en.jsonhinzufügen:{ "myFeature": { "title": "My Feature" } } -
In HTML verwenden:
<h1 data-i18n="myFeature.title">My Feature</h1>
-
Überprüfen:
make test
- Frontend: Vanilla JavaScript (keine Frameworks!)
- Styling: Reines CSS (keine Präprozessoren)
- Backend: PHP (nur Voting-System)
- PWA: Service Worker, Web App Manifest
- Build: Node.js (Cache-Busting, Icon-Generierung)
- Testing: Playwright (Cross-Browser)
- Server: nginx (Docker für Entwicklung)
3-Schichten-Caching-System:
- Service Worker Cache - Offline-Funktionalität
- localStorage Cache - JSON-Daten (1-Stunden-TTL)
- Cache Busting - MD5-gehashte Dateinamen
Beispiel:
app.css→app.b417865e.cssmenu.json→menu.ec9daa78.jsonheader.js→header.e3796179.js
Alle Hash-Updates erfolgen automatisch während des Builds!
- ✅ Installierbar - Zum Startbildschirm hinzufügen (Android, iOS, Desktop)
- ✅ Offline-First - Funktioniert ohne Internet
- ✅ Schnell - Gecachte Assets, sofortiges Laden
- ✅ Responsiv - Mobil, Tablet, Desktop
- ✅ Sicher - HTTPS erforderlich
- ✅ Auto-Updates - Service Worker Updates
Dieses Projekt ist lizenziert unter der GNU Affero General Public License v3.0 (AGPL-3.0).
- ✅ Freie Nutzung - Sie können die Software frei verwenden, modifizieren und verteilen
- ✅ Open Source - Der Quellcode bleibt immer verfügbar
- ✅ SaaS-geschützt - Auch bei Web-Service-Betrieb muss der Code offengelegt werden
⚠️ Copyleft - Änderungen müssen unter derselben Lizenz veröffentlicht werden⚠️ Netzwerk-Nutzung - Bei SaaS-Betrieb muss ein Link zum Quellcode bereitgestellt werden
Für Closed-Source oder proprietäre Nutzung ist eine separate kommerzielle Lizenz erforderlich.
Siehe LICENSE für den vollständigen Lizenztext.
Mit ❤️ entwickelt für das DevOps Camp.
© Proud Commerce | 2025




