Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 66 additions & 19 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,73 @@
# This build supports SQLite only. The runtime client and Prisma CLI both read DATABASE_URL.
DATABASE_URL="file:./prisma/dev.db"

# Root secret. Required in every environment, including development. Must be base64 or
# hex encoding of exactly 32 random bytes — a passphrase is rejected, because this key
# also protects credentials at rest and HKDF has no work factor. Generate once with
# `openssl rand -base64 32`, keep it stable, and back it up.
#
# Session signing, credential encryption, and OTA download-link signing are each derived
# from it with a distinct HKDF label, so a leak of one derived key does not expose the
# others. Rotating it signs everyone out and invalidates outstanding OTA links.
APP_SECRET="replace-with-openssl-rand-base64-32"

# Set during an APP_SECRET rotation, to the value(s) being replaced (comma-separated).
# Stored credentials sealed under a listed root are re-encrypted at startup; remove this
# once the server has started cleanly. Without it, a changed APP_SECRET refuses to start.
# APP_SECRET_PREVIOUS="the-previous-app-secret"

# Origins this server may be reached at (comma-separated). One list drives Better Auth's
# CSRF and redirect allowlist and the Next.js dev-server allowlist.
#
# Localhost, 127.0.0.1, and [::1] are always trusted outside production, so this is only
# needed for other hostnames. Entries may be a bare host, a host:port, or a full origin;
# a leading "*." wildcard is allowed outside production only, because a wildcard trusts
# every host under it for both CSRF and post-login redirects.
#
# Optional. With neither this nor PUBLIC_BASE_URL set, a production server trusts the host
# each request arrived on. Sign-in then works on any hostname and cross-site requests are
# still rejected, but a forged Host header can steer the absolute URLs this server
# generates (OAuth callbacks, iOS enrollment and install links, the GitHub webhook URL).
# A warning is logged at startup when that happens.
# APP_ORIGINS="app.example.com,*.hare-bull.ts.net"

# Believe x-forwarded-host / x-forwarded-proto. Enable only when a reverse proxy in front
# of this server sets them and strips client-supplied copies.
# TRUST_PROXY_HEADERS="false"

# Every account has the same, complete authority over this instance. There are no
# roles: any signed-in user can create and delete accounts, set anyone's password,
# revoke sessions, issue and revoke API keys, and reopen public registration.
# Creating an account for someone is granting them full control of the server —
# and of every credential it holds. Registration closes automatically once the
# first account is created.
# AUTH_MODE="password" # password | oidc | both

# One generic OAuth/OIDC provider is supported when AUTH_MODE is oidc or both.
# Supply a discovery URL, or all three explicit endpoint URLs. PKCE is always enabled;
# issuer validation defaults to false and can be enabled explicitly. The callback URL
# registered with the provider is:
# ${origin}/api/auth/oauth2/callback/${AUTH_OAUTH_PROVIDER_ID}
# where ${origin} is PUBLIC_BASE_URL when set, otherwise the first APP_ORIGINS entry.
# AUTH_OAUTH_PROVIDER_ID="oidc"
# AUTH_OAUTH_PROVIDER_NAME="Single sign-on"
# AUTH_OAUTH_CLIENT_ID="client-id"
# AUTH_OAUTH_CLIENT_SECRET="client-secret"
# AUTH_OAUTH_SCOPES="openid,profile,email"
# AUTH_OAUTH_REQUIRE_ISSUER_VALIDATION="false"
# AUTH_OAUTH_DISCOVERY_URL="https://identity.example.com/.well-known/openid-configuration"
# AUTH_OAUTH_ISSUER="https://identity.example.com"
# AUTH_OAUTH_AUTHORIZATION_URL="https://identity.example.com/oauth2/authorize"
# AUTH_OAUTH_TOKEN_URL="https://identity.example.com/oauth2/token"
# AUTH_OAUTH_USER_INFO_URL="https://identity.example.com/oauth2/userinfo"

# Long-lived application credential storage. Database storage is the default on npm,
# Linux, and containers. Homebrew installs default to macOS Keychain instead.
# CREDENTIAL_STORAGE_TYPE="database" # database | vault | keychain

