feat: + initialize project with docker-compose infrastructure and server application logic

This commit is contained in:
2026-04-08 00:18:09 +02:00
parent 8d90d97182
commit c3fed5226a
2 changed files with 1020 additions and 989 deletions

View File

@@ -834,15 +834,46 @@ app.post('/v1/health-check', async (request, response) => {
}); });
const analysis = analysisResponse?.analysis; const analysis = analysisResponse?.analysis;
if (!analysis) { if (!analysis) {
// All models in the chain failed (timeout, quota, network) — return a graceful
// "unavailable" result instead of PROVIDER_ERROR so the user never sees an error alert.
// Credits are NOT charged. Response is NOT cached so the user can retry.
console.warn('Health check analysis was null — all models returned unusable output.', { console.warn('Health check analysis was null — all models returned unusable output.', {
attemptedModels: analysisResponse?.attemptedModels, attemptedModels: analysisResponse?.attemptedModels,
modelUsed: analysisResponse?.modelUsed, modelUsed: analysisResponse?.modelUsed,
}); });
const error = new Error( const unavailableIssue = language === 'de'
`Health check AI failed. Tried: ${(analysisResponse?.attemptedModels || []).join(', ')}. Verify API key, model access, and network.` ? 'Die KI-Analyse ist gerade nicht verfügbar. Bitte versuche es in einem Moment erneut.'
); : language === 'es'
error.code = 'PROVIDER_ERROR'; ? 'El análisis de IA no está disponible ahora. Inténtalo de nuevo en un momento.'
throw error; : 'AI analysis is temporarily unavailable. Please try again in a moment.';
const unavailableAction = language === 'de'
? 'Erneut scannen wenn die Verbindung stabil ist.'
: language === 'es'
? 'Volver a escanear cuando la conexión sea estable.'
: 'Try scanning again when your connection is stable.';
const fallbackHealthCheck = {
generatedAt: nowIso(),
overallHealthScore: 50,
status: 'watch',
likelyIssues: [{
title: language === 'de' ? 'Analyse nicht verfügbar' : language === 'es' ? 'Análisis no disponible' : 'Analysis unavailable',
confidence: 0.1,
details: unavailableIssue,
}],
actionsNow: [unavailableAction],
plan7Days: [unavailableAction],
creditsCharged: 0,
imageUri,
};
const fallbackPayload = {
healthCheck: fallbackHealthCheck,
creditsCharged: 0,
modelUsed: null,
modelFallbackCount: Math.max((analysisResponse?.attemptedModels?.length || 0) - 1, 0),
billing: await getBillingSummary(db, userId),
};
response.status(200).json(fallbackPayload);
return;
} }
let creditsCharged = 0; let creditsCharged = 0;