Zum Inhalt springen

Konfiguration ​

Auf dieser Seite schlägst du die Einstellungen des Servers nach. Einstellungen kommen aus diesen Quellen, und jede überschreibt die nachfolgenden:

  1. Umgebungsvariablen
  2. User Secrets
  3. appsettings.{Environment}.json
  4. appsettings.json

Die versionierten appsettings*.json-Dateien enthalten nur Log-Levels und nicht geheime Standardwerte, zum Beispiel den Anmelde-Issuer und die lokalen Mail-Einstellungen. Setze Secrets anderswo:

  • Lokal: Nutze dotnet user-secrets set. Siehe Entwicklungsumgebung.
  • In einem Container: Nutze Umgebungsvariablen, mit __ als Abschnittstrenner, zum Beispiel ConnectionStrings__SchulyDatabase.

Datenbank-Connection-String ​

SchulyDbContext liest den Connection-String namens SchulyDatabase (ConnectionStrings:SchulyDatabase), verdrahtet in DatabaseExtensions. Wiederholungen bei vorübergehenden Postgres-Fehlern sind aktiv.

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

Anmeldung ​

Die Anmeldung ist mit der Bibliothek Toamaisutaa (AddSchulyAuthentication) in den Server eingebaut. Es gibt keinen separaten Identity Provider. Ihre Tabellen liegen in der Schuly-Datenbank (Migration AddToamaisutaa).

Aktiviert: Passwort-Anmeldung mit Selbstregistrierung, E-Mail-Verifizierung, Zurücksetzen des Passworts per E-Mail, TOTP-Zwei-Faktor mit Wiederherstellungscodes, «remember this device» (vertrauenswürdige Geräte), optionales Single Sign-on über OIDC-Provider und das Aufräumen abgelaufener Tokens.

Nicht aktiviert: Passkeys, Magic Links, Einladungen und von Admins erstellte Konten.