# Optional database credential encryption key. It must be strict base64 encoding of exactly
# 32 random bytes. Generate once with `openssl rand -base64 32`, back it up securely, and
# retain it for the lifetime of all encrypted Credential rows. Restart after setting it.
# Missing keys permit plaintext database storage with a UI warning. Invalid, missing, or
# changed keys never fall back to plaintext when encrypted rows exist. Key rotation is not
# currently supported.
# CREDENTIAL_ENCRYPTION_KEY="base64-encoded-32-byte-key"
# Database credential storage is always encrypted, with a key derived from APP_SECRET.
# There is no plaintext mode and no separate encryption key to configure. Vault and
# Keychain storage do not use the derived key at all.

# HashiCorp Vault KV v2 configuration (used when CREDENTIAL_STORAGE_TYPE=vault).
# VAULT_ADDR is required. Token and namespace are optional; other auth workflows may use
Expand Down Expand Up @@ -59,6 +115,7 @@ DATABASE_URL="file:./prisma/dev.db"
# CONTROL_AGENT_DEV_SERVER="http://127.0.0.1:3000"
# CONTROL_AGENT_DEV_WEBSOCKET_SERVER="ws://127.0.0.1:3092/graphql"
# CONTROL_AGENT_DEV_CONFIG="/absolute/path/to/dev-agent-config.json"
# CONTROL_AGENT_DEV_ENROLLMENT_TOKEN="enroll_one-time-token"

# Public origin used to build iOS device-enrollment and over-the-air install URLs
# and to configure the GitHub App webhook when forwarded headers do not already
Expand All @@ -72,9 +129,8 @@ DATABASE_URL="file:./prisma/dev.db"
# Access application paths must not contain query strings.
# PUBLIC_BASE_URL="https://builds.example.com"

# Secret used to sign short-lived iOS install download links. A random per-process
# value is used when unset, which invalidates outstanding links on restart.
# OTA_TOKEN_SECRET="a-long-random-string"
# Short-lived iOS install download links are signed with a key derived from APP_SECRET,
# so they survive a restart. There is nothing to configure.

# Where downloaded build artifacts are cached, and how much room they may take.
# Installing over the air re-reads the package several times, so it is fetched
Expand All @@ -88,12 +144,3 @@ DATABASE_URL="file:./prisma/dev.db"

# Apollo GraphOS API key used by `npm run schema:publish` (optional).
# APOLLO_KEY="service:your-graph:replace-with-a-graph-api-key"

# Optional authentication for the built-in Streamable HTTP MCP endpoint and
# Tools-page calls. When set, clients must send `Authorization: Bearer <value>`.
# When unset, tool calls are accepted without authentication.
# TOOLS_API_TOKEN="generate-a-long-random-value"

