6.5 KiB
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)
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)
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)
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)
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:packagesfür Daten-Transfer.
Dieses Design ist final und bereit für Implementierung. Updates via PR.