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) oderConnect, abgeleitet auscustomers.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.
- Datei-Downloads — aus
- Support-Verlauf — letzte 3 Tickets (
support_tickets, sortiert nachupdated_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 beistatus='active'): „Abonnement kündigen" (Datum-Modal) bzw. Kündigung zurücknehmen. - Aktionen — Registrierungslink neu senden, Passwort-Reset, Stripe-Billing-Portal öffnen
- Gefahrenzone — Löschen (DSGVO Art. 17): Kunde wird in
deleted_customersarchiviert (nurcustomer_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-Ankercustomers.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
- Pakete — Pakete erstellen + zuweisen
- Rechnungsstellung — Stripe-Setup
- Account — Kundensicht