# Comma-separated list of extra origins allowed by the Next.js dev server (optional).
# Localhost, the machine hostname, and LAN IPs are already allowed by default.
# ALLOWED_DEV_ORIGINS="dev.example.com,10.0.0.50"
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@
"type": "shell",
"label": "screenshots:copy",
"group": "test",
"command": "npm run screenshots:copy -- '${input:docsDirectory}'",
"detail": "Copy the desktop light and dark captures into the docs project"
"command": "npm run screenshots:copy -- --include-videos '${input:docsDirectory}'",
"detail": "Copy the desktop light and dark captures, including walkthrough videos, into the docs project"
},
{
"type": "shell",
Expand Down
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,13 @@ VOLUME ["/data"]

EXPOSE 3090 3091

# Probes /api/auth/config rather than a GraphQL query because GraphQL now requires
# a credential, and baking one into an image is worse than the coverage it buys.
# The route still exercises the server, the auth configuration, and a database read,
# so the check is narrower than before but not shallow: a broken GraphQL layer alone
# no longer fails it.
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD ["node", "-e", "fetch('http://127.0.0.1:'+process.env.PORT+'/api/graphql',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({query:'{ health }'})}).then(async response=>{const body=await response.json();if(!response.ok||body.data?.health!=='ok')process.exit(1)}).catch(()=>process.exit(1))"]
CMD ["node", "-e", "fetch('http://127.0.0.1:'+process.env.PORT+'/api/auth/config').then(async response=>{const body=await response.json();if(!response.ok||!body.mode)process.exit(1)}).catch(()=>process.exit(1))"]

STOPSIGNAL SIGTERM

Expand Down
119 changes: 98 additions & 21 deletions messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"cannotBeUndone": "Diese Aktion kann nicht rückgängig gemacht werden."
},
"shell": {
"productName": "AI Development Environment",
"productName": "KI-Entwicklungsumgebung",
"dashboard": "Übersicht",
"ai": "KI",
"navigation": "Navigation",
Expand Down Expand Up @@ -57,7 +57,10 @@
"sessions": "Sitzungen",
"drafts": "Entwürfe",
"credentials": "Anmeldedaten",
"users": "Benutzer",
"apiKeys": "API-Schlüssel",
"settings": "Einstellungen",
"signOut": "Abmelden",
"costs": "Kosten",
"newWorkflow": "Neuer Workflow",
"newCommand": "Neuer Befehl",
Expand Down Expand Up @@ -983,13 +986,6 @@
"removeDeviceTitle": "Dieses registrierte Gerät entfernen?",
"removeDeviceDescription": "Dieses Gerät erhält keine nativen Benachrichtigungen mehr. Es kann sich über die App erneut registrieren."
},
"credentialEncryption": {
"title": "Datenbank-Anmeldedaten sind nicht verschlüsselt",
"description": "Geheimnisse in der Anwendungsdatenbank werden derzeit im Klartext gespeichert. Erzeugen Sie mit diesem Befehl einen 32-Byte-Schlüssel:",
"instructionsPrefix": "Setzen Sie den erzeugten Wert als",
"instructionsSuffix": "in der Serverumgebung und starten Sie den Server neu. Vorhandene Klartext-Anmeldedaten werden nach dem Neustart gemeinsam verschlüsselt.",
"backup": "Sichern Sie diesen Schlüssel geschützt und bewahren Sie ihn während der gesamten Lebensdauer der verschlüsselten Einträge auf. Bei Verlust oder Änderung werden diese Anmeldedaten unlesbar."
},
"credentials": {
"title": "Anmeldedaten",
"description": "Prüfen Sie das aktive Backend, den Schutzstatus und ein reines Metadaten-Inventar. Geheimwerte werden hier nie angezeigt.",
Expand Down Expand Up @@ -1082,10 +1078,8 @@
"readWrite": "Lesen und Schreiben"
},
"warningTitles": {
"DATABASE_UNENCRYPTED": "Datenbankverschlüsselung ist deaktiviert",
"CREDENTIAL_ENCRYPTION_KEY_INVALID": "Verschlüsselungsschlüssel ist ungültig",
"CREDENTIAL_ENCRYPTION_KEY_MISSING": "Verschlüsselungsschlüssel fehlt",
"CREDENTIAL_ENCRYPTION_KEY_MISMATCH": "Verschlüsselungsschlüssel stimmt nicht überein",
"APP_SECRET_INVALID": "APP_SECRET ist ungültig",
"CREDENTIAL_KEY_MISMATCH": "APP_SECRET passt nicht zu gespeicherten Anmeldedaten",
"CREDENTIAL_DATA_INVALID": "Anmeldedaten sind ungültig",
"CREDENTIAL_STORAGE_TYPE_INVALID": "Speichertyp ist ungültig",
"CREDENTIAL_STORE_UNAVAILABLE": "Anmeldedatenspeicher ist nicht verfügbar",
Expand All @@ -1099,10 +1093,8 @@
"BACKEND_MISMATCH": "Anmeldedaten verwenden ein anderes Backend"
},
"warnings": {
"DATABASE_UNENCRYPTED": "Anmeldedaten werden im Klartext gespeichert, bis ein Verschlüsselungsschlüssel konfiguriert ist.",
"CREDENTIAL_ENCRYPTION_KEY_INVALID": "CREDENTIAL_ENCRYPTION_KEY muss eine strikte Base64-Kodierung von genau 32 Byte sein. Korrigieren Sie den Wert und starten Sie neu; bei einem ungültigen Schlüssel gibt es keinen Klartext-Rückfall.",
"CREDENTIAL_ENCRYPTION_KEY_MISSING": "Verschlüsselte Einträge sind vorhanden, aber der Schlüssel fehlt. Stellen Sie den ursprünglichen Schlüssel wieder her und starten Sie den Server neu.",
"CREDENTIAL_ENCRYPTION_KEY_MISMATCH": "Der konfigurierte Schlüssel passt nicht zu vorhandenen Einträgen. Stellen Sie den ursprünglichen Schlüssel wieder her und starten Sie neu.",
"APP_SECRET_INVALID": "APP_SECRET muss eine Base64- oder Hex-Kodierung von genau 32 zufälligen Bytes sein. Erzeugen Sie einen Wert mit `openssl rand -base64 32` und starten Sie den Server neu.",
"CREDENTIAL_KEY_MISMATCH": "Gespeicherte Anmeldedaten wurden mit einem anderen APP_SECRET verschlüsselt. Stellen Sie den ursprünglichen Wert wieder her oder setzen Sie ihn als APP_SECRET_PREVIOUS, damit sie beim nächsten Start neu verschlüsselt werden.",
"CREDENTIAL_DATA_INVALID": "Mindestens ein Anmeldedatensatz enthält ungültige Metadaten und kann nicht verwendet werden.",
"CREDENTIAL_STORAGE_TYPE_INVALID": "CREDENTIAL_STORAGE_TYPE muss database, vault oder keychain sein.",
"CREDENTIAL_STORE_UNAVAILABLE": "Der Anmeldedatenspeicher konnte nicht initialisiert werden. Prüfen Sie Serverkonfiguration und Protokolle.",
Expand Down Expand Up @@ -3048,17 +3040,14 @@
"auditWorkflow": "Workflow",
"connectTitle": "Externe Clients verbinden",
"connectDescription": "Andere MCP-Clients können über Streamable HTTP alle integrierten Werkzeuge dieses Servers aufrufen.",
"toolApiToken": "Tool-API-Token (optional)",
"toolApiTokenPlaceholder": "TOOLS_API_TOKEN eingeben",
"toolApiTokenHelp": "Nur erforderlich, wenn TOOLS_API_TOKEN auf dem Server konfiguriert ist. Das Token bleibt ausschließlich im Speicher dieser Seite.",
"serverUrl": "Server-URL",
"copyUrl": "Server-URL kopieren",
"clientConfig": "Client-Konfiguration",
"clientConfigHelp": "Diesen Eintrag zur MCP-Konfiguration von Claude Code, Cursor oder einem anderen Streamable-HTTP-Client hinzufügen.",
"clientConfigHelp": "Erstellen Sie einen API-Schlüssel, ersetzen Sie den Platzhalter und fügen Sie dies einem Streamable-HTTP-Client hinzu.",
"copyConfig": "Konfiguration kopieren",
"connectCopied": "Kopiert",
"connectCopyFailed": "Es konnte nicht in die Zwischenablage kopiert werden.",
"connectWarning": "Die Authentifizierung ist deaktiviert, wenn TOOLS_API_TOKEN nicht konfiguriert ist. Falls aktiviert, darf das Token nicht in die Versionsverwaltung oder in Screenshots gelangen.",
"connectWarning": "Externe MCP-Clients müssen einen API-Schlüssel in X-API-Key senden. Halten Sie ihn aus Quellcode und Screenshots fern.",
"serverHost": "Serverhost",
"customServerHost": "Benutzerdefinierter Host",
"addServer": "MCP-Server hinzufügen",
Expand Down Expand Up @@ -4462,5 +4451,93 @@
"deletions": "Löschungen",
"changeType": "Änderungsart"
}
},
"auth": {
"productName": "KI-Entwicklungsumgebung",
"signInTitle": "Willkommen zurück",
"signInDescription": "Melden Sie sich an, um diese Entwicklungsumgebung zu verwalten.",
"setupTitle": "Erstes Konto erstellen",
"setupDescription": "Dieses Konto schließt die Einrichtung ab und deaktiviert die öffentliche Registrierung.",
"registerTitle": "Konto erstellen",
"registerDescription": "Registrieren Sie sich für den Zugriff auf diese Entwicklungsumgebung.",
"registrationDisabled": "Die öffentliche Kontoregistrierung ist derzeit deaktiviert.",
"name": "Name",
"email": "E-Mail",
"password": "Passwort",
"signIn": "Anmelden",
"createAccount": "Konto erstellen",
"or": "oder",
"continueWith": "Mit {provider} fortfahren",
"needAccount": "Benötigen Sie ein Konto?",
"completeSetup": "Einrichtung abschließen",
"register": "Registrieren",
"haveAccount": "Sie haben bereits ein Konto?",
"unknownError": "Authentifizierung fehlgeschlagen. Versuchen Sie es erneut."
},
"userManagement": {
"title": "Benutzer",
"description": "Verwalten Sie Konten, aktive Sitzungen und die öffentliche Registrierung.",
"refresh": "Aktualisieren",
"createUser": "Benutzer erstellen",
"registrationTitle": "Öffentliche Registrierung",
"registrationEnabled": "Neue Benutzer können derzeit eigene Konten erstellen.",
"registrationDisabled": "Nur authentifizierte Benutzer können Konten erstellen.",
"allowRegistration": "Registrierung erlauben",
"search": "Benutzer suchen",
"searchPlaceholder": "Nach Name oder E-Mail suchen…",
"currentUser": "Aktuell",
"editNamed": "{name} bearbeiten",
"deleteNamed": "{name} löschen",
"passwordProvider": "Passwort",
"sessions": "{count, plural, one {# Sitzung} other {# Sitzungen}}",
"unknownDevice": "Unbekanntes Gerät",
"revokeSession": "Sitzung widerrufen",
"noSessions": "Keine aktiven Sitzungen",
"createTitle": "Lokales Konto erstellen",
"createDescription": "Der neue Benutzer kann sich sofort anmelden. Es wird keine Bestätigungs-E-Mail gesendet.",
"editTitle": "Benutzer bearbeiten",
"editDescription": "Aktualisieren Sie Kontodaten und optional das Passwort.",
"name": "Name",
"email": "E-Mail",
"password": "Passwort",
"leavePasswordBlank": "Leer lassen, um das vorhandene Passwort beizubehalten",
"saveChanges": "Änderungen speichern",
"delete": "Benutzer löschen",
"deleteTitle": "Benutzer löschen?",
"deleteDescription": "{name} samt Sitzungen, verknüpften Identitäten und API-Schlüsseln löschen?"
},
"apiKeyManagement": {
"title": "API-Schlüssel",
"description": "Erstellen Sie Zugangsdaten für GraphQL und unbeschränkte oder voreingestellte MCP-Clients.",
"refresh": "Aktualisieren",
"createKey": "API-Schlüssel erstellen",
"securityNotice": "API-Schlüssel haben vollen GraphQL- und MCP-Zugriff. Das Geheimnis wird nur einmal angezeigt.",
"unnamed": "Unbenannter Schlüssel",
"disabled": "Deaktiviert",
"enabled": "Aktiviert",
"owner": "Eigentümer",
"expires": "Läuft ab",
"never": "Nie",
"created": "Erstellt",
"lastUsed": "Zuletzt verwendet",
"rename": "Umbenennen",
"enable": "Aktivieren",
"disable": "Deaktivieren",
"revoke": "Widerrufen",
"emptyTitle": "Keine API-Schlüssel",
"emptyDescription": "Erstellen Sie einen Schlüssel für nicht interaktiven GraphQL- oder MCP-Zugriff.",
"createTitle": "API-Schlüssel erstellen",
"createDescription": "Wählen Sie Eigentümer und optionales Ablaufdatum.",
"name": "Name",
"optionalExpiration": "Ablauf (optional)",
"secretTitle": "API-Schlüssel kopieren",
"secretDescription": "Dies ist die einzige Anzeige des Geheimnisses. Bewahren Sie es sicher auf.",
"copied": "Kopiert",
"copy": "Kopieren",
"renameTitle": "API-Schlüssel umbenennen",
"renameDescription": "Verwenden Sie einen Namen für den Client oder die Automatisierung.",
"save": "Speichern",
"revokeTitle": "API-Schlüssel widerrufen?",
"revokeDescription": "{name} widerrufen? Verwendende Clients verlieren sofort den Zugriff."
}
}
Loading