| app | ||
| bootstrap | ||
| config | ||
| database | ||
| docs | ||
| public | ||
| resources | ||
| routes | ||
| storage | ||
| tests | ||
| vendor | ||
| .editorconfig | ||
| .env | ||
| .env.example | ||
| API_AUTHENTICATION_GUIDE.md | ||
| artisan | ||
| check_events.php | ||
| composer.json | ||
| composer.lock | ||
| IMPLEMENTATION_CHECKLIST.md | ||
| IMPLEMENTATION_REPORT.md | ||
| package.json | ||
| phpunit.xml | ||
| README.md | ||
| TESTING_GUIDE.md | ||
| vite.config.js | ||
<<<<<<< HEAD
🎪 Veranstaltungen-App Dresden - Laravel Event Portal
Ein modernes, skalierbares Event-Portal für Dresden mit automatisiertem Import aus externen Veranstaltungsquellen (APIs, Web-Scraping).
⚡ Features
✅ Event-Management
- Veranstaltungen mit mehreren Terminen/Öffnungszeiten
- Flexible Kategorisierung und Ortsfilter
- Slug-basierte SEO-URLs
- Soft Deletes (weiche Löschung)
✅ Datenquellen-Integration
- Multi-Source Import (Stadt Dresden, Kulturzentrum, etc.)
- Queue-basierte asynchrone Verarbeitung
- Upsert-Logik (automatisches Update bei Duplikaten)
- Last-Import-Tracking
✅ REST API
/api/events- Events mit Filtern (Datum, Kategorie, Ort)/api/events/{id}- Einzelnes Event mit allen Terminen/api/events/categories/list- Verfügbare Kategorien/api/events/locations/list- Verfügbare Orte
✅ Scheduler-Integration
- Tägliche automatische Imports (03:00 Uhr)
- Stündliche Updates für häufig aktualisierte Quellen
- Automatische Wartung (markiere abgelaufene Termine, Archive)
🏗️ Technologie-Stack
| Komponente | Technologie |
|---|---|
| PHP | 8.2+ |
| Framework | Laravel 11 LTS |
| Datenbank | MariaDB 10.4+ |
| Task-Verarbeitung | Queue (database/redis/beanstalkd) |
| Scheduling | Laravel Scheduler + Cron |
| HTTP-Client | Laravel HTTP Client / Guzzle |
| Web-Scraping | Symfony DomCrawler (optional) |
📁 Projektstruktur
Veranstaltungen-APP/
├── app/
│ ├── Models/ # Eloquent Models
│ │ ├── Source.php # Quelle (Stadt Dresden, etc.)
│ │ ├── Event.php # Veranstaltung
│ │ └── EventOccurrence.php # Einzelne Termine/Öffnungszeiten
│ ├── Http/Controllers/
│ │ └── EventController.php # REST API Controller
│ ├── Jobs/
│ │ └── ImportEventsJob.php # Queue Job für Event-Import
│ ├── Commands/
│ │ └── ImportEventsCommand.php # Artisan Command
│ └── Services/
│ └── EventImportService.php # Import-Business-Logic
│
├── database/
│ └── migrations/ # Database Schema
│ ├── create_sources_table.php
│ ├── create_events_table.php
│ └── create_event_occurrences_table.php
│
├── routes/
│ └── api.php # REST API Routen
│
└── docs/ # 📚 Dokumentation
├── SETUP.md # Installation & Setup-Anleitung
├── EXAMPLE_QUERIES.php # 10+ Eloquent Query-Beispiele
├── API_RESPONSES.md # API Response-Formate
├── IMPORT_SCRAPER_INTEGRATION.md # Import/Scraper-Dokumentation
└── KERNEL_SCHEDULER_EXAMPLE.php # Scheduler-Konfiguration
🚀 Quick Start
1. Installation
# Frisches Laravel-Projekt
composer create-project laravel/laravel Veranstaltungen-APP
cd Veranstaltungen-APP
# Dateien aus diesem Paket kopieren
# (siehe SETUP.md für detaillierte Anleitung)
2. Konfiguration
# .env einrichten
cp .env.example .env
php artisan key:generate
# MariaDB konfigurieren
# DB_CONNECTION=mysql
# DB_DATABASE=veranstaltungen_app
3. Datenbank
# Migrations ausführen
php artisan migrate
# Event-Quellen erstellen
php artisan tinker
>>> \App\Models\Source::create(['name' => 'Stadt Dresden', 'status' => 'active']);
4. Events importieren
# Synchron (blockierend)
php artisan events:import --sync
# Oder asynchron (Queue)
php artisan events:import
php artisan queue:work --verbose # Worker starten
5. API testen
# Events auflisten
curl "http://localhost:8000/api/events?from=2026-04-15&to=2026-05-31&location=Dresden"
# Einzelnes Event
curl "http://localhost:8000/api/events/1"
📚 Dokumentation
| Datei | Inhalt |
|---|---|
SETUP.md |
Komplette Installations- & Setup-Anleitung |
EXAMPLE_QUERIES.php |
10+ Eloquent Query-Beispiele |
API_RESPONSES.md |
API Endpoint-Doku mit Response-Beispielen |
IMPORT_SCRAPER_INTEGRATION.md |
Import/Scraper, Queue, Scheduler, Rate Limiting |
KERNEL_SCHEDULER_EXAMPLE.php |
Komplette Scheduler-Konfiguration |
🔑 API Endpoints
📋 Events auflisten
GET /api/events
?from=2026-04-15 # Ab Datum (Standard: heute)
&to=2026-05-31 # Bis Datum (Standard: +3 Monate)
&category=Kultur # Nach Kategorie
&location=Dresden # Nach Ort
&limit=20 # Pro Seite
Response:
{
"success": true,
"data": [
{
"id": 1,
"title": "Ostermarkt",
"location": "Dresden",
"category": "Kultur",
"occurrences": [
{
"id": 5,
"start_datetime": "2026-04-18T10:00:00+02:00",
"end_datetime": "2026-04-20T18:00:00+02:00"
}
]
}
],
"pagination": { "total": 42, "per_page": 20, "current_page": 1 }
}
Weitere Endpoints: 👉 Siehe API_RESPONSES.md
🎯 Datenmodell
Events ↔ EventOccurrences (1:N Beziehung)
Ein Event ist eine Veranstaltung mit stabilen Eigenschaften:
title,description,location,categoryslug(für SEO-URLs)status(draft, published, archived)
Ein EventOccurrence ist ein einzelner Termin mit Zeitinformation:
start_datetime,end_datetimeis_all_day(ganztägig?)location_details(z.B. "Saal A")capacity,available_ticketspricestatus(scheduled, cancelled, completed)
Beispiel:
📌 Event: "Ostermarkt auf der Altstadt"
├─ 🗓️ Occurrence 1: Sa 18.04., 10:00-18:00 (Kapazität: 1000)
├─ 🗓️ Occurrence 2: So 19.04., 10:00-18:00 (Kapazität: 1000)
└─ 🗓️ Occurrence 3: Mo 20.04., 10:00-18:00 (Kapazität: 800)
📊 Import-Workflow
External Source (API/Scraper)
↓
ImportEventsCommand
↓
ImportEventsJob (Queue)
↓
upsertEvent() [updateOrCreate]
↓
upsertOccurrences() [updateOrCreate]
↓
Database (MariaDB)
↓
REST API
Upsert-Logik:
- Events werden anhand
[source_id, external_id]abgeglichen - Existierende Events werden aktualisiert
- Neue Events werden angelegt
- Verhindert Duplikate durch Unique Index
⏰ Geplante Imports (Scheduler)
Die Integration mit Laravel Scheduler (tägliche Cron-Regel):
03:00 Uhr → Täglich alle Quellen importieren
Stündlich → Stadt-Dresden-Quelle (häufige Updates)
Alle 6h → Andere Quellen
04:00 Uhr → Markiere abgelaufene Termine
Sonntag → Archive alte Events
Weitere Details: 👉 IMPORT_SCRAPER_INTEGRATION.md
🛠️ Commands & Artisan
# Manueller Import
php artisan events:import [--source=ID|Name] [--sync]
# Queue Worker starten
php artisan queue:work --verbose
# Scheduler testen (nur für Entwicklung)
php artisan schedule:run
# Queue debuggen
php artisan queue:failed
php artisan queue:retry {id}
php artisan queue:flush
🔐 Best Practices (implementiert)
✅ Datenbank-Design:
- Foreign Keys mit CASCADE DELETE
- Composite Indizes für häufige Filter-Kombinationen
- Unique Index auf
[source_id, external_id]gegen Duplikate - MariaDB-spezifische Optimierungen (InnoDB Engine, utf8mb4)
✅ Code-Qualität:
- Eloquent Models mit Relationships & Scopes
- Type Hints (PHP 8.2+)
- Request Validation
- Error Logging
- Transaction Support
✅ Performance:
- Query Optimization mit eager loading (
.with()) - Effiziente Composite Indizes
- Pagination für API-Response
- Queue-basierte Background Jobs
✅ Wartbarkeit:
- Service-Layer für Business Logic
- Commands für CLI-Interface
- Job-Klassen für Queue-Verarbeitung
- Dokumentierte Code-Beispiele
🚀 Production Deployment
- Queue Worker setup (Supervisor)
- Scheduler Cron-Job (täglicher Scheduler:run)
- Redis/Beanstalkd für Queue (statt database)
- Error Monitoring (Sentry, etc.)
- Backup vor Production-Launch
Siehe: 👉 SETUP.md - Production Deployment
📚 Beispiele
Query: "Nächste 10 Events in Dresden"
$events = Event::published()
->byLocation('Dresden')
->with(['occurrences' => function ($q) {
$q->upcoming()->limit(1);
}])
->limit(10)
->get();
Query: "Alle Events am 15. April"
$date = Carbon::parse('2026-04-15');
$events = Event::published()
->with(['occurrences' => function ($q) use ($date) {
$q->onDate($date)->scheduled();
}])
->whereHas('occurrences', function ($q) use ($date) {
$q->onDate($date)->scheduled();
})
->get();
Weitere: 👉 EXAMPLE_QUERIES.php
🤝 Integration Beispiele
Stadt-Dresden-API
$response = Http::get('https://api.stadt-dresden.de/events', [
'limit' => 1000,
]);
Web-Scraping
composer require symfony/dom-crawler
Google-Calendar (iCal)
$feed = file_get_contents('https://calendar.google.com/.../basic.ics');
// Parse mit Spatie iCalendar Parser
🐛 FAQ & Troubleshooting
F: Migrations schlagen fehl
A: MariaDB Version checken, dann:
php artisan migrate:refresh
php artisan migrate
F: Queue-Jobs werden nicht verarbeitet
A: Worker-Prozess nicht laufend?
php artisan queue:work --verbose
F: API gibt 404 zurück
A: php artisan serve
dann http://localhost:8000/api/events testen
📄 Lizenz
Laravel ist unter der MIT-Lizenz lizenziert.
👨💻 Autor
Vollständig arbeitsfertiges Event-Portal für Dresden Erstellt: 9. April 2026