382 lines
9.9 KiB
Markdown
382 lines
9.9 KiB
Markdown
# 🎪 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# .env einrichten
|
|
cp .env.example .env
|
|
php artisan key:generate
|
|
|
|
# MariaDB konfigurieren
|
|
# DB_CONNECTION=mysql
|
|
# DB_DATABASE=veranstaltungen_app
|
|
```
|
|
|
|
### 3. Datenbank
|
|
|
|
```bash
|
|
# Migrations ausführen
|
|
php artisan migrate
|
|
|
|
# Event-Quellen erstellen
|
|
php artisan tinker
|
|
>>> \App\Models\Source::create(['name' => 'Stadt Dresden', 'status' => 'active']);
|
|
```
|
|
|
|
### 4. Events importieren
|
|
|
|
```bash
|
|
# Synchron (blockierend)
|
|
php artisan events:import --sync
|
|
|
|
# Oder asynchron (Queue)
|
|
php artisan events:import
|
|
php artisan queue:work --verbose # Worker starten
|
|
```
|
|
|
|
### 5. API testen
|
|
|
|
```bash
|
|
# 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`](docs/SETUP.md) | Komplette Installations- & Setup-Anleitung |
|
|
| [`EXAMPLE_QUERIES.php`](docs/EXAMPLE_QUERIES.php) | 10+ Eloquent Query-Beispiele |
|
|
| [`API_RESPONSES.md`](docs/API_RESPONSES.md) | API Endpoint-Doku mit Response-Beispielen |
|
|
| [`IMPORT_SCRAPER_INTEGRATION.md`](docs/IMPORT_SCRAPER_INTEGRATION.md) | Import/Scraper, Queue, Scheduler, Rate Limiting |
|
|
| [`KERNEL_SCHEDULER_EXAMPLE.php`](docs/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:**
|
|
```json
|
|
{
|
|
"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](docs/API_RESPONSES.md)
|
|
|
|
## 🎯 Datenmodell
|
|
|
|
### Events ↔ EventOccurrences (1:N Beziehung)
|
|
|
|
Ein **Event** ist eine Veranstaltung mit stabilen Eigenschaften:
|
|
- `title`, `description`, `location`, `category`
|
|
- `slug` (für SEO-URLs)
|
|
- `status` (draft, published, archived)
|
|
|
|
Ein **EventOccurrence** ist ein einzelner Termin mit Zeitinformation:
|
|
- `start_datetime`, `end_datetime`
|
|
- `is_all_day` (ganztägig?)
|
|
- `location_details` (z.B. "Saal A")
|
|
- `capacity`, `available_tickets`
|
|
- `price`
|
|
- `status` (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](docs/IMPORT_SCRAPER_INTEGRATION.md)
|
|
|
|
## 🛠️ Commands & Artisan
|
|
|
|
```bash
|
|
# 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
|
|
|
|
1. **Queue Worker setup** (Supervisor)
|
|
2. **Scheduler Cron-Job** (täglicher Scheduler:run)
|
|
3. **Redis/Beanstalkd** für Queue (statt database)
|
|
4. **Error Monitoring** (Sentry, etc.)
|
|
5. **Backup** vor Production-Launch
|
|
|
|
Siehe: 👉 [SETUP.md - Production Deployment](docs/SETUP.md)
|
|
|
|
## 📚 Beispiele
|
|
|
|
### Query: "Nächste 10 Events in Dresden"
|
|
```php
|
|
$events = Event::published()
|
|
->byLocation('Dresden')
|
|
->with(['occurrences' => function ($q) {
|
|
$q->upcoming()->limit(1);
|
|
}])
|
|
->limit(10)
|
|
->get();
|
|
```
|
|
|
|
### Query: "Alle Events am 15. April"
|
|
```php
|
|
$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](docs/EXAMPLE_QUERIES.php)
|
|
|
|
## 🤝 Integration Beispiele
|
|
|
|
### Stadt-Dresden-API
|
|
```php
|
|
$response = Http::get('https://api.stadt-dresden.de/events', [
|
|
'limit' => 1000,
|
|
]);
|
|
```
|
|
|
|
### Web-Scraping
|
|
```bash
|
|
composer require symfony/dom-crawler
|
|
```
|
|
|
|
### Google-Calendar (iCal)
|
|
```php
|
|
$feed = file_get_contents('https://calendar.google.com/.../basic.ics');
|
|
// Parse mit Spatie iCalendar Parser
|
|
```
|
|
|
|
## 🐛 FAQ & Troubleshooting
|
|
|
|
**F: Migrations schlagen fehl**
|
|
```bash
|
|
A: MariaDB Version checken, dann:
|
|
php artisan migrate:refresh
|
|
php artisan migrate
|
|
```
|
|
|
|
**F: Queue-Jobs werden nicht verarbeitet**
|
|
```bash
|
|
A: Worker-Prozess nicht laufend?
|
|
php artisan queue:work --verbose
|
|
```
|
|
|
|
**F: API gibt 404 zurück**
|
|
```bash
|
|
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
|
|
|
|
---
|
|
|
|
### 📖 Dokumentation starten mit:
|
|
👉 [**SETUP.md** - Installations-Anleitung](docs/SETUP.md)
|
|
|