Zum Hauptinhalt springen

Kunden verwalten

[admin] [billing]

Kundenverwaltung im Admin: Einladen, Freischalten, Pakete zuweisen, Vertragsdaten, Kündigung, Löschung. Inkl. DSGVO-konformes Archiv.

Für wen

Admins, die ihre Lizenz-Kunden manuell oder per Self-Service-Link aufnehmen, Pakete zuordnen, Verträge verwalten.

Übersicht

Sidebar → Kunden: Liste aller Kunden mit Filter (Status: pending / active / inactive / cancelled). Spalten: Kundennummer, Name/Firma, Paket, Status, Erstellt.

Status-Lifecycle

  • pending — eingeladen, noch nicht oder ausstehend bezahlt / freigeschaltet
  • active — freigeschaltet, hat Portal-Zugang
  • inactive — deaktiviert (z.B. Zahlung gescheitert mehrere Wochen)
  • Gelöscht (deleted_customers-Archiv): DSGVO-konform anonymisiert

Schritt für Schritt — Kunden einladen

1. + Kunde einladen

Kunden → + Kunde einladen.

2. Felder

  • E-Mail (Pflicht) — Empfänger der Einladungs-Mail
  • Vorname / Nachname / Firma
  • Paket auswählen (Dropdown aller aktiven Pakete des Tenants)
  • Add-ons optional zuweisen
  • Notizen (intern, für dich)

3. Versenden

licensio generiert einen Registrierungs-Token, schickt eine Mail mit dem Link /<tenant>.licensio.io/register/<token>. Kunde:

  • Klickt Link → Passwort setzen → Stripe-Checkout für erste Zahlung
  • Zahlung erfolgt → Status bleibt pending
  • Du schaltest manuell auf active frei (im Kunden-Detail oder Bulk-Aktion)

4. Automatische Freischaltung (optional)

Wenn das gewählte Paket auto_activate=true hat, wird der Kunde direkt nach Zahlung freigeschaltet. Mail-Bestätigung geht raus.

Kunden-Detail

Klick auf Kunde in der Liste. Das Layout besteht aus einer fixen Kopf-Kachel und aufklappbaren Sektionen (Collapsibles). Der Auf-/Zu-Zustand jeder Sektion und der aktive Logs-Tab werden pro Kunde im Browser gespeichert (localStorage). Standardmäßig sind alle Collapsibles zugeklappt.

Fixe Kachel "Kontakt & Abonnement"

Immer geöffnet, oben. Bündelt Stammdaten + Abonnement. Über den Bearbeiten-Button (oben rechts) werden die Stammdaten inline editierbar (Felder werden zu Eingaben, Speichern / Abbrechen):

  • Name, Firma, E-Mail, Kundennummer (customer_number, z.B. PT-2026-0001), Status-Badge, externe ID
  • Adresse (Straße, PLZ, Stadt, Land), USt-ID, Steuernummer
  • Ansprechpartner, Zahlungsart, interne Nr. (customer_number_int, sekundär)
  • Account-Typ: Whitelabel (Default) oder Connect, abgeleitet aus customers.connect_user_id (NULL = Whitelabel, gesetzt = Connect)
  • Zahlungsstatus (Stripe-Subscription live: Status, Betrag, nächste/letzte Belastung)
  • Pakete & Zahlung: Basis-Paket (wechselbar) + Add-ons, Add-Package-Button (Payment-Link erzeugen / per Mail senden)

