Veranstaltungen-APP/docs/SETUP.md

479 lines
11 KiB
Markdown

# 🎉 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