feat: Improve CMS health check error reporting and limit connectivity notice display to developer and debug environments.
Some checks failed
Build & Deploy KLZ Cables / 🔍 Prepare Environment (push) Successful in 22s
Build & Deploy KLZ Cables / 🧪 Quality Assurance (push) Successful in 1m32s
Build & Deploy KLZ Cables / 🚀 Deploy (push) Has been cancelled
Build & Deploy KLZ Cables / ⚡ PageSpeed (push) Has been cancelled
Build & Deploy KLZ Cables / 🔔 Notifications (push) Has been cancelled
Build & Deploy KLZ Cables / 🏗️ Build & Push (push) Has been cancelled

This commit is contained in:
2026-02-02 13:42:20 +01:00
parent 372a0c5cfa
commit 479a36f1d0
2 changed files with 98 additions and 67 deletions

View File

@@ -4,69 +4,82 @@ import React, { useEffect, useState } from 'react';
import { AlertCircle, RefreshCw, Database } from 'lucide-react'; import { AlertCircle, RefreshCw, Database } from 'lucide-react';
export default function CMSConnectivityNotice() { export default function CMSConnectivityNotice() {
const [status, setStatus] = useState<'checking' | 'ok' | 'error'>('checking'); const [status, setStatus] = useState<'checking' | 'ok' | 'error'>('checking');
const [errorMsg, setErrorMsg] = useState(''); const [errorMsg, setErrorMsg] = useState('');
const [isVisible, setIsVisible] = useState(false); const [isVisible, setIsVisible] = useState(false);
useEffect(() => { useEffect(() => {
// Only show in development or if explicitly checking // Only show if we've detected an issue AND we are in a context where we want to see it
const checkCMS = async () => { const checkCMS = async () => {
try { const isDebug = new URLSearchParams(window.location.search).has('cms_debug');
const response = await fetch('/api/health/cms'); const isLocal =
const data = await response.json(); window.location.hostname === 'localhost' || window.location.hostname.includes('127.0.0.1');
const isStaging =
window.location.hostname.includes('staging') ||
window.location.hostname.includes('testing');
if (data.status !== 'ok') { // Only proceed with check if it's developer context
setStatus('error'); if (!isLocal && !isStaging && !isDebug) return;
setErrorMsg(data.message);
setIsVisible(true);
} else {
setStatus('ok');
setIsVisible(false);
}
} catch (err) {
setStatus('error');
setErrorMsg('Could not connect to CMS health endpoint');
setIsVisible(true);
}
};
checkCMS(); try {
}, []); const response = await fetch('/api/health/cms');
const data = await response.json();
if (!isVisible) return null; if (data.status !== 'ok') {
setStatus('error');
setErrorMsg(data.message);
setIsVisible(true);
} else {
setStatus('ok');
setIsVisible(false);
}
} catch (err) {
// If it's a connection error, only show if we are really debugging
if (isDebug || isLocal) {
setStatus('error');
setErrorMsg('Could not connect to CMS health endpoint');
setIsVisible(true);
}
}
};
return ( checkCMS();
<div className="fixed bottom-4 right-4 z-[9999] animate-slide-up"> }, []);
<div className="bg-red-500/90 backdrop-blur-md border border-red-400 text-white p-4 rounded-2xl shadow-2xl max-w-sm">
<div className="flex items-start gap-3"> if (!isVisible) return null;
<div className="bg-white/20 p-2 rounded-lg">
<AlertCircle className="w-5 h-5" /> return (
</div> <div className="fixed bottom-4 right-4 z-[9999] animate-slide-up">
<div className="flex-1"> <div className="bg-red-500/90 backdrop-blur-md border border-red-400 text-white p-4 rounded-2xl shadow-2xl max-w-sm">
<h4 className="font-bold text-sm mb-1">CMS Issue Detected</h4> <div className="flex items-start gap-3">
<p className="text-xs opacity-90 leading-relaxed mb-3"> <div className="bg-white/20 p-2 rounded-lg">
{errorMsg === 'relation "products" does not exist' <AlertCircle className="w-5 h-5" />
? 'The database schema is missing. Please sync your local data to this environment.' </div>
: errorMsg || 'The application cannot connect to the Directus CMS.'} <div className="flex-1">
</p> <h4 className="font-bold text-sm mb-1">CMS Issue Detected</h4>
<div className="flex gap-2"> <p className="text-xs opacity-90 leading-relaxed mb-3">
<button {errorMsg === 'relation "products" does not exist'
onClick={() => window.location.reload()} ? 'The database schema is missing. Please sync your local data to this environment.'
className="bg-white text-red-600 text-[10px] font-bold uppercase tracking-wider px-3 py-1.5 rounded-lg flex items-center gap-2 hover:bg-neutral-100 transition-colors" : errorMsg || 'The application cannot connect to the Directus CMS.'}
> </p>
<RefreshCw className="w-3 h-3" /> <div className="flex gap-2">
Retry <button
</button> onClick={() => window.location.reload()}
<button className="bg-white text-red-600 text-[10px] font-bold uppercase tracking-wider px-3 py-1.5 rounded-lg flex items-center gap-2 hover:bg-neutral-100 transition-colors"
onClick={() => setIsVisible(false)} >
className="bg-black/20 text-white text-[10px] font-bold uppercase tracking-wider px-3 py-1.5 rounded-lg hover:bg-black/30 transition-colors" <RefreshCw className="w-3 h-3" />
> Retry
Dismiss </button>
</button> <button
</div> onClick={() => setIsVisible(false)}
</div> className="bg-black/20 text-white text-[10px] font-bold uppercase tracking-wider px-3 py-1.5 rounded-lg hover:bg-black/30 transition-colors"
</div> >
Dismiss
</button>
</div> </div>
</div>
</div> </div>
); </div>
</div>
);
} }

