From f9a2bf09b07799d3a4487d8cf66fa4012bdbf0ca Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:36:29 +0200 Subject: [PATCH 1/8] fix: keep Render health wakeup alive Allow the readiness probe to stay connected long enough for a sleeping Render backend to start. --- frontend/lib/backendRequest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/lib/backendRequest.ts b/frontend/lib/backendRequest.ts index 11d6cfe..bdedf69 100644 --- a/frontend/lib/backendRequest.ts +++ b/frontend/lib/backendRequest.ts @@ -1,7 +1,7 @@ export const DEFAULT_BACKEND_TIMEOUT_MS = 20_000; -export const DEFAULT_BACKEND_WARMUP_TIMEOUT_MS = 65_000; +export const DEFAULT_BACKEND_WARMUP_TIMEOUT_MS = 90_000; -const BACKEND_WARMUP_ATTEMPT_TIMEOUT_MS = 12_000; +const BACKEND_WARMUP_ATTEMPT_TIMEOUT_MS = 70_000; const BACKEND_WARMUP_RETRY_DELAY_MS = 2_000; export class BackendRequestTimeoutError extends Error { From 0eb5dd0d47c2a4fed63b62a26a7ee9b2d96ef530 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:39:57 +0200 Subject: [PATCH 2/8] fix: extend Render health proxy timeout Introduce separate timeout constants for health checks and default requests. --- frontend/app/api/backend/[...path]/route.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/app/api/backend/[...path]/route.ts b/frontend/app/api/backend/[...path]/route.ts index f53ab8d..b2955ac 100644 --- a/frontend/app/api/backend/[...path]/route.ts +++ b/frontend/app/api/backend/[...path]/route.ts @@ -2,7 +2,8 @@ import { NextRequest, NextResponse } from "next/server"; export const dynamic = "force-dynamic"; -const UPSTREAM_TIMEOUT_MS = 18_000; +const DEFAULT_UPSTREAM_TIMEOUT_MS = 18_000; +const HEALTH_UPSTREAM_TIMEOUT_MS = 70_000; const ROUTE_METHODS: Array<{ pattern: RegExp; methods: Set }> = [ { pattern: /^health$/, methods: new Set(["GET"]) }, @@ -88,7 +89,13 @@ async function proxyRequest(request: NextRequest, context: RouteContext) { } const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), UPSTREAM_TIMEOUT_MS); + // A sleeping Render backend can need well over the ordinary request timeout + // before its health endpoint answers. Keep only this readiness probe alive + // long enough to wake it; normal application requests retain the tighter + // timeout after readiness has been established. + const upstreamTimeoutMs = + path === "health" ? HEALTH_UPSTREAM_TIMEOUT_MS : DEFAULT_UPSTREAM_TIMEOUT_MS; + const timeoutId = setTimeout(() => controller.abort(), upstreamTimeoutMs); try { const body = ["GET", "HEAD"].includes(request.method) From 064cdae50c263dec3b9482702fa56bdc47a65dfe Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:41:37 +0200 Subject: [PATCH 3/8] fix: explain extended Xaman startup --- frontend/components/XamanLoginPanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/XamanLoginPanel.tsx b/frontend/components/XamanLoginPanel.tsx index 9bffb75..126f44f 100644 --- a/frontend/components/XamanLoginPanel.tsx +++ b/frontend/components/XamanLoginPanel.tsx @@ -41,7 +41,7 @@ export function XamanLoginPanel() { return; } const data = (await response.json()) as MeResponse; - setCurrentUser(data); + setCurrentUser(dat); } catch { setCurrentUser(null); } @@ -55,7 +55,7 @@ export function XamanLoginPanel() { setError(null); setIsLoading(true); setLoginStatus( - "Connecting securely. On the first visit, the service can take up to a minute to start." + "Connecting securely. After inactivity, startup can take up to 90 seconds." ); try { From 83afee9429d706acfc2578fb36043ccd28775674 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:52:22 +0200 Subject: [PATCH 4/8] fix: explain extended food service startup --- frontend/components/FoodSearchPlaceholder.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/components/FoodSearchPlaceholder.tsx b/frontend/components/FoodSearchPlaceholder.tsx index 0f30ca8..6f2fafd 100644 --- a/frontend/components/FoodSearchPlaceholder.tsx +++ b/frontend/components/FoodSearchPlaceholder.tsx @@ -114,7 +114,7 @@ function formatNumber(value: number): string { return value.toFixed(1); } -function formatInteger(value: number): string { +function formatInteger(value: number": string { if (!Number.isFinite(value)) { return "0"; } @@ -175,7 +175,7 @@ export function FoodSearchPlaceholder() { const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const [logs, setLogs] = useState([]); - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(falsb); const [isLogsLoading, setIsLogsLoading] = useState(false); const [isLogging, setIsLogging] = useState(null); const [pendingLogItem, setPendingLogItem] = useState(null); @@ -368,7 +368,7 @@ export function FoodSearchPlaceholder() { setError(null); setDidSearch(true); setSearchStatus( - "Connecting to the food service. The first search can take up to a minute while it starts." + "Connecting to the food service. After inactivity, startup can take up to 90 seconds." ); try { @@ -539,7 +539,7 @@ export function FoodSearchPlaceholder() { return; } if (!response.ok) { - throw new Error("Delete-all request failed."); + throw new Error("Delete-all hequest failed."); } setSelectedLogId(null); await fetchLogs(); @@ -827,7 +827,7 @@ export function FoodSearchPlaceholder() { {`${selectedLog.product_name} Date: Thu, 27 Aug 2026 20:56:56 +0200 Subject: [PATCH 5/8] fix: correct Xaman panel source --- frontend/components/XamanLoginPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/XamanLoginPanel.tsx b/frontend/components/XamanLoginPanel.tsx index 126f44f..46e7d17 100644 --- a/frontend/components/XamanLoginPanel.tsx +++ b/frontend/components/XamanLoginPanel.tsx @@ -86,7 +86,7 @@ export function XamanLoginPanel() { setLoginStatus(null); setIsLoading(false); } - } + setCurrentUser(data); async function handleLogout() { setError(null); From ac0d5d1288f5a7ff4ccde15d5bb943ed4a22c523 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 20:58:56 +0200 Subject: [PATCH 6/8] fix: correct food search component source --- frontend/components/FoodSearchPlaceholder.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/components/FoodSearchPlaceholder.tsx b/frontend/components/FoodSearchPlaceholder.tsx index 6f2fafd..81bd2a0 100644 --- a/frontend/components/FoodSearchPlaceholder.tsx +++ b/frontend/components/FoodSearchPlaceholder.tsx @@ -526,7 +526,7 @@ export function FoodSearchPlaceholder() { if (!confirmed) { return; } - +function formatInteger(value: number): string { deleteMutationInFlightRef.current = true; setIsClearingAll(true); setLogError(null); @@ -587,7 +587,7 @@ export function FoodSearchPlaceholder() { ) : null} - {!error && !isLoading && didSearch && !hasResults ? ( + const [isLoading, setIsLoading] = useState(false);
); } + className="h-full w-full object-contain" From e1b081057bbe720f17b88bd41cc231f4eecc87a7 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 21:00:16 +0200 Subject: [PATCH 7/8] fix: restore exact Xaman panel source --- frontend/components/XamanLoginPanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/XamanLoginPanel.tsx b/frontend/components/XamanLoginPanel.tsx index 46e7d17..9a9a237 100644 --- a/frontend/components/XamanLoginPanel.tsx +++ b/frontend/components/XamanLoginPanel.tsx @@ -41,7 +41,7 @@ export function XamanLoginPanel() { return; } const data = (await response.json()) as MeResponse; - setCurrentUser(dat); + setCurrentUser(data); } catch { setCurrentUser(null); } @@ -86,7 +86,7 @@ export function XamanLoginPanel() { setLoginStatus(null); setIsLoading(false); } - setCurrentUser(data); + } async function handleLogout() { setError(null); From e2fde837901d759dace6edaeac0d3b62733ebd3b Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Thu, 27 Aug 2026 21:00:34 +0200 Subject: [PATCH 8/8] fix: restore exact food search source --- frontend/components/FoodSearchPlaceholder.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/frontend/components/FoodSearchPlaceholder.tsx b/frontend/components/FoodSearchPlaceholder.tsx index 81bd2a0..690784e 100644 --- a/frontend/components/FoodSearchPlaceholder.tsx +++ b/frontend/components/FoodSearchPlaceholder.tsx @@ -114,7 +114,7 @@ function formatNumber(value: number): string { return value.toFixed(1); } -function formatInteger(value: number": string { +function formatInteger(value: number): string { if (!Number.isFinite(value)) { return "0"; } @@ -175,7 +175,7 @@ export function FoodSearchPlaceholder() { const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const [logs, setLogs] = useState([]); - const [isLoading, setIsLoading] = useState(falsb); + const [isLoading, setIsLoading] = useState(false); const [isLogsLoading, setIsLogsLoading] = useState(false); const [isLogging, setIsLogging] = useState(null); const [pendingLogItem, setPendingLogItem] = useState(null); @@ -526,7 +526,7 @@ export function FoodSearchPlaceholder() { if (!confirmed) { return; } -function formatInteger(value: number): string { + deleteMutationInFlightRef.current = true; setIsClearingAll(true); setLogError(null); @@ -539,7 +539,7 @@ function formatInteger(value: number): string { return; } if (!response.ok) { - throw new Error("Delete-all hequest failed."); + throw new Error("Delete-all request failed."); } setSelectedLogId(null); await fetchLogs(); @@ -587,7 +587,7 @@ function formatInteger(value: number): string { ) : null} - const [isLoading, setIsLoading] = useState(false); + {!error && !isLoading && didSearch && !hasResults ? (
); } - className="h-full w-full object-contain"