# 🎉 Laravel Event-Portal - Vollständige Implementierung Dieses Projekt ist ein vollständig arbeitsfertiges Event-Portal für Dresden mit Integration von externen Veranstaltungsquellen. --- ## 📋 Projektstruktur ``` Veranstaltungen-APP/ ├── app/ │ ├── Models/ │ │ ├── Source.php # Quelle (z.B. Stadt Dresden) │ │ ├── Event.php # Veranstaltung │ │ └── EventOccurrence.php # Einzelne Termine │ ├── Http/Controllers/ │ │ └── EventController.php # REST API Controller │ ├── Jobs/ │ │ └── ImportEventsJob.php # Queue Job für Import │ ├── Commands/ │ │ └── ImportEventsCommand.php # Artisan Command für manuellen Import │ ├── Services/ │ │ └── EventImportService.php # Business Logic Service │ ├── database/ │ └── migrations/ │ ├── 2026_04_09_000001_create_sources_table.php │ ├── 2026_04_09_000002_create_events_table.php │ └── 2026_04_09_000003_create_event_occurrences_table.php │ ├── routes/ │ └── api.php # REST API Routen │ ├── docs/ │ ├── SETUP.md # Diese Datei │ ├── EXAMPLE_QUERIES.php # Eloquent Query-Beispiele │ ├── API_RESPONSES.md # API Response-Formate │ ├── IMPORT_SCRAPER_INTEGRATION.md # Import-Dokumentation │ └── KERNEL_SCHEDULER_EXAMPLE.php # Scheduler-Konfiguration ``` --- ## ⚙️ Installation & Setup ### 1. Frisches Laravel-Projekt erstellen ```bash # Laravel 11 LTS (oder aktuelle LTS) composer create-project laravel/laravel Veranstaltungen-APP cd Veranstaltungen-APP ``` ### 2. Diese Dateien in das Projekt kopieren ```bash # Kopiere alle PHP/Migration-Dateien aus diesem Package # in die entsprechenden Verzeichnisse # Beispiel: cp app/Models/*.php ./app/Models/ cp app/Http/Controllers/*.php ./app/Http/Controllers/ cp app/Jobs/*.php ./app/Jobs/ cp app/Commands/*.php ./app/Commands/ cp app/Services/*.php ./app/Services/ cp database/migrations/*.php ./database/migrations/ cp routes/api.php ./routes/ ``` ### 3. Umgebungsvariablen konfigurieren ```bash # .env erstellen cp .env.example .env # Schüssel generieren php artisan key:generate ``` Bearbeite `.env`: ```env DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=veranstaltungen_app DB_USERNAME=root DB_PASSWORD= QUEUE_CONNECTION=database MAIL_FROM_ADDRESS=noreply@veranstaltungen-app.de ``` ### 4. Datenbank & Migrations ```bash # Datenbank erstellen (MariaDB) mysql -u root -p -e "CREATE DATABASE veranstaltungen_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" # Migrations ausführen php artisan migrate # Optionale Fixtures/Seeds laden php artisan db:seed --class=SourceSeeder ``` ### 5. Queue für Imports vorbereiten ```bash # Queue-Tabelle erstellen php artisan queue:table php artisan migrate # Queue Worker starten (Development) php artisan queue:work --verbose ``` --- ## 🚀 Erste Schritte ### Event-Quellen erstellen ```bash # Interaktiv via Artisan Tinker php artisan tinker >>> $source = \App\Models\Source::create([ ... 'name' => 'Stadt Dresden', ... 'description' => 'Offizielle Veranstaltungen der Stadt', ... 'url' => 'https://stadt-dresden.de', ... 'status' => 'active', ... ]); ``` ### Events importieren ```bash # Manueller Import (blockierend) php artisan events:import --sync # Oder asynchron in Queue php artisan events:import # Queue Worker muss laufen für Verarbeitung: php artisan queue:work ``` ### API testen ```bash # Events auflisten curl "http://localhost:8000/api/events?from=2026-04-15&to=2026-05-31&limit=10" # Ein Event anzeigen curl "http://localhost:8000/api/events/1" # Verfügbare Kategorien curl "http://localhost:8000/api/events/categories/list" # Verfügbare Orte curl "http://localhost:8000/api/events/locations/list" ``` --- ## 📚 Dokumentation ### Für Event-Queries siehe: 👉 [EXAMPLE_QUERIES.php](EXAMPLE_QUERIES.php) ### Für API-Endpoints siehe: 👉 [API_RESPONSES.md](API_RESPONSES.md) ### Für Import/Scraper-Integration siehe: 👉 [IMPORT_SCRAPER_INTEGRATION.md](IMPORT_SCRAPER_INTEGRATION.md) ### Für Scheduler-Setup siehe: 👉 [KERNEL_SCHEDULER_EXAMPLE.php](KERNEL_SCHEDULER_EXAMPLE.php) --- ## 🔑 API-Endpoints | Methode | Endpoint | Beschreibung | |---------|----------|-------------| | GET | `/api/events` | Events mit Filtern auflisten | | GET | `/api/events/{id}` | Einzelnes Event anzeigen | | GET | `/api/events/categories/list` | Verfügbare Kategorien | | GET | `/api/events/locations/list` | Verfügbare Orte | ### Filter-Parameter ``` GET /api/events ?from=2026-04-15 # Ab Datum (YYYY-MM-DD), Standard: heute &to=2026-05-31 # Bis Datum (YYYY-MM-DD), Standard: +3 Monate &category=Kultur # Nach Kategorie filtern &location=Dresden # Nach Ort filtern &limit=20 # Ergebnisse pro Seite (1-100, Standard: 20) ``` --- ## 🎯 Datenmodell ### Events (Veranstaltungen) - `id` - Eindeutige ID - `source_id` - Referenz zur Quelle - `external_id` - ID der Quelle - `title` - Name der Veranstaltung - `description` - Beschreibung - `location` - Ort/Stadt - `category` - Kategorie (z.B. Kultur, Sport) - `slug` - URL-freundlicher Name - `image_url`, `website_url`, `contact_email`, `contact_phone` - `status` - draft | published | archived - `created_at`, `updated_at` ### Event Occurrences (Termine) - `id` - Eindeutige ID - `event_id` - Referenz zum Event - `start_datetime` - Startzeit - `end_datetime` - Endzeit - `is_all_day` - Ganztägig? - `location_details` - Raum/Gebäude - `capacity` - Kapazität - `available_tickets` - Verfügbare Tickets - `price` - Preis (optional) - `status` - scheduled | cancelled | completed ### Sources (Quellen) - `id` - Eindeutige ID - `name` - Name der Quelle - `description` - Beschreibung - `url` - Website URL - `status` - active | inactive - `last_import_at` - Letzter Import-Zeitpunkt --- ## 🔄 Import-Workflow ``` 1. External Source (z.B. Stadt Dresden API) ↓ 2. ImportEventsCommand / EventImportService ↓ 3. ImportEventsJob (läuft in Queue) ↓ 4. fetchExternalEvents() - Ruft externe Daten ab ↓ 5. upsertEvent() - Erstellt oder aktualisiert Event+Occurrences ↓ 6. Database (MySQL/MariaDB) ↓ 7. API (für Frontend verfügbar) ``` ### Upsert-Logik - Events werden anhand `[source_id, external_id]` abgeglichen - Existierende Events = Update - Neue Events = Insert - Verhindert Duplikate durch Unique Index --- ## ⏰ Geplante Imports (Scheduler) In `app/Console/Kernel.php` (siehe Beispiel): - **03:00 Uhr** - Täglich alle Quellen importieren - **Stündlich** - Stadt-Dresden-Quelle (häufige Updates) - **Alle 6 Stunden** - Andere Quellen - **04:00 Uhr** - Markiere abgelaufene Termine - **Sonntag 05:00** - Räume archivierte Events auf --- ## 🛠️ Commands ```bash # Event-Import php artisan events:import [--source=ID|Name] [--sync] # Queue einrichten php artisan queue:table php artisan migrate # Queue Worker starten (Development) php artisan queue:work [--verbose] [--tries=3] [--timeout=120] # Failed Jobs anzeigen php artisan queue:failed php artisan queue:retry ID php artisan queue:forget ID # Alle Jobs leeren php artisan queue:flush # Cache leeren php artisan cache:clear # Logs leeren php artisan log:prune # Datenbank frisch seeden php artisan migrate:refresh --seed ``` --- ## 📊 Datenbank-Indizes Die Migrationen erstellen folgende Indizes für Performance: **sources:** - `status` (Filter nach aktiv/inaktiv) - `created_at` (Sortierer) **events:** - `source_id` (Foreign Key) - `slug` (Unique, für SEO-URLs) - `[location, status]` (Composite Index für Location-Filter) - `[category, status]` (Composite Index für Kategorie-Filter) - `created_at` (Neueste zuerst) - `[source_id, external_id]` (Unique, verhindert Duplikate) **event_occurrences:** - `event_id` (Foreign Key) - `start_datetime` (Filter nach Datum) - `[start_datetime, status]` (Composite Index für "nächste Events") - `[event_id, status]` (Filter nach Event & Status) --- ## 🔐 Security-Best-Practices ✅ **Implementiert:** - SQL-Injections vermieden (Eloquent ORM) - CSRF-Schutz (Laravel Standard) - Rate Limiting für APIs - Input Validation in Controllers - Soft Deletes für Datenintegrität ⚠️ **Zu implementieren:** - API-Authentifizierung (Laravel Passport/Sanctum) - Request Throttling - CORS-Konfiguration - Content Security Policy --- ## 🐛 Troubleshooting ### Migrations schlagen fehl ```bash # Checke MariaDB Version mysql --version # Migrations zurückrollen php artisan migrate:reset # Neu starten php artisan migrate ``` ### Queue-Jobs werden nicht verarbeitet ```bash # Worker-Prozess läuft? ps aux | grep "queue:work" # Queue starten (Development) php artisan queue:work --verbose ``` ### API gibt 404 zurück ```bash # Checke Routes php artisan route:list # Starte Server php artisan serve ``` ### Zu viel Memory-Verbrauch ```bash # Optimize Autoloader composer install --optimize-autoloader --no-dev # Disable Query Logging in Production # In .env: APP_DEBUG=false ``` --- ## 📈 Production Deployment ### Vorbereitung ```bash # .env für Production APP_ENV=production APP_DEBUG=false QUEUE_CONNECTION=redis # oder beanstalkd LOG_CHANNEL=stack ``` ### Cron-Job einrichten (Scheduler) ```bash # /etc/cron.d/laravel-scheduler * * * * * cd /path/to/app && php artisan schedule:run >> /dev/null 2>&1 ``` Oder mit systemd: ```bash # supervisor für Queue Workers [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /path/to/app/artisan queue:work redis --sleep=3 --tries=3 --timeout=90 autostart=true autorestart=true numprocs=4 redirect_stderr=true stdout_logfile=/path/to/app/storage/logs/worker.log ``` --- ## 🤝 Weitere Integration ### Beispiel: Import aus Stadt-Dresden-API Bearbeite `app/Jobs/ImportEventsJob.php`: ```php protected function fetchExternalEvents() { $response = Http::withHeaders([ 'Accept' => 'application/json', ])->get('https://api.stadt-dresden.de/events', [ 'limit' => 1000, ]); return $response->json('data'); } ``` ### Beispiel: Web-Scraping ```bash composer require symfony/dom-crawler symfony/http-client ``` Dann in Import-Service: ```php use Symfony\Component\DomCrawler\Crawler; $response = Http::get('https://example.com/events'); $crawler = new Crawler($response->body()); // ... scrape & extract events ``` --- ## 📞 Support & Weitere Ressourcen - [Laravel Documentation](https://laravel.com/docs) - [Laravel Queue Driver Comparison](https://laravel.com/docs/queues) - [Laravel Scheduler](https://laravel.com/docs/scheduling) - [Symfony DomCrawler](https://symfony.com/doc/current/components/dom_crawler.html) --- **Version:** 1.0 **Laravel:** 11 LTS **PHP:** 8.2+ **Database:** MariaDB 10.4+ **Erstellt:** 9. April 2026