# Packages-Design für Fotospiel

## Überblick
Dieses Dokument definiert das neue package-basierte Business Model, das das bestehende Credits-System ersetzt. Packages sind vordefinierte Bündel mit Limits und Features, die als Einmalkäufe pro Event (für Endkunden) oder jährliche Subscriptions (für Reseller/Agenturen) verkauft werden. Das Modell priorisiert Einfachheit: Bei Event-Erstellung wählt der User ein Package, das Limits für diesen Event setzt. Für Reseller limitiert das Tenant-Package die Anzahl Events pro Jahr und globale Features.

Ziele:
- Ersetze Credits vollständig (keine Balance mehr, sondern Event-spezifische Limits).
- Unterstütze Freemium: Free-Paket für Einstieg.
- Skalierbar: Endkunden pro Event, Reseller jährlich.
- Integration: Stripe für Zahlungen (Einmalkäufe/Subscriptions), Ledger für Transaktionen.

## Endkunden-Pakete (pro Event, Einmalkauf)
Diese Pakete werden bei Event-Erstellung ausgewählt und gekauft. Sie definieren Limits für den spezifischen Event (z.B. max_photos, gallery_duration). Preise basierend auf User-Vorschlag.

| Paket     | Preis | max_photos | max_guests | gallery_days | max_tasks | watermark | branding | Extra Features |
|-----------|-------|------------|------------|--------------|-----------|-----------|----------|----------------|
| Free/Test | 0 €  | 30        | 10        | 3           | 1        | Standard | Nein    | -             |
| Starter   | 19 € | 300       | 50        | 14          | 5        | Standard | Nein    | -             |
| Standard  | 39 € | 1000      | 150       | 30          | 10       | Custom   | Ja      | Logo          |
| Premium   | 79 € | 3000      | 500       | 180         | 20       | Kein     | Ja      | Live-Slideshow, Analytics |

## Reseller/Agentur-Pakete (jährlich, Subscription)
Diese Pakete werden auf Tenant-Ebene gekauft und limitieren Events pro Jahr, mit erweiterten Features (z.B. White-Label). Preise als Richtwerte.

| Paket      | Preis/Jahr | max_events/year | Per-Event Limits | Branding | Extra |
|------------|------------|-----------------|------------------|----------|-------|
| Reseller S | 149 €     | 5              | Standard        | Eingeschränkt | -    |
| Reseller M | 299 €     | 15             | Standard        | Eigene Logos | 3 Monate Galerie |
| Reseller L | 599 €     | 40             | Premium         | White-Label  | -    |
| Enterprise | ab 999 €  | Unlimited      | Premium         | Voll       | Custom Domain, Support |

## Datenbank-Schema
### Globale Packages-Tabelle (für alle Pakete, geteilt)
```php
Schema::create('packages', function (Blueprint $table) {
    $table->id();
    $table->string('name'); // z.B. 'Starter', 'Reseller M'
    $table->string('type'); // 'endcustomer' oder 'reseller'
    $table->decimal('price', 8, 2); // Preis in EUR
    $table->integer('max_photos')->nullable(); // Null für Reseller (vererbt an Events)
    $table->integer('max_guests')->nullable();
    $table->integer('gallery_days')->nullable();
    $table->integer('max_tasks')->nullable();
    $table->boolean('watermark_allowed')->default(true);
    $table->boolean('branding_allowed')->default(false);
    $table->integer('max_events_per_year')->nullable(); // Für Reseller
    $table->timestamp('expires_after')->nullable(); // Für Subscriptions
    $table->json('features')->nullable(); // z.B. ['live_slideshow', 'analytics']
    $table->timestamps();
});
```
Seeder: Füge die obigen Pakete ein.

### Event-Packages (Zuordnung Event zu Endkunden-Paket)
```php
Schema::create('event_packages', function (Blueprint $table) {
    $table->id();
    $table->foreignId('event_id')->constrained()->cascadeOnDelete();
    $table->foreignId('package_id')->constrained()->cascadeOnDelete();
    $table->decimal('purchased_price', 8, 2);
    $table->timestamp('purchased_at');
    $table->integer('used_photos')->default(0); // Counter für Limits
    $table->timestamps();
});
```
- Bei Event-Create: Package auswählen/kaufen, Eintrag erstellen.
- Checks: z.B. if ($event->package->used_photos >= $event->package->max_photos) abort(403);

### Tenant-Packages (für Reseller)
```php
Schema::create('tenant_packages', function (Blueprint $table) {
    $table->id();
    $table->foreignId('tenant_id')->constrained()->cascadeOnDelete();
    $table->foreignId('package_id')->constrained()->cascadeOnDelete();
    $table->decimal('price', 8, 2);
    $table->timestamp('purchased_at');
    $table->timestamp('expires_at'); // z.B. +1 Jahr
    $table->integer('used_events')->default(0); // Counter für max_events_per_year
    $table->boolean('active')->default(true);
    $table->timestamps();
});
```
- Bei Tenant-Registrierung: Free-Reseller oder Upgrade.
- Check: if ($tenant->activePackage->used_events >= $tenant->activePackage->max_events_per_year) block new Event.

### Ledger und Purchases (ersetzt Credits-Ledger)
```php
Schema::create('package_purchases', function (Blueprint $table) {
    $table->id();
    $table->foreignId('tenant_id')->constrained()->nullable(); // Null für Event-spezifisch
    $table->foreignId('event_id')->constrained()->nullable(); // Für Endkunden
    $table->foreignId('package_id')->constrained();
    $table->string('stripe_id'); // Für Webhook/Idempotenz
    $table->decimal('price', 8, 2);
    $table->string('type'); // 'endcustomer_event', 'reseller_subscription'
    $table->json('metadata'); // z.B. {'event_id': 123}
    $table->timestamps();
});
```
- Kein separater Ledger nötig; Purchases tracken alles.

## Integration und Logik
- **Event-Create Flow**: User wählt Package → Stripe-Checkout (Einmalkauf) → Webhook bestätigt → Event mit package_id erstellen.
- **Reseller-Upgrade**: Im Admin-Dashboard Package auswählen → Subscription erstellen → expires_at setzen.
- **Limits-Checks**: Middleware prüft Event-Package-Limits (Photos/Uploads), Tenant-Package für Event-Anzahl.
- **Fallback**: Bestehende Tenants migrieren zu Free-Paket (z.B. if old_credits > 100 → Standard).
- **UI/Features**: Wasserzeichen: if (!$package->watermark_allowed) hide; Branding: Custom Logo-Upload if allowed.
- **Billing**: Stripe Products für jedes Package; Webhooks updaten Status (z.B. Subscription cancel → active=false).

## Migration von Altem System
- Entferne: event_credits_balance aus tenants, event_purchases, event_credits_ledger.
- Migriere: Für Events mit Credits → Zuordnen zu Free-Paket; Tenant-Balance → Initial Reseller S.
- Skript: Artisan Command `php artisan migrate:packages` für Daten-Transfer.

Dieses Design ist final und bereit für Implementierung. Updates via PR.