fix(tradein): RouteGuard prod 401 → session-expired screen, stop re-subscribe storm (#800)

TanStack Query errored queries (staleTime: Infinity) are always stale — each
new observer subscription triggers a refetch regardless of retry:false.
RouteGuard mounting children on 401 caused continuous re-subscribe churn
(616+ requests in 15s confirmed by design-loop repro 2026-05-31).

Fix: on 401 in production, render NoAccessScreen variant="session" instead
of mounting the app subtree. Dev without Caddy keeps the passthrough
(process.env.NODE_ENV !== "production") so local next dev still works.

Also adds NoAccessScreen "session" variant (title: Сессия истекла,
subtitle: Обновите страницу, чтобы войти снова).
This commit is contained in:
bot-frontend 2026-05-31 16:07:21 +03:00
parent 2890199d07
commit 81cd1f61d3
2 changed files with 13 additions and 6 deletions

View file

@ -10,15 +10,17 @@
*/
interface NoAccessScreenProps {
variant: "user" | "path";
variant: "user" | "path" | "session";
path?: string;
}
export function NoAccessScreen({ variant, path }: NoAccessScreenProps) {
const subtitle =
variant === "user"
? "Учётная запись не привязана к роли. Обратитесь к администратору GenDesign — kopylov."
: "У вашей роли нет доступа к этому разделу. Вернитесь на главную или обратитесь к администратору.";
variant === "session"
? "Сессия истекла или вы не авторизованы. Обновите страницу, чтобы войти снова."
: variant === "user"
? "Учётная запись не привязана к роли. Обратитесь к администратору GenDesign — kopylov."
: "У вашей роли нет доступа к этому разделу. Вернитесь на главную или обратитесь к администратору.";
return (
<main
@ -54,7 +56,7 @@ export function NoAccessScreen({ variant, path }: NoAccessScreenProps) {
lineHeight: 1.25,
}}
>
Доступа нет
{variant === "session" ? "Сессия истекла" : "Доступа нет"}
</h1>
<p
style={{

View file

@ -45,7 +45,12 @@ export function RouteGuard({ children }: RouteGuardProps) {
if (isLoading) return null;
if (error instanceof HTTPError && error.status === 401) {
return <>{children}</>;
// Dev without Caddy: 401 is normal, mount the app so local dev works.
// Prod: mounting children on 401 causes TanStack Query re-subscribe storm
// (each new observer on errored query triggers a refetch). Show session screen
// instead — prevents the subtree from mounting, kills the loop.
if (process.env.NODE_ENV !== "production") return <>{children}</>;
return <NoAccessScreen variant="session" />;
}
if (error instanceof HTTPError && error.status === 403) {