Vai al contenuto

Configurazione ​

Usa questa pagina per consultare le impostazioni del server. Le impostazioni provengono da queste fonti, e ognuna sovrascrive quelle successive:

  1. Variabili d'ambiente
  2. User secrets
  3. appsettings.{Environment}.json
  4. appsettings.json

I file appsettings*.json tracciati contengono solo i livelli di logging e valori predefiniti non segreti, come l'issuer dell'accesso e le impostazioni mail locali. Imposta i segreti altrove:

  • In locale: usa dotnet user-secrets set. Vedi Setup di sviluppo.
  • In un container: usa le variabili d'ambiente, con __ come separatore di sezione, ad esempio ConnectionStrings__SchulyDatabase.

Stringa di connessione al database ​

SchulyDbContext legge la stringa di connessione denominata SchulyDatabase (ConnectionStrings:SchulyDatabase), collegata in DatabaseExtensions. Il nuovo tentativo in caso di errore è attivo per gli errori transitori di Postgres.

sh
export ConnectionStrings__SchulyDatabase="Host=localhost;Port=2406;Database=schuly-dev;Username=postgres;Password=..."

Accesso ​

L'accesso è integrato nel server con la libreria Toamaisutaa (AddSchulyAuthentication). Non c'è un identity provider separato. Le sue tabelle si trovano nel database di Schuly (migrazione AddToamaisutaa).

Attivi: accesso con password con registrazione autonoma, verifica dell'email, reimpostazione della password via email, autenticazione a due fattori TOTP con codici di recupero, "ricorda questo dispositivo" (dispositivi attendibili), single sign-on facoltativo tramite provider OIDC e pulizia dei token scaduti.

Non attivi: passkey, magic link, inviti e account creati dall'amministratore.

