Skip to content
v26.3

Self-Service-Onboarding (Architektur)

Das Self-Service-Onboarding erlaubt Interessenten, sich ohne Vertriebskontakt selbst eine DiKAS-Cloud-Instanz einzurichten – wahlweise als kostenlosen Test (Trial) oder direkt als zahlende Live-Instanz. Diese Seite beschreibt die technische Architektur, die Konfiguration und die Sicherheitsmechanismen. Die Endanwender-Sicht ist unter Online-Registrierung beschrieben.

Standardmäßig deaktiviert (Dark-Rollout)

Der öffentliche Funnel ist über das Flag SelfServiceSignupEnabled abgesichert und im Auslieferungszustand aus. Solange das Flag false ist, liefern alle öffentlichen Endpoints 404. Vor einer Aktivierung sind die Punkte unter Vor der Aktivierung zu erfüllen.

Überblick

Der Ablauf besteht aus einem öffentlichen Frontend-Wizard und einer Reihe anonymer Backend-Endpoints. Die eigentliche Provisionierung läuft über denselben ILicenseProvisioningService, den auch der Portal- und der Trial-Pfad nutzen.

Bereich Ort
Frontend-Wizard Route /signup (PublicOnboardingWizardComponent, App dikas-web)
Magic-Link-Bestätigung Route /signup/verify
Backend-Endpoints /api/v1/onboarding/public/* und /api/v1/trial/start
Feature-Pack Dikas.Features.Licensing

Der Wizard führt durch sieben Schritte: PaketTSE (Cloud vs. Swissbit) → Account (E-Mail, passwortlos per Magic-Link) → FirmendatenOnline-Name (Subdomain) → Recht & ZahlungFertig (Instanz-URL und Zugangsdaten).

Feature-Flag SelfServiceSignupEnabled

Das Flag liegt als Eigenschaft auf dem Singleton-Dokument OperationalConfig (feste ID operationalconfig) und ist nur über die Datenbank bzw. die Admin-Oberfläche änderbar – es gibt keine Umgebungsvariable dafür.

OperationalConfig.SelfServiceSignupEnabled  (bool, Default: false)

Jeder öffentliche Endpoint ruft zuerst CheckSelfServiceEnabledAsync() auf und antwortet mit 404 Not Found, solange das Flag false ist. Der Funnel bleibt damit unsichtbar, bis er bewusst freigeschaltet wird.

Öffentliche Endpoints

Alle Endpoints sind [AllowAnonymous] und durch das Flag sowie die Anti-Missbrauchs-Maßnahmen abgesichert.

Methode & Pfad Zweck
POST /api/v1/onboarding/public/orders Anonyme Draft-Bestellung anlegen (liefert geheimes Order-Token)
PUT /api/v1/onboarding/public/orders/{id} Draft aktualisieren (Token-gebunden)
POST /api/v1/onboarding/public/orders/{id}/reserve-name Online-Namen kurzzeitig reservieren
POST /api/v1/onboarding/public/register Passwortlosen Kunden anlegen, Magic-Link versenden
POST /api/v1/onboarding/public/orders/{id}/bind Order an den per Magic-Link verifizierten Account binden ([Authorize])
POST /api/v1/onboarding/public/payment/set Stripe-SetupIntent/PaymentIntent erzeugen (liefert ClientSecret)
POST /api/v1/onboarding/public/payment/webhook Stripe-Webhook (Zahlungsbestätigung)
POST /api/v1/onboarding/public/orders/{id}/submit Instanz provisionieren
GET /api/v1/onboarding/public/payment-config Stripe-Publishable-Key fürs Frontend
POST /api/v1/trial/start Direkter Self-Service-Trial (ohne Order/Portal-Account)

Sicherheit / Anti-Missbrauch

Da jede Provisionierung echte Kosten (COGS) erzeugt, sind mehrere voneinander unabhängige Schutzschichten aktiv:

  • Honeypot – ein verstecktes Formularfeld; ist es ausgefüllt, wird mit 202 Accepted still abgelehnt (kein Provisioning).
  • Fehler-Limiter pro IP – exponentielles Delay, Sperre nach 10 Fehlern (1 h) bzw. 20 Fehlern (24 h).
  • Provisionierungs-Kontingent pro IP und 24 h (MaxPublicProvisionsPerIpPer24h, Default 3). Es greift sowohl am öffentlichen Submit als auch am Trial-Start und wird bei Erfolg nicht zurückgesetzt. Wird das Kontingent überschritten, antwortet der Endpoint mit 429 (code: SIGNUP_RATE_LIMITED).
  • E-Mail-Versand-Kontingent pro IP und Stunde (MaxPublicEmailSendsPerIpPerHour, Default 5) gegen Magic-Link-Bombing.
  • Magic-Link statt klassischer E-Mail-Bestätigung; der Klick verifiziert die Adresse und liefert ein Portal-JWT, mit dem die Order gebunden wird.
  • Echte Client-IP – hinter dem Ingress wird die Quell-IP über ForwardedHeaders ermittelt. Die vertrauenswürdigen Netze (KnownNetworks) müssen im Deployment auf die Cluster-CIDR gesetzt sein, sonst kollabiert die IP-Quote.

In-Memory-Kontingente

Die Kontingente werden im Arbeitsspeicher gehalten (rollendes Zeitfenster). Bei mehreren Instanzen hinter einem Load-Balancer zählt jede Instanz für sich; in dem Fall ist eine Sticky-Session oder ein gemeinsamer Cache vorzusehen.

Konfiguration

Die Optionen werden aus der Sektion Onboarding geladen (OnboardingOptions). Alle Werte haben sinnvolle Defaults im Code; Überschreiben per Umgebungsvariable mit doppeltem Unterstrich.

Schlüssel Default Bedeutung
Onboarding__MaxPublicProvisionsPerIpPer24h 3 Max. Provisionierungen pro IP / 24 h (Submit + Trial)
Onboarding__MaxPublicEmailSendsPerIpPerHour 5 Max. Magic-Link-Mails pro IP / Stunde
Onboarding__RequireEmailVerifyBeforeProvision true (Portal) E-Mail-Bestätigung vor Provisionierung erzwingen
Onboarding__RequireOnlinePaymentForNonTrial false (Portal) Bei Nicht-Trial echte Online-Zahlung erzwingen

Zahlung

Die Zahlung läuft über Stripe auf einem zentralen DiKAS-Konto (nicht pro Mandant).

Schlüssel Bedeutung
Signup__Stripe__SecretKey Stripe-Secret-Key (aktiviert den echten Zahlungs-Adapter)
Signup__Stripe__PublishableKey Publishable-Key fürs Frontend
Signup__Stripe__WebhookSecret Signatur-Geheimnis für den Webhook

Ohne gesetzten SecretKey ist ein Null-Adapter aktiv (Dev/Test). Die OnboardingPaymentMethod-Werte: SepaLastschrift = 1, StripeSetupIntent = 2 (Trial-first, Zahlart hinterlegen), StripePaymentIntent = 3 (Pay-first, sofortige Zahlung).

Lebenszyklus & Aufräumen

Zwei Hintergrund-Dienste halten den Funnel sauber:

Abgebrochene Bestellungen

OnboardingCleanupService (täglich) entfernt abgebrochene/unbezahlte Bestellungen, die länger als 14 Tage (CleanupAbandonedOnboardingsCommand, konfigurierbar) inaktiv sind – einschließlich verwaister anonymer Public-Drafts (ohne gebundenen Kunden) – und gibt deren Online-Namen-Reservierung wieder frei. Provisionierte/bezahlte Bestellungen bleiben unberührt.

Abgelaufene Trials (Dry-Run, dark)

TrialDeprovisioningService ist ein bewusst zurückhaltend gebauter Dienst:

  • Er findet abgelaufene Trials, deren Kulanzfrist (GraceDays, Default 30) nach dem Trial-Ende verstrichen ist (IsTrial = true und EndDate jenseits der Frist; konvertierte/bezahlte Lizenzen mit IsTrial = false werden nie erfasst).
  • Im DRY-RUN protokolliert er lediglich, welche Tenant-Datenbanken ({DatabasePrefix}_maindb, {DatabasePrefix}_gastrocurrent) ein späterer Live-Lauf löschen würde – er löscht nichts.
  • Er ist standardmäßig vollständig deaktiviert und läuft nur bei TrialDeprovision__Enabled=true.
Schlüssel Default Bedeutung
TrialDeprovision__Enabled false Master-Schalter; false = Dienst läuft gar nicht
TrialDeprovision__GraceDays 30 Kulanzfrist in Tagen nach Trial-Ende

Echter DB-Drop ist nicht implementiert

Das tatsächliche Löschen der Mandanten-Datenbanken ist absichtlich nicht verdrahtet. Es erfordert eine ausdrückliche Freigabe sowie ein verifiziertes Datenbank-Namens-Mapping und sollte mit dem Ablauf-Enforcement (Trial-Ende → Sperre → Export) koordiniert werden.

Audit

Jede Provisionierung wird über den IAuditLogger protokolliert und ist in der Operator-Audit-Ansicht sichtbar (GET /api/v1/audit/logs/{date}, nur Rolle Admin):

Ereignis Auslöser
TRIAL_PROVISIONED Erfolgreicher Trial-Start (mit Online-Name, Lizenz-ID, Laufzeit)
TRIAL_CONVERTED_PAID Konversion eines Trials zu einer bezahlten Lizenz

Zeitstempel und Client-IP stammen aus dem Request; bei anonymen Trials steht als Benutzer -. Zugangsdaten werden nicht ins Audit geschrieben.

Vor der Aktivierung

Bevor SelfServiceSignupEnabled jemals auf true gesetzt wird:

  • ForwardedHeaders:KnownNetworks im Prod-Deploy auf die echte Cluster-CIDR gesetzt (sonst IP-Quote wirkungslos).
  • Stripe-Keys (Signup__Stripe__*) gesetzt – sonst wäre eine „sofort live"-Zahlung mit echtem Provider kostenlos.
  • Magic-Link-Versand und /signup/verify durchgängig verdrahtet.
  • Flag in der OperationalConfig aktiviert.