View File

@@ -93,31 +93,49 @@ export async function getProductBySlug(slug: string, locale: string = 'de') {
export async function checkHealth() { export async function checkHealth() {
try { try {
await ensureAuthenticated(); // 1. Connectivity & Auth Check
try {
// 1. Basic connectivity check await ensureAuthenticated();
await client.request(readCollections()); await client.request(readCollections());
} catch (e: any) {
console.error('Directus authentication failed during health check:', e);
return {
status: 'error',
message:
'Authentication failed. Check your DIRECTUS_ADMIN_EMAIL and DIRECTUS_ADMIN_PASSWORD.',
code: 'AUTH_FAILED',
details: e.message,
};
}
// 2. Schema check (does the products table exist?) // 2. Schema check (does the products table exist?)
try { try {
await client.request(readItems('products', { limit: 1 })); await client.request(readItems('products', { limit: 1 }));
} catch (e: any) { } catch (e: any) {
if (e.message?.includes('does not exist') || e.code === 'INVALID_PAYLOAD') { if (
e.message?.includes('does not exist') ||
e.code === 'INVALID_PAYLOAD' ||
e.status === 404
) {
return { return {
status: 'error', status: 'error',
message: 'The "products" collection is missing. Please sync your data.', message: 'The "products" collection is missing or inaccessible. Please sync your data.',
code: 'SCHEMA_MISSING', code: 'SCHEMA_MISSING',
}; };
} }
throw e; return {
status: 'error',
message: `Schema error: ${e.message}`,
code: 'SCHEMA_ERROR',
};
} }
return { status: 'ok', message: 'Directus is reachable and responding.' }; return { status: 'ok', message: 'Directus is reachable and responding.' };
} catch (error: any) { } catch (error: any) {
console.error('Directus health check failed:', error); console.error('Directus health check failed with unexpected error:', error);
return { return {
status: 'error', status: 'error',
message: error.message || 'Unknown error', message: error.message || 'An unexpected error occurred while connecting to the CMS.',
code: error.code || 'UNKNOWN', code: error.code || 'UNKNOWN',
}; };
} }