Veranstaltungen-APP/README.md

9.9 KiB

<<<<<<< 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, 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

🛠️ 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

  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

📚 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


📖 Dokumentation starten mit:

👉 SETUP.md - Installations-Anleitung

Veranstaltungen-APP

220c3e4742