diff --git a/src/App.jsx b/src/App.jsx
index 940c819..3ffb752 100755
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,7 +1,7 @@
import React, { useState, useEffect, useCallback, useRef, Suspense, lazy } from "react";
import { NAV_ITEMS, defaultData } from "./constants.js";
import { verifyPassword, withHashedPassword, stripCredentials } from "./utils.js";
-import { storage, isCloudBackend } from "./storage/adapter.js";
+import { storage, isCloudBackend, isServerMode } from "./storage/adapter.js";
import { applyMigrations } from "./storage/migrations.js";
import Login from "./views/Login.jsx";
import Setup from "./views/Setup.jsx";
@@ -464,8 +464,10 @@ export default function App() {
// lokalen Daten gibt. Sobald er gewählt hat, übernimmt der jeweilige Wizard.
// UpdateNotifier wird in allen Pre-Login-Screens mitgerendert, damit ein
// hängender Setup-Wizard sich via Auto-Update selbst befreien kann.
+ // Server-Modus (gehostete Web-GUI): nie die Lokal/Server-Wahl zeigen — die
+ // App ist fest an diesen Server gebunden. Nur die lokale DMG zeigt die Wahl.
const hasChosenBackend = localStorage.getItem("rapport_backend_chosen") === "1";
- if (!hasChosenBackend && isNewInstall && !data.settings.setupCompleted && !currentUser) {
+ if (!isServerMode && !hasChosenBackend && isNewInstall && !data.settings.setupCompleted && !currentUser) {
return <>>;
}
diff --git a/src/storage/adapter.js b/src/storage/adapter.js
index 52e93a7..1ccbdb9 100644
--- a/src/storage/adapter.js
+++ b/src/storage/adapter.js
@@ -45,8 +45,17 @@ export class LocalStorageAdapter {
}
}
+// SERVER-MODUS: dieser Build ist die gehostete Web-GUI eines bestimmten
+// Servers (gesetzt via VITE_SERVER_MODE=1 im Dockerfile.app). Dann ist die App
+// FEST an diesen einen Server gebunden — keine Lokal/Server-Wahl, kein Wechsel
+// der Server-Adresse, kein Verbinden auf andere Instanzen. Nur der Login auf
+// genau diesem Server. Die lokale DMG (Tauri) setzt diese Flag NIE und behält
+// die volle Wahl (Lokal / beliebige Server-IP).
+const _isTauri = typeof window !== "undefined" && !!window.__TAURI_INTERNALS__;
+export const isServerMode = import.meta.env.VITE_SERVER_MODE === "1" && !_isTauri;
+
function createAdapter() {
- const isTauri = typeof window !== "undefined" && !!window.__TAURI_INTERNALS__;
+ const isTauri = _isTauri;
// Build-time-URL nur für Web-Deploy gültig. Tauri-Builds ignorieren den
// eingebrannten Wert — Desktop-User geben die Server-URL aktiv ein.
// Der Anon-Key bleibt aus dem Build, weil er pro Cloud-Instanz konstant ist
@@ -54,6 +63,22 @@ function createAdapter() {
const envUrl = isTauri ? null : import.meta.env.VITE_SUPABASE_URL;
const envKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
+ // ── Server-Modus: fest auf diesen Server, ohne Wahlmöglichkeit ───────────
+ if (isServerMode) {
+ if (!envUrl || !envKey) {
+ console.error("VITE_SERVER_MODE=1, aber VITE_SUPABASE_URL/ANON_KEY fehlen — Fehlkonfiguration des Web-Builds.");
+ return new LocalStorageAdapter();
+ }
+ // localStorage konsistent halten (Login liest cloud_url für listStudios),
+ // aber der User kann nichts davon ändern — die Werte kommen aus dem Build.
+ if (typeof localStorage !== "undefined") {
+ localStorage.setItem("rapport_backend", "cloud");
+ localStorage.setItem("rapport_backend_chosen", "1");
+ localStorage.setItem("rapport_cloud_url", envUrl.replace(/\/+$/, ""));
+ }
+ return new SupabaseAdapter(envUrl, envKey);
+ }
+
if (typeof localStorage !== "undefined") {
// ── Auto-Recovery für 0.8.0-Upgrade-Bug ──────────────────────────────
// 0.8.0 hat Cloud-Modus ungewollt gesetzt bei Lokal-Usern (siehe 0.8.1
diff --git a/src/views/Login.jsx b/src/views/Login.jsx
index fec49fb..3ae131b 100755
--- a/src/views/Login.jsx
+++ b/src/views/Login.jsx
@@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from "react";
-import { storage, isCloudBackend } from "../storage/adapter.js";
+import { storage, isCloudBackend, isServerMode } from "../storage/adapter.js";
const isValidEmail = (s) => /.+@.+\..+/.test(s);
@@ -121,8 +121,10 @@ export default function Login({ verifyLogin, settings, version, cloudUnreachable
const userPlaceholder = isCloud ? "name@studio.ch" : "admin";
const userInputType = isCloud ? "email" : "text";
- const showUrlField = isCloud && editUrl;
- const showUrlBadge = isCloud && !editUrl && cloudUrl;
+ // Im Server-Modus (gehostete Web-GUI) gibt es keine Server-Adress-Eingabe —
+ // die App ist fest an diesen Server gebunden.
+ const showUrlField = isCloud && editUrl && !isServerMode;
+ const showUrlBadge = isCloud && !editUrl && cloudUrl && !isServerMode;
// Hostname zur Anzeige (ohne Protokoll, ohne Port falls Standard)
let urlDisplay = cloudUrl;
@@ -381,6 +383,10 @@ export default function Login({ verifyLogin, settings, version, cloudUnreachable
)}
{/* Verbindung-Switch + Server-Anzeige (dezent darunter) */}
+ {/* Verbindungs-Switch (Lokal/Server + Server-Adresse) nur in der lokalen
+ DMG. Die gehostete Web-GUI (Server-Modus) ist fest an diesen Server
+ gebunden — keine Wahl, kein Wechsel. */}
+ {!isServerMode && (
)}
+ )}
{version ? `V${version}` : ""}