Endpoint: si trovano sotto /auth, ad esempio POST /auth/register, /auth/login, /auth/refresh, /auth/logout, /auth/password, /auth/password/forgot, /auth/password/reset, /auth/email, /auth/email/verify, /auth/2fa/*, /auth/devices, /auth/providers e /auth/external/*.

Token: l'API sotto /api/* accetta l'access token come Authorization: Bearer. Gli access token durano 15 minuti. I refresh token ruotano a ogni utilizzo.

Client: l'app web, servita dal server stesso, invia l'header X-Schuly-Client: web. Riceve il refresh token e il token del dispositivo ricordato in cookie HttpOnly, SameSite=Strict limitati a /auth. Gli altri client, come l'app mobile, ricevono i token nel corpo JSON.

ChiaveScopo
LocalLogin:SigningKeyFirma gli access token. Base64, esattamente 32 byte.
TwoFactor:EncryptionKeyCifra i segreti dell'autenticazione a due fattori. Base64, esattamente 32 byte.
LocalLogin:Issuer, LocalLogin:AudienceIssuer e audience dei token. appsettings.json li imposta entrambi a schuly.
LocalLogin:AllowSelfRegistrationSe chiunque può registrarsi (true in appsettings.json).
LocalLogin:RequireVerifiedEmailForSignInSe l'accesso richiede un indirizzo verificato (true in appsettings.json).
LocalLogin:RequireVerifiedEmailForPasswordResetInvia le mail di reimpostazione solo agli indirizzi verificati (true in appsettings.json).
TwoFactor:IssuerNome mostrato nelle app di autenticazione (Schuly).

Genera entrambe le chiavi con openssl rand -base64 32 e tienile stabili. Una nuova chiave di firma disconnette tutti. Una nuova chiave di cifratura rompe l'autenticazione a due fattori per ogni account che l'ha configurata.

Non esiste un ruolo di amministratore. Al primo token valido per un utente sconosciuto, l'API crea l'utente Schuly corrispondente (AddUserSync, IUserService).

Single sign-on (provider OIDC) ​

Il single sign-on è facoltativo. Configura zero, uno o più provider OIDC: Google, Microsoft, Authentik, Pocket ID, Keycloak o qualsiasi issuer con un documento di discovery. Senza provider, l'app web e l'app mobile mostrano solo il modulo della password. Ogni provider compare come pulsante "Continue with ...". Gli utenti che hanno effettuato l'accesso collegano o scollegano i provider sotto Settings → Security nell'app web.

ChiaveScopo
ExternalLogin:Providers:<key>:DisplayNameEtichetta del pulsante. Il valore predefinito è la chiave.
ExternalLogin:Providers:<key>:IconUrlIcona del pulsante: qualsiasi URL di immagine, o un percorso servito dal server. Se è vuoto, le authority di Google (https://accounts.google.com) e Microsoft (login.microsoftonline.com, login.live.com) ricevono il loro logo.
ExternalLogin:Providers:<key>:AuthorityL'issuer, come https://accounts.google.com. Deve essere https:// fuori da Development.
ExternalLogin:Providers:<key>:ClientId, ClientSecretIl client emesso dal provider. Ometti il segreto per un client pubblico.
ExternalLogin:Providers:<key>:ScopesIl valore predefinito è openid profile email.
ExternalLogin:Providers:<key>:AllowSignUpSe un primo accesso può creare un account. false per impostazione predefinita, quindi solo gli account che hanno collegato il provider possono usarlo.
ExternalLogin:Providers:<key>:TrustEmailVerifiedSe un indirizzo che questo provider segna come email_verified vale come email dell'account quando l'account non ha un indirizzo verificato. Senza questa impostazione, gli account creati tramite il provider non hanno un'email. Attivala solo per i provider che verificano davvero gli indirizzi.
ExternalLogin:Providers:<key>:LinkByVerifiedEmailSe un primo accesso si unisce all'account che ha già l'indirizzo verificato del provider. Attivala solo per i provider che verificano davvero gli indirizzi.
ExternalLogin:AllowedReturnUrlsURL esatti a cui un accesso concluso può tornare (ExternalLogin__AllowedReturnUrls__0, __1 e così via).
ExternalLogin:CallbackBaseUrlSchema e host pubblici del server, quando un proxy non li inoltra.

AllowedReturnUrls ha bisogno di queste voci:

  • https://<API_HOST>/login: accesso nell'app web
  • https://<API_HOST>/settings: collegamento di un provider nell'app web
  • schuly://auth/callback: accesso nell'app mobile (schuly-dev://auth/callback per la build dev)

Presso ogni provider, registra https://<API_HOST>/auth/external/<key>/callback come URI di reindirizzamento. Ogni collegamento memorizza la chiave, quindi non rinominarla in seguito.

Email (SMTP) ​

Le mail di verifica e di reimpostazione della password vengono inviate tramite SMTP:

ChiaveScopo
Email:Smtp:Host, Email:Smtp:PortServer di posta.
Email:Smtp:SecuritySicurezza della connessione. appsettings.Development.json imposta None.
Email:Smtp:User, Email:Smtp:PasswordCredenziali del server di posta.
Email:Smtp:FromIndirizzo del mittente.
Email:Smtp:FromDisplayNameNome del mittente (Schuly in appsettings.json).
Email:Smtp:PasswordResetLinkTemplateLink nella mail di reimpostazione, come https://<API_HOST>/reset-password?token={token}.
Email:Smtp:EmailVerificationLinkTemplateLink nella mail di verifica, come https://<API_HOST>/verify-email?token={token}.

In Development, appsettings.Development.json invia le mail a un catcher SMTP locale su localhost:1025 e crea link verso http://localhost:4200. Vedi Setup di sviluppo.

Documento OpenAPI ​

Il documento OpenAPI usa uno schema di sicurezza HTTP bearer. Nella UI di Scalar, incolli un access token. Non c'è nessun flusso OAuth2.

Storage dei documenti (S3) ​

I blob di documenti e avatar vanno in un bucket compatibile con S3, che negli stack inclusi è SeaweedFS.

ChiaveScopo
S3:EndpointEndpoint S3, come http://localhost:8333.
S3:BucketNome del bucket.
S3:AccessKey, S3:SecretKeyCredenziali. Devono corrispondere a s3-config.json di SeaweedFS.
S3:UsePathStyletrue per impostazione predefinita. Usa true per SeaweedFS e per la maggior parte delle implementazioni S3 self-hosted.
Documents:EncryptionKeyCifra i documenti prima che raggiungano il bucket. Generala con openssl rand -base64 32. Obbligatoria fuori da Development. Se la perdi, i documenti memorizzati diventano illeggibili.
Documents:KeyVersion, Documents:PreviousKeys:<version>Versione corrente della chiave (predefinita 1) e chiavi precedenti, così i documenti cifrati con esse restano leggibili.

Firma degli URL degli avatar ​

ChiaveScopo
Avatar:SigningKeyChiave HMAC per gli URL firmati di breve durata degli avatar. Generala con openssl rand -hex 32.

Gli utenti caricano un'immagine del profilo con PUT /api/me/avatar (multipart; PNG, JPEG o WebP; al massimo 2 MB) e la rimuovono con DELETE /api/me/avatar. Il file va nello storage dei documenti e viene servito tramite URL firmati di breve durata sotto /api/avatars/users/{id}.

Il database memorizza solo una semplice chiave del blob, e il server crea un URL firmato a ogni accesso. Il server legge la chiave in modo lazy. Se manca, vedi Avatar:SigningKey is not configured. la prima volta che viene firmato un URL di un avatar, non all'avvio.

Vault dei plugin ​

ChiaveScopo
Vault:MasterKeyCifra le credenziali memorizzate dei plugin. Base64, esattamente 32 byte. Generala con openssl rand -base64 32.

Fuori da Development, il server rifiuta di avviarsi senza una chiave valida. Tieni stabile la chiave: con una nuova chiave, le credenziali memorizzate diventano illeggibili. In Development, una chiave mancante o non valida scrive un avviso nel log e il server usa una chiave temporanea, quindi le credenziali memorizzate non sopravvivono a un riavvio.

Conservazione ​

Un servizio ospitato elimina i dati scaduti cinque minuti dopo l'avvio e poi ogni 24 ore. Usa lo stesso codice di eliminazione di DELETE /api/auth/me, quindi una riga eliminata non lascia nulla in Postgres o in S3.

ChiaveScopo
Retention:EnabledSe l'eliminazione viene eseguita (predefinito true).
Retention:MonthsAfterLeaveElimina i dati scolastici in cache degli school user il cui LeaveDate è più vecchio di questo valore (predefinito 6).
Retention:MonthsInactiveElimina i dati Schuly degli account senza richieste autenticate per questo periodo, non l'account di accesso (predefinito 12).

ApplicationUser.LastSeenAt misura l'inattività. La pipeline di validazione dei JWT lo aggiorna al massimo una volta all'ora, così un client attivo non scrive a ogni richiesta. Un account che non è mai stato aggiornato usa il suo CreatedAt.

L'account di accesso resta, quindi un account eliminato può accedere di nuovo e risincronizzare da zero.

Notifiche push (Firebase) ​

Un servizio in background svuota l'outbox delle notifiche (note, assenze, modifiche all'agenda) e le recapita tramite Firebase Cloud Messaging.

ChiaveScopo
Firebase:ServiceAccountJsonBase64 del JSON del service account Firebase.
Firebase:ServiceAccountPathPercorso del file JSON del service account, in alternativa al valore inline.

Se nessuna delle due è impostata, il backend scrive una volta nel log all'avvio che le notifiche push sono disattivate e non invia nulla, così i deployment senza Firebase continuano a funzionare. Svuota comunque l'outbox, così la tabella resta limitata.

Helply ​

Helply è l'assistente IA facoltativo. Ha bisogno di un gateway chat-completions compatibile con OpenAI.

ChiaveScopo
Helply:BaseUrlURL del gateway. http o https assoluto.
Helply:ApiKeyChiave API del gateway.
Helply:ModelFacoltativo. Senza di esso, il server prova i modelli elencati dal gateway e usa il primo che risponde alle chiamate di strumenti.

BaseUrl e ApiKey insieme attivano Helply. Queste tre impostazioni non hanno un valore predefinito. Impostale solo come variabili d'ambiente (Helply__BaseUrl, Helply__ApiKey, Helply__Model), mai in appsettings. Senza di esse, il server scrive nel log che Helply è disattivato e gli utenti lo vedono disattivato.

Limiti ​

Queste chiavi si trovano sotto Helply:Limits.

ChiavePredefinitoScopo
MessagesPerMinute10Messaggi per utente al minuto.
MessagesPerDay200Messaggi per utente al giorno.
MaxInputChars4000Messaggio più lungo.
RunTimeoutSeconds120Tempo a disposizione per un turno.
RunTimeoutSecondsWithWorkspace300Tempo a disposizione per un turno con il workspace.
MaxToolIterations8Chiamate di strumenti andata e ritorno in un turno.
MaxToolIterationsWithWorkspace16Chiamate di strumenti andata e ritorno in un turno con il workspace.
MaxHistoryMessages40Messaggi precedenti inviati al modello.
MaxHistoryChars60000Testo precedente inviato al modello.
MaxOutputTokens2048Risposta più lunga.
MaxToolResultChars16000Risultato di strumento più lungo nel prompt. I risultati più lunghi vengono tagliati con una nota.
MaxToolArgumentChars20000Argomenti di strumento serializzati più lunghi. Le chiamate più grandi vengono rifiutate.
MaxAttachmentTextChars30000Quantità massima di testo di un allegato nel prompt.
MaxAttachmentTextTotalChars60000Quantità massima di testo degli allegati in una richiesta al modello.
MaxNativeBytesPerRequest12000000Quantità massima di byte di file (immagini, PDF) inviati come file in una richiesta al modello.

Workspace ​

Il workspace permette a Helply di eseguire codice in una sandbox. Ha bisogno di Helply:Sandbox:BaseUrl e Helply:Sandbox:ApiKey, che deve avere almeno 32 caratteri. Impostali come variabili d'ambiente (Helply__Sandbox__BaseUrl, Helply__Sandbox__ApiKey). Vedi il README di deploy per la configurazione.

Server MCP ​

Il server espone MCP su /mcp, così gli utenti possono collegare app di IA.

ChiaveScopo
Mcp:PublicUrlL'origine pubblica e l'audience di ogni token MCP. Impostala nei deployment. Senza di essa, il server ricava l'origine da ogni richiesta.
Mcp:AllowedOriginsOrigini del browser ammesse da CORS, oltre a quella del server (Mcp__AllowedOrigins__0, __1 e così via). I caratteri jolly non sono supportati.

Di norma imposti solo queste due. Le durate dei token e i limiti si trovano anch'essi sotto Mcp: e hanno valori predefiniti funzionanti (McpOAuthOptions).

Limitare le registrazioni alla Svizzera ​

Imposta SignUp:SwitzerlandOnly su true (SignUp__SwitzerlandOnly=true in config/backend.env) per accettare nuovi account solo da reti svizzere. Di default è disattivato.

  • Le registrazioni con password da altre reti ricevono un errore. Il server confronta l'indirizzo solo con un elenco integrato, senza salvarlo né registrarlo nei log.
  • I provider OIDC non possono creare account, qualunque sia il valore di AllowSignUp. Gli account che hanno già collegato un provider continuano a usarlo.
  • Gli account esistenti continuano a funzionare ovunque. La modalità privata non ha un account e quindi non è interessata.
  • Un indirizzo svizzero deve raggiungere il server. Dietro un proxy, imposta correttamente ForwardedHeaders:KnownNetworks, altrimenti ogni registrazione viene rifiutata.

L'elenco proviene dai dati del registro RIPE, che indicano dove è registrata una rete, quindi non è esatto. Una VPN può aggirarlo. Per aggiornare l'elenco prima di una release, esegui scripts/update-swiss-networks.sh.

Criterio di autorizzazione ​

Il criterio di fallback richiede un utente autenticato per ogni endpoint (AddSchulyAuthorization). Gli endpoint se ne escludono con [AllowAnonymous]. Questi non hanno bisogno di un token:

  • La superficie anonima /api/app, come il catalogo dei sistemi scolastici e i loghi statici sotto wwwroot, così l'app può caricare il suo catalogo di login.
  • Registrazione, login e gli altri endpoint pubblici di accesso sotto /auth.

Plugin ​

Vedi Gestione dei plugin per l'URL del registro, il file dei plugin desiderati e le directory.

Logging ​

Imposta i livelli di log sotto Logging:LogLevel in appsettings.json. L'override di Development alza il logging HTTP a Information per il tracciamento delle richieste.