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

```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)
=======
# Veranstaltungen-APP
>>>>>>> 220c3e47427d7ebd5927cd513bf43274163b5d0a

