Self-Service-Onboarding (Architettura)¶
Il Self-Service-Onboarding consente a potenziali clienti di configurare da soli, senza contatto commerciale, una propria istanza cloud DiKAS – a scelta come test gratuito (Trial) oppure direttamente come istanza live a pagamento. Questa pagina descrive l'architettura tecnica, la configurazione e i meccanismi di sicurezza. La visuale dell'utente finale è descritta in Registrazione online.
Disattivato per impostazione predefinita (Dark-Rollout)
Il funnel pubblico è protetto dal flag SelfServiceSignupEnabled ed è spento nello stato
di consegna. Finché il flag è false, tutti gli endpoint pubblici restituiscono 404. Prima
di un'attivazione vanno soddisfatti i punti elencati in
Prima dell'attivazione.
Panoramica¶
Il processo è costituito da un wizard frontend pubblico e da una serie di endpoint backend
anonimi. Il provisioning vero e proprio passa attraverso lo stesso ILicenseProvisioningService
utilizzato anche dal percorso Portale e dal percorso Trial.
| Ambito | Posizione |
|---|---|
| Wizard frontend | Rotta /signup (PublicOnboardingWizardComponent, app dikas-web) |
| Conferma Magic Link | Rotta /signup/verify |
| Endpoint backend | /api/v1/onboarding/public/* e /api/v1/trial/start |
| Feature pack | Dikas.Features.Licensing |
Il wizard guida attraverso sette passaggi: Pacchetto → TSE (Cloud vs. Swissbit) → Account (e-mail, senza password tramite Magic Link) → Dati aziendali → Nome online (sottodominio) → Diritto e pagamento → Completato (URL dell'istanza e credenziali di accesso).
Feature flag SelfServiceSignupEnabled¶
Il flag è una proprietà del documento singleton OperationalConfig (ID fisso
operationalconfig) ed è modificabile solo tramite il database o l'interfaccia Admin – non
esiste alcuna variabile d'ambiente per questo.
Ogni endpoint pubblico richiama prima CheckSelfServiceEnabledAsync() e risponde con
404 Not Found finché il flag è false. Il funnel resta così invisibile finché non viene
attivato consapevolmente.
Endpoint pubblici¶
Tutti gli endpoint sono [AllowAnonymous] e protetti dal flag nonché dalle misure anti-abuso.
| Metodo & percorso | Scopo |
|---|---|
POST /api/v1/onboarding/public/orders |
Creare un ordine bozza anonimo (restituisce un token d'ordine segreto) |
PUT /api/v1/onboarding/public/orders/{id} |
Aggiornare la bozza (vincolata al token) |
POST /api/v1/onboarding/public/orders/{id}/reserve-name |
Riservare temporaneamente il nome online |
POST /api/v1/onboarding/public/register |
Creare un cliente senza password, inviare il Magic Link |
POST /api/v1/onboarding/public/orders/{id}/bind |
Collegare l'ordine all'account verificato tramite Magic Link ([Authorize]) |
POST /api/v1/onboarding/public/payment/set |
Creare un SetupIntent/PaymentIntent Stripe (restituisce ClientSecret) |
POST /api/v1/onboarding/public/payment/webhook |
Webhook Stripe (conferma di pagamento) |
POST /api/v1/onboarding/public/orders/{id}/submit |
Effettuare il provisioning dell'istanza |
GET /api/v1/onboarding/public/payment-config |
Publishable Key Stripe per il frontend |
POST /api/v1/trial/start |
Trial self-service diretto (senza ordine/account portale) |
Sicurezza / anti-abuso¶
Poiché ogni provisioning genera costi reali (COGS), sono attivi diversi livelli di protezione indipendenti tra loro:
- Honeypot – un campo di modulo nascosto; se compilato, viene rifiutato silenziosamente con
202 Accepted(nessun provisioning). - Limitatore di errori per IP – ritardo esponenziale, blocco dopo 10 errori (1 h) ovvero 20 errori (24 h).
- Quota di provisioning per IP e 24 h (
MaxPublicProvisionsPerIpPer24h, default 3). Si applica sia al submit pubblico sia all'avvio del Trial e non viene azzerata in caso di successo. Se la quota viene superata, l'endpoint risponde con429(code: SIGNUP_RATE_LIMITED). - Quota di invio e-mail per IP e ora (
MaxPublicEmailSendsPerIpPerHour, default 5) contro il Magic-Link-bombing. - Magic Link invece della classica conferma via e-mail; il clic verifica l'indirizzo e restituisce un JWT del portale, con cui l'ordine viene collegato.
- IP client reale – dietro l'ingress, l'IP di origine viene determinato tramite
ForwardedHeaders. Le reti attendibili (KnownNetworks) devono essere impostate nel deployment sul CIDR del cluster, altrimenti la quota per IP collassa.
Quote in memoria
Le quote vengono mantenute in memoria (finestra temporale scorrevole). Con più istanze dietro un load balancer, ogni istanza conta per sé; in tal caso occorre prevedere una sticky session o una cache condivisa.
Configurazione¶
Le opzioni vengono caricate dalla sezione Onboarding (OnboardingOptions). Tutti i valori hanno
default sensati nel codice; sovrascrivibili tramite variabile d'ambiente con doppio underscore.
| Chiave | Default | Significato |
|---|---|---|
Onboarding__MaxPublicProvisionsPerIpPer24h |
3 |
Max. provisioning per IP / 24 h (submit + Trial) |
Onboarding__MaxPublicEmailSendsPerIpPerHour |
5 |
Max. e-mail Magic Link per IP / ora |
Onboarding__RequireEmailVerifyBeforeProvision |
true (Portale) |
Imporre la conferma e-mail prima del provisioning |
Onboarding__RequireOnlinePaymentForNonTrial |
false (Portale) |
Per i non-Trial imporre un pagamento online reale |
Pagamento¶
Il pagamento passa tramite Stripe su un conto DiKAS centrale (non per singolo mandante).
| Chiave | Significato |
|---|---|
Signup__Stripe__SecretKey |
Stripe Secret Key (attiva il connettore di pagamento reale) |
Signup__Stripe__PublishableKey |
Publishable Key per il frontend |
Signup__Stripe__WebhookSecret |
Segreto di firma per il webhook |
Senza SecretKey impostata è attivo un connettore nullo (Dev/Test). I valori di
OnboardingPaymentMethod: SepaLastschrift = 1, StripeSetupIntent = 2 (Trial-first, salvare il
metodo di pagamento), StripePaymentIntent = 3 (Pay-first, pagamento immediato).
Ciclo di vita e pulizia¶
Due servizi in background mantengono il funnel pulito:
Ordini abbandonati¶
OnboardingCleanupService (giornaliero) rimuove gli ordini abbandonati/non pagati che sono
inattivi da più di 14 giorni (CleanupAbandonedOnboardingsCommand, configurabile) – incluse le
bozze pubbliche anonime orfane (senza cliente collegato) – e libera nuovamente la loro
riserva del nome online. Gli ordini con provisioning effettuato/pagati restano intatti.
Trial scaduti (Dry-Run, dark)¶
TrialDeprovisioningService è un servizio costruito volutamente in modo prudente:
- Trova i Trial scaduti il cui periodo di tolleranza (
GraceDays, default 30) dopo la fine del Trial è trascorso (IsTrial = trueedEndDateoltre il periodo; le licenze convertite/pagate conIsTrial = falsenon vengono mai considerate). - In DRY-RUN si limita a registrare quali database del tenant (
{DatabasePrefix}_maindb,{DatabasePrefix}_gastrocurrent) un successivo run live eliminerebbe – non elimina nulla. - È completamente disattivato per default e gira solo con
TrialDeprovision__Enabled=true.
| Chiave | Default | Significato |
|---|---|---|
TrialDeprovision__Enabled |
false |
Interruttore principale; false = il servizio non gira affatto |
TrialDeprovision__GraceDays |
30 |
Periodo di tolleranza in giorni dopo la fine del Trial |
L'eliminazione reale del DB non è implementata
L'effettiva eliminazione dei database dei mandanti è volutamente non cablata. Richiede un'autorizzazione esplicita nonché una mappatura verificata dei nomi dei database e dovrebbe essere coordinata con l'applicazione della scadenza (fine Trial → blocco → esportazione).
Audit¶
Ogni provisioning viene protocollato tramite IAuditLogger ed è visibile nella vista di audit
dell'operatore (GET /api/v1/audit/logs/{date}, solo ruolo Admin):
| Evento | Trigger |
|---|---|
TRIAL_PROVISIONED |
Avvio riuscito di un Trial (con nome online, ID licenza, durata) |
TRIAL_CONVERTED_PAID |
Conversione di un Trial in una licenza a pagamento |
Timestamp e IP client provengono dalla request; nei Trial anonimi come utente compare -.
Le credenziali di accesso non vengono scritte nell'audit.
Prima dell'attivazione¶
Prima che SelfServiceSignupEnabled venga mai impostato su true:
-
ForwardedHeaders:KnownNetworksnel deploy di produzione impostato sul CIDR reale del cluster (altrimenti la quota per IP è inefficace). - Chiavi Stripe (
Signup__Stripe__*) impostate – altrimenti un pagamento „subito live" con un provider reale sarebbe gratuito. - Invio del Magic Link e
/signup/verifycablati in modo continuo. - Flag attivato in
OperationalConfig.