Endpunkte: Diese liegen unter /auth, zum Beispiel 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 und /auth/external/*.

Tokens: Die API unter /api/* nimmt das Access-Token als Authorization: Bearer. Access-Tokens gelten 15 Minuten. Refresh-Tokens rotieren bei jeder Nutzung.

Clients: Die Web-App, die der Server selbst ausliefert, sendet den Header X-Schuly-Client: web. Sie erhält das Refresh-Token und das Token des gemerkten Geräts in HttpOnly-, SameSite=Strict-Cookies, beschränkt auf /auth. Andere Clients, zum Beispiel die Mobile App, erhalten die Tokens im JSON-Body.

SchlüsselZweck
LocalLogin:SigningKeySigniert Access-Tokens. Base64, genau 32 Bytes.
TwoFactor:EncryptionKeyVerschlüsselt die Zwei-Faktor-Secrets. Base64, genau 32 Bytes.
LocalLogin:Issuer, LocalLogin:AudienceToken-Issuer und -Audience. appsettings.json setzt beide auf schuly.
LocalLogin:AllowSelfRegistrationOb sich alle registrieren können (true in appsettings.json).
LocalLogin:RequireVerifiedEmailForSignInOb die Anmeldung eine verifizierte Adresse braucht (true in appsettings.json).
LocalLogin:RequireVerifiedEmailForPasswordResetSendet Reset-Mails nur an verifizierte Adressen (true in appsettings.json).
TwoFactor:IssuerName in Authenticator-Apps (Schuly).

Erzeuge beide Schlüssel mit openssl rand -base64 32 und halte sie stabil. Ein neuer Signaturschlüssel meldet alle ab. Ein neuer Verschlüsselungsschlüssel macht Zwei-Faktor für jedes Konto kaputt, das es eingerichtet hat.

Es gibt keine Admin-Rolle. Beim ersten gültigen Token eines unbekannten Users erstellt die API den passenden Schuly-User (AddUserSync, IUserService).

Single Sign-on (OIDC-Provider) ​

Single Sign-on ist optional. Konfiguriere keinen, einen oder mehrere OIDC-Provider: Google, Microsoft, Authentik, Pocket ID, Keycloak oder jeden Issuer mit einem Discovery-Dokument. Ohne Provider zeigen die Web-App und die Mobile App nur das Passwortformular. Jeder Provider erscheint als Button «Continue with ...». Angemeldete User verknüpfen oder trennen Provider in der Web-App unter Settings → Security.

SchlüsselZweck
ExternalLogin:Providers:<key>:DisplayNameButton-Beschriftung. Standardwert ist der Schlüssel.
ExternalLogin:Providers:<key>:IconUrlButton-Icon: eine beliebige Bild-URL oder ein Pfad, den der Server ausliefert. Wenn leer, erhalten die Authorities von Google (https://accounts.google.com) und Microsoft (login.microsoftonline.com, login.live.com) ihr Logo.
ExternalLogin:Providers:<key>:AuthorityDer Issuer, zum Beispiel https://accounts.google.com. Muss ausserhalb von Development https:// sein.
ExternalLogin:Providers:<key>:ClientId, ClientSecretDer Client, den der Provider ausgestellt hat. Lass das Secret bei einem öffentlichen Client weg.
ExternalLogin:Providers:<key>:ScopesStandardwert ist openid profile email.
ExternalLogin:Providers:<key>:AllowSignUpOb eine erste Anmeldung ein Konto erstellen darf. Standardmässig false, damit nur Konten mit verknüpftem Provider ihn nutzen können.
ExternalLogin:Providers:<key>:TrustEmailVerifiedOb eine Adresse, die dieser Provider als email_verified markiert, als E-Mail des Kontos gilt, wenn das Konto keine verifizierte Adresse hat. Ohne das haben über den Provider erstellte Konten keine E-Mail. Schalte das nur bei Providern ein, die Adressen wirklich verifizieren.
ExternalLogin:Providers:<key>:LinkByVerifiedEmailOb eine erste Anmeldung dem Konto beitritt, das schon die verifizierte Adresse des Providers hat. Schalte das nur bei Providern ein, die Adressen wirklich verifizieren.
ExternalLogin:AllowedReturnUrlsExakte URLs, zu denen eine abgeschlossene Anmeldung zurückkehren darf (ExternalLogin__AllowedReturnUrls__0, __1 und so weiter).
ExternalLogin:CallbackBaseUrlÖffentliches Schema und öffentlicher Host des Servers, wenn ein Proxy sie nicht weiterleitet.

AllowedReturnUrls braucht diese Einträge:

  • https://<API_HOST>/login: Anmeldung in der Web-App
  • https://<API_HOST>/settings: Provider in der Web-App verknüpfen
  • schuly://auth/callback: Anmeldung in der Mobile App (schuly-dev://auth/callback für den Dev-Build)

Registriere bei jedem Provider https://<API_HOST>/auth/external/<key>/callback als Redirect-URI. Jede Verknüpfung speichert den Schlüssel. Benenne ihn deshalb später nicht um.

E-Mail (SMTP) ​

Verifizierungs- und Reset-Mails gehen über SMTP hinaus:

SchlüsselZweck
Email:Smtp:Host, Email:Smtp:PortMailserver.
Email:Smtp:SecurityVerbindungssicherheit. appsettings.Development.json setzt None.
Email:Smtp:User, Email:Smtp:PasswordZugangsdaten des Mailservers.
Email:Smtp:FromAbsenderadresse.
Email:Smtp:FromDisplayNameAbsendername (Schuly in appsettings.json).
Email:Smtp:PasswordResetLinkTemplateLink in der Reset-Mail, zum Beispiel https://<API_HOST>/reset-password?token={token}.
Email:Smtp:EmailVerificationLinkTemplateLink in der Verifizierungs-Mail, zum Beispiel https://<API_HOST>/verify-email?token={token}.

In Development sendet appsettings.Development.json Mails an einen lokalen SMTP-Catcher auf localhost:1025 und baut Links auf http://localhost:4200. Siehe Entwicklungsumgebung.

OpenAPI-Dokument ​

Das OpenAPI-Dokument nutzt ein HTTP-Bearer-Sicherheitsschema. Im Scalar-UI fügst du ein Access-Token ein. Es gibt keinen OAuth2-Ablauf.

Dokumenten-Storage (S3) ​

Dokument- und Avatar-Blobs gehen in einen S3-kompatiblen Bucket, in den mitgelieferten Stacks ist das SeaweedFS.

SchlüsselZweck
S3:EndpointS3-Endpunkt, zum Beispiel http://localhost:8333.
S3:BucketBucket-Name.
S3:AccessKey, S3:SecretKeyZugangsdaten. Müssen zur s3-config.json von SeaweedFS passen.
S3:UsePathStyleStandardmässig true. Nutze true für SeaweedFS und die meisten selbst gehosteten S3-Implementierungen.
Documents:EncryptionKeyVerschlüsselt Dokumente, bevor sie den Bucket erreichen. Erzeuge ihn mit openssl rand -base64 32. Ausserhalb von Development erforderlich. Geht er verloren, sind gespeicherte Dokumente nicht mehr lesbar.
Documents:KeyVersion, Documents:PreviousKeys:<version>Aktuelle Schlüsselversion (Standard 1) und frühere Schlüssel, damit damit verschlüsselte Dokumente lesbar bleiben.

Avatar-URL-Signierung ​

SchlüsselZweck
Avatar:SigningKeyHMAC-Schlüssel für kurzlebige signierte Avatar-URLs. Erzeuge ihn mit openssl rand -hex 32.

User laden ein Profilbild mit PUT /api/me/avatar hoch (multipart; PNG, JPEG oder WebP; höchstens 2 MB) und entfernen es mit DELETE /api/me/avatar. Die Datei geht in den Dokumenten-Storage und wird über kurzlebige signierte URLs unter /api/avatars/users/{id} ausgeliefert.

Die Datenbank speichert nur einen reinen Blob-Schlüssel, und der Server erstellt für jeden Zugriff eine signierte URL. Der Server liest den Schlüssel erst bei Bedarf. Fehlt er, siehst du Avatar:SigningKey is not configured., wenn zum ersten Mal eine Avatar-URL signiert wird, nicht beim Start.

Plugin-Vault ​

SchlüsselZweck
Vault:MasterKeyVerschlüsselt gespeicherte Plugin-Zugangsdaten. Base64, genau 32 Bytes. Erzeuge ihn mit openssl rand -base64 32.

Ausserhalb von Development startet der Server nicht ohne gültigen Schlüssel. Halte den Schlüssel stabil: Unter einem neuen Schlüssel werden gespeicherte Zugangsdaten unlesbar. In Development führt ein fehlender oder ungültiger Schlüssel zu einer Warnung im Log, und der Server nutzt einen temporären Schlüssel. Gespeicherte Zugangsdaten überstehen dann keinen Neustart.

Aufbewahrung ​

Ein Hosted Service räumt abgelaufene Daten fünf Minuten nach dem Start und danach alle 24 Stunden auf. Er nutzt denselben Löschcode wie DELETE /api/auth/me. Eine aufgeräumte Zeile hinterlässt also nichts in Postgres oder S3.

SchlüsselZweck
Retention:EnabledOb das Aufräumen überhaupt läuft (Standard true).
Retention:MonthsAfterLeaveEntfernt zwischengespeicherte Schuldaten von School-Usern, deren LeaveDate älter ist als dieser Wert (Standard 6).
Retention:MonthsInactiveLöscht die Schuly-Daten von Konten ohne authentifizierte Anfrage in dieser Zeit, nicht das Anmeldekonto (Standard 12).

ApplicationUser.LastSeenAt misst die Inaktivität. Die JWT-Validierungs-Pipeline stempelt den Wert höchstens einmal pro Stunde, damit ein aktiver Client nicht bei jeder Anfrage schreibt. Ein Konto ohne Stempel fällt auf sein CreatedAt zurück.

Das Anmeldekonto bleibt. Ein aufgeräumtes Konto kann sich also wieder anmelden und von Grund auf neu synchronisieren.

Push-Benachrichtigungen (Firebase) ​

Ein Hintergrund-Service leert die Benachrichtigungs-Outbox (Noten, Absenzen, Agenda-Änderungen) und stellt sie über Firebase Cloud Messaging zu.

SchlüsselZweck
Firebase:ServiceAccountJsonBase64 des Firebase-Service-Account-JSON.
Firebase:ServiceAccountPathPfad zur Service-Account-JSON-Datei, als Alternative zum Inline-Wert.

Ist keiner der beiden gesetzt, loggt das Backend beim Start einmal, dass Push-Benachrichtigungen aus sind, und sendet nichts. Deployments ohne Firebase funktionieren also weiter. Es leert die Outbox trotzdem, damit die Tabelle begrenzt bleibt.

Helply ​

Helply ist der optionale KI-Assistent. Er braucht ein OpenAI-kompatibles Chat-Completions-Gateway.

SchlüsselZweck
Helply:BaseUrlGateway-URL. Absolut, http oder https.
Helply:ApiKeyAPI-Key des Gateways.
Helply:ModelOptional. Ohne den Wert prüft der Server die Modelle, die das Gateway auflistet, und nutzt das erste, das auf Tool-Aufrufe antwortet.

BaseUrl und ApiKey schalten Helply zusammen ein. Diese drei Einstellungen haben keinen Standardwert. Setze sie nur als Umgebungsvariablen (Helply__BaseUrl, Helply__ApiKey, Helply__Model), nie in appsettings. Ohne sie loggt der Server, dass Helply deaktiviert ist, und User sehen es als ausgeschaltet.

Limits ​

Diese Schlüssel liegen unter Helply:Limits.

SchlüsselStandardZweck
MessagesPerMinute10Nachrichten pro User und Minute.
MessagesPerDay200Nachrichten pro User und Tag.
MaxInputChars4000Längste Nachricht.
RunTimeoutSeconds120Zeitbudget für einen Durchgang.
RunTimeoutSecondsWithWorkspace300Zeitbudget für einen Durchgang mit dem Workspace.
MaxToolIterations8Tool-Runden in einem Durchgang.
MaxToolIterationsWithWorkspace16Tool-Runden in einem Durchgang mit dem Workspace.
MaxHistoryMessages40Frühere Nachrichten, die an das Modell gehen.
MaxHistoryChars60000Früherer Text, der an das Modell geht.
MaxOutputTokens2048Längste Antwort.
MaxToolResultChars16000Längstes Tool-Ergebnis im Prompt. Längere Ergebnisse werden mit einem Hinweis gekürzt.
MaxToolArgumentChars20000Längste serialisierte Tool-Argumente. Grössere Aufrufe werden abgelehnt.
MaxAttachmentTextChars30000Höchstmenge Text aus einem Anhang im Prompt.
MaxAttachmentTextTotalChars60000Höchstmenge Anhangstext in einer Modell-Anfrage.
MaxNativeBytesPerRequest12000000Höchstmenge Datei-Bytes (Bilder, PDFs), die in einer Modell-Anfrage als Dateien gesendet werden.

Workspace ​

Mit dem Workspace kann Helply Code in einer Sandbox ausführen. Er braucht Helply:Sandbox:BaseUrl und Helply:Sandbox:ApiKey, der mindestens 32 Zeichen haben muss. Setze sie als Umgebungsvariablen (Helply__Sandbox__BaseUrl, Helply__Sandbox__ApiKey). Die Einrichtung steht im Deploy-README.

MCP-Server ​

Der Server stellt MCP unter /mcp bereit, damit User KI-Apps verbinden können.

SchlüsselZweck
Mcp:PublicUrlDer öffentliche Origin und die Audience jedes MCP-Tokens. Setze ihn in Deployments. Ohne ihn nimmt der Server den Origin aus jeder Anfrage.
Mcp:AllowedOriginsBrowser-Origins, die CORS nutzen dürfen, neben dem eigenen des Servers (Mcp__AllowedOrigins__0, __1 und so weiter). Wildcards werden nicht unterstützt.

Normalerweise setzt du nur diese zwei. Token-Laufzeiten und Limits liegen ebenfalls unter Mcp: und haben funktionierende Standardwerte (McpOAuthOptions).

Registrierungen auf die Schweiz beschränken ​

Setze SignUp:SwitzerlandOnly auf true (SignUp__SwitzerlandOnly=true in config/backend.env), um neue Konten nur aus Schweizer Netzen anzunehmen. Standardmässig ist das aus.

  • Registrierungen mit Passwort aus anderen Netzen erhalten eine Fehlermeldung. Der Server vergleicht die Adresse nur mit einer eingebauten Liste und speichert oder protokolliert sie nicht.
  • OIDC-Anbieter können keine Konten erstellen, egal was AllowSignUp sagt. Konten, die bereits einen Anbieter verknüpft haben, nutzen ihn weiter.
  • Bestehende Konten funktionieren weiterhin überall. Der private Modus hat kein Konto und ist deshalb nicht betroffen.
  • Eine Schweizer Adresse muss den Server erreichen. Setze hinter einem Proxy ForwardedHeaders:KnownNetworks korrekt, sonst wird jede Registrierung abgelehnt.

Die Liste stammt aus RIPE-Registerdaten. Diese zeigen, wo ein Netz registriert ist, und sind deshalb nicht exakt. Ein VPN kann sie umgehen. Führe vor einem Release scripts/update-swiss-networks.sh aus, um die Liste zu aktualisieren.

Autorisierungsrichtlinie ​

Die Fallback-Richtlinie verlangt für jeden Endpunkt einen authentifizierten User (AddSchulyAuthorization). Endpunkte nehmen sich mit [AllowAnonymous] aus. Diese brauchen kein Token:

  • Die anonyme /api/app-Oberfläche, zum Beispiel der Schulsystem-Katalog und die statischen Logo-Dateien unter wwwroot, damit die App ihren Login-Katalog laden kann.
  • Registrierung, Login und die anderen öffentlichen Anmelde-Endpunkte unter /auth.

Plugins ​

Die Registry-URL, die Datei mit den gewünschten Plugins und die Verzeichnisse findest du unter Plugin-Verwaltung.

Logging ​

Setze Log-Levels unter Logging:LogLevel in appsettings.json. Das Development-Override erhöht das HTTP-Logging für das Nachverfolgen von Anfragen auf Information.