feat: nicht dauerhaftes Upload-Verzeichnis wird erkannt, bevor Daten verloren gehen
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m12s
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m12s
Ergaenzt den Abgleich ausc8ddcecum die Pruefung, die frueher anschlaegt. checkUploadFiles() erkennt fehlende Dateien — also erst, NACHDEM sie weg sind. checkUploadVolume() erkennt die Ursache schon vorher: liegt UPLOAD_DIR im Container statt auf einem gemounteten Volume, sind alle Bilder und Videos beim naechsten Redeploy verloren, auch wenn gerade noch jede Datei da ist. Erkennung ueber die Geraete-Kennung (st_dev): ein eigener Mountpunkt hat eine andere als sein uebergeordnetes Verzeichnis. Bewusst eine Heuristik und damit nur ein Hinweis, keine Blockade — ein Bind-Mount innerhalb desselben Dateisystems kann dieselbe Kennung tragen. Ausserhalb von NODE_ENV=production immer "gemountet", weil UPLOAD_DIR lokal als "./uploads" im Projektverzeichnis liegt und dort sonst ein Daueralarm entstuende. Die Funktion liegt in lib/uploads.ts statt in lib/upload-health.ts: Letzteres importiert Prisma und laesst sich ohne DATABASE_URL nicht testen — dieselbe Ueberlegung wie bei lib/form-fields.ts inff365c3. Als reine Funktion neben UPLOAD_DIR ist sie direkt pruefbar, und dort gehoert sie fachlich ohnehin hin. Vier Tests: kein Alarm ausserhalb der Produktion, ein gewoehnliches Verzeichnis wird in Produktion als nicht dauerhaft erkannt, ein fehlendes Verzeichnis erzeugt keinen Fehlalarm, und der gepruefte Pfad kommt mit zurueck, damit die Warnung ihn benennen kann. Das Admin-Dashboard zeigt beide Befunde getrennt: die Vorwarnung als Hinweis, fehlende Dateien als Fehler. Nicht enthalten und auch nicht moeglich: das Anwenden der Manifeste im Cluster. Auf dieser Maschine gibt es weder kubectl noch eine kubeconfig; die beiden kubectl-Befehle aus k8s/README.md muss jemand mit Cluster-Zugriff einmalig ausfuehren. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
c8ddcec04c
commit
c61ae92390
6 files changed
+142
-1
No files matched your search
+20
-1
@@ -4,6 +4,7 @@ import { formatPrice } from "@/lib/format";
|
||||
import { getLocale } from "@/i18n/locale";
|
||||
import { getDictionary } from "@/i18n/get-dictionary";
|
||||
import { checkUploadFiles } from "@/lib/upload-health";
|
||||
import { checkUploadVolume } from "@/lib/uploads";
|
||||
|
||||
const DASHBOARD_ICON_PROPS = {
|
||||
width: 20,
|
||||
@@ -228,7 +229,10 @@ export default async function AdminDashboardPage() {
|
||||
// Bewusst NACH den Kennzahlen abgefragt und nicht in deren Promise.all:
|
||||
// schlaegt der Dateiabgleich fehl (etwa weil das Upload-Verzeichnis gar
|
||||
// nicht lesbar ist), soll das Dashboard trotzdem seine Zahlen zeigen.
|
||||
const uploadHealth = await checkUploadFiles().catch(() => null);
|
||||
const [uploadHealth, uploadVolume] = await Promise.all([
|
||||
checkUploadFiles().catch(() => null),
|
||||
checkUploadVolume().catch(() => null),
|
||||
]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -239,6 +243,21 @@ export default async function AdminDashboardPage() {
|
||||
ein "emptyDir" statt eines PersistentVolumeClaim). Ohne diesen
|
||||
Hinweis faellt das erst auf, wenn Kundschaft im Shop leere
|
||||
Produktkacheln sieht — im Log steht nichts. */}
|
||||
{/* Schlaegt an, BEVOR etwas verloren geht: liegt das
|
||||
Upload-Verzeichnis im Container statt auf einem gemounteten
|
||||
Volume, sind die Dateien beim naechsten Redeploy weg — auch wenn
|
||||
gerade noch alle vorhanden sind. */}
|
||||
{uploadVolume && !uploadVolume.mounted ? (
|
||||
<div className="mb-8 border border-honey/50 bg-honey/10 p-4">
|
||||
<p className="text-sm text-honey-dark">
|
||||
{t.adminDashboardPage.uploadsNotPersistentTitle}
|
||||
</p>
|
||||
<p className="mt-2 text-xs text-ink/70">
|
||||
{t.adminDashboardPage.uploadsNotPersistentHint(uploadVolume.uploadDir)}
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{uploadHealth && uploadHealth.missing > 0 ? (
|
||||
<div className="mb-8 border border-red-700/40 bg-red-50 p-4">
|
||||
<p className="text-sm text-red-800">
|
||||
|
||||
Reference in new issue
Block a user