Bearbeiten (Admin): PATCH /api/customers/[id] schreibt first_name, last_name, company, responsible_person, street, zip, city, country, vat_id, tax_number, payment_method. Best-effort Stripe-Sync wie im Portal-Self-Edit: Adresse + Name auf den Stripe-Customer, vat_id als eu_vat-Tax-ID. tax_number bleibt nur in der DB (Stripe kennt keine nationale Steuernummer). country wird als 2-stelliger ISO-Code validiert. E-Mail bleibt ausgenommen (eigener OTP-Flow via „E-Mail ändern").

Aufklappbare Sektionen (Standard: zugeklappt)

  • Logs — Tab-Bar mit drei Tabs (jeweils letzte 10):
    • Datei-Downloads — aus download_logs (Datum, Produkt, Dateityp)
    • Logins — aus customer_activity (activity_type='login', Datum + gekürzter IP-Hash)
    • Feed-Exporte — aus customer_activity (activity_type='feed_export', Datum + Format + via token/session)
    • Leerer Tab zeigt „Noch keine Daten". Tab-Auswahl wird pro Kunde gemerkt.
  • Support-Verlauf — letzte 3 Tickets (support_tickets, sortiert nach updated_at, mit Status-Badge + Link zur Ticket-Detailseite) + E-Mail-Verlauf (email_logs)
  • Einwilligungen — DSGVO-Nachweis (customer_consents, nur wenn vorhanden)
  • Dokumente — Vertrags-Uploads (customer_documents) + Vertragsstart-Datum
  • Interne Notizen
  • Status — Freischalten (pending → active) / Deaktivieren / Aktivierung ablehnen (rejected_at, rejection_reason) / Pausieren-Reaktivieren. Kündigung ist hier integriert (nur bei status='active'): „Abonnement kündigen" (Datum-Modal) bzw. Kündigung zurücknehmen.
  • Aktionen — Registrierungslink neu senden, Passwort-Reset, Stripe-Billing-Portal öffnen
  • GefahrenzoneLöschen (DSGVO Art. 17): Kunde wird in deleted_customers archiviert (nur customer_number, tenant_id, deleted_at, deleted_by — KEIN PII), Auth-User + Customer-Record werden gelöscht.

Hinweis: Logins + Feed-Exporte stammen aus dem Customer-Activity-Logging (Migration 060). Downloads bleiben separat in download_logs. Account-Typ-Anker customers.connect_user_id (Migration 061, nullable, noch ohne FK) — licensio Connect ist Phase 2.

Kundennummern

Auto-Trigger generiert: PT-2026-0001, PT-2026-0002, ... pro Tenant + Jahr. Nach Kunden-Löschung wird die Nummer NICHT wiederverwendet — sie bleibt im deleted_customers-Archiv reserviert (Migration 013).

Häufige Fragen

Wie lange dauert die Stripe-Synchronisation? Sofort beim Speichern. Bei Stripe-Express-Accounts werden manche Felder (z.B. company.address) nicht akzeptiert — dann silent best-effort, der Rest wird gespeichert.

Woher kommt die Kundenadresse? Beim Checkout fragt Stripe eine Pflicht-Adresse (und optional die USt-ID) ab. Nach Abschluss übernimmt der Webhook (checkout.session.completed) Straße/PLZ/Stadt + USt-ID automatisch in den Kundendatensatz — aber nur, wenn die Felder noch leer sind. Eine später im Portal oder Admin gepflegte Adresse wird nie überschrieben. country wird nicht aus dem Checkout übernommen (bleibt beim Registrierungs-Wert). Hinweis: Der Setup-Checkout (Pakete ohne sofortige Abbuchung) sammelt keine Adresse — dort bleibt das Feld leer, bis es im Portal/Admin gepflegt wird. Bestandskunden lassen sich per Backfill-Script (apps/portal/scripts/backfill-stripe-addresses.ts) nachziehen.

Was wenn ein Kunde sich selbst registriert hat? Self-Service-Pakete erstellen den Customer mit status='pending'. Du siehst sie in der Liste mit Filter "Pending".

Kann ich Kunden CSV-importieren? Phase 2 — Bulk-Import noch nicht implementiert (product_imports-Tabelle ist Skeleton dafür).

DSGVO-Auskunft für einen Kunden? Aktuell manuell aus DB exportierbar. Self-Service-Auskunft (Phase 2 / nice-to-have).

Was wenn der Stripe-Customer-Update fehlschlägt? licensio-Customer wird trotzdem gespeichert. Du siehst eine Warnung im UI. Stripe-Sync kannst du via "Erneut synchronisieren"-Button wiederholen.

Verwandt