+ {/* Halbes Update: gebaut, aber nicht neu gestartet. Ohne den Hinweis
+ sieht das aus wie ein Fehler in der Funktion. */}
+
{children}
diff --git a/web/src/components/StandHinweis.jsx b/web/src/components/StandHinweis.jsx
new file mode 100644
index 0000000..f8feb87
--- /dev/null
+++ b/web/src/components/StandHinweis.jsx
@@ -0,0 +1,39 @@
+import { useEffect, useState } from "react";
+import { api } from "../api";
+import Icon from "./Icon";
+
+// Wird von Vite beim Bauen eingesetzt (siehe vite.config.js).
+const GEBAUT = typeof __APP_SHA__ === "string" ? __APP_SHA__ : "";
+
+/**
+ * Weist darauf hin, wenn Oberfläche und Server aus verschiedenen Ständen
+ * stammen.
+ *
+ * Das passiert genau dann, wenn `npm run build` lief, der Dienst aber nicht neu
+ * gestartet wurde: Die Oberfläche ruft dann Endpunkte auf, die es serverseitig
+ * noch gar nicht gibt, und alles sieht nach einem Fehler in der Funktion aus
+ * statt nach einem halben Update.
+ *
+ * Verglichen wird nur, wenn BEIDE Seiten ihren Stand kennen – sonst schwiege
+ * der Hinweis besser, als falschen Alarm zu schlagen.
+ */
+export default function StandHinweis() {
+ const [server, setServer] = useState(null);
+ useEffect(() => {
+ let ok = true;
+ api.version().then((v) => ok && setServer(v?.git_sha || "")).catch(() => {});
+ return () => { ok = false; };
+ }, []);
+
+ if (!GEBAUT || !server || server === GEBAUT) return null;
+ return (
+
+
+
+ Oberfläche ({GEBAUT}) und Server ({server}) laufen auf verschiedenen
+ Ständen. Bitte sudo ./deploy/update.sh ausführen – sonst
+ fehlen dem Server Funktionen, die die Oberfläche schon aufruft.
+
+
+ );
+}
diff --git a/web/src/finance.css b/web/src/finance.css
index b11ed6a..744504e 100644
--- a/web/src/finance.css
+++ b/web/src/finance.css
@@ -1587,3 +1587,31 @@ tr.row-dup {
flex: 0 1 auto;
max-width: 9em;
}
+
+/* ---------- Halbes Update ----------
+ Gebaut, aber der Dienst nicht neu gestartet: Die Oberfläche ruft dann
+ Endpunkte auf, die es serverseitig noch gar nicht gibt. Ohne diesen Hinweis
+ sieht das aus wie ein Fehler in der Funktion. */
+.stand-hinweis {
+ display: flex;
+ align-items: flex-start;
+ gap: var(--sp-2);
+ margin-bottom: var(--sp-4);
+ padding: var(--sp-3) var(--sp-4);
+ border: 1px solid var(--warn);
+ border-radius: var(--radius-sm);
+ background: var(--warn-soft);
+ color: var(--text);
+ font-size: 0.85rem;
+ line-height: 1.45;
+}
+.stand-hinweis svg {
+ flex: 0 0 auto;
+ margin-top: 2px;
+}
+.stand-hinweis code {
+ padding: 1px 5px;
+ border-radius: 4px;
+ background: var(--surface-2);
+ font-size: 0.95em;
+}
diff --git a/web/vite.config.js b/web/vite.config.js
index 82299c9..fdf620f 100644
--- a/web/vite.config.js
+++ b/web/vite.config.js
@@ -1,12 +1,27 @@
+import { execSync } from "node:child_process";
+
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
+// Der Commit, aus dem dieses Bundle stammt. Die Oberflaeche vergleicht ihn mit
+// dem, den der Server meldet – laufen beide auseinander, wurde gebaut, aber der
+// Dienst nicht neu gestartet. Das kostete schon mehrfach eine halbe Stunde
+// Fehlersuche an einer Funktion, die es serverseitig noch gar nicht gab.
+function commit() {
+ try {
+ return execSync("git rev-parse --short HEAD", { encoding: "utf8" }).trim();
+ } catch {
+ return ""; // Kein Git zur Hand – dann wird nichts verglichen.
+ }
+}
+
// Im Dev-Modus wird /api an das lokale Backend weitergeleitet. Anders als in der
// Vorlage wird der /api-Präfix NICHT entfernt – das Backend bedient die Routen
// bewusst unter /api/... (ein Prozess liefert API und SPA gemeinsam aus).
// In Produktion liefert derselbe FastAPI-Prozess das gebaute Frontend mit aus.
export default defineConfig({
plugins: [react()],
+ define: { __APP_SHA__: JSON.stringify(commit()) },
server: {
port: 5173,
proxy: {