fix(tradein): не запекать preview-флаг в прод-образ + noindex/баннер (#2205) #2223

Merged
lekss361 merged 1 commit from fix/tradein-no-public-preview into main 2026-07-02 20:21:59 +00:00
3 changed files with 64 additions and 1 deletions

View file

@ -232,10 +232,13 @@ jobs:
context: ./tradein-mvp/frontend
push: true
# basePath=/trade-in baked-in во время build (Next.js)
# NB (#2205): НЕ передаём NEXT_PUBLIC_ENABLE_PREVIEW — preview-роут
# (/ui-preview/estimate, статичная demo-фикстура) собирается ТОЛЬКО в
# dev/CI (a11y/lighthouse). В прод-образе флаг не задан → страница
# уходит в notFound (404), не индексируется и не краулится.
build-args: |
NEXT_PUBLIC_BASE_PATH=/trade-in
NEXT_PUBLIC_API_BASE_URL=/trade-in
NEXT_PUBLIC_ENABLE_PREVIEW=1
cache-from: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache
cache-to: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache,mode=max
tags: |

View file

@ -114,6 +114,25 @@ function PreviewContent() {
{/* Те же layout-классы, что у реальной страницы (page.tsx): .page .result-col
(flex-column gap, --container ширина). Без них карточки рендерились узко/«мобильно». */}
<main className="page">
{/* #2205: заметный баннер эта страница НЕ реальная оценка, а статичная
demo-фикстура для UI-тестов (axe/lighthouse). Контентный блок (не
перекрывает), не ломает audit-сценарии. */}
<div
role="note"
aria-label="Демо-данные: статичная фикстура для UI-тестов, не реальная оценка"
style={{
margin: "16px 0",
padding: "12px 16px",
borderRadius: 8,
border: "1px solid #f0b400",
background: "#fff7e0",
color: "#5c4500",
fontWeight: 600,
textAlign: "center",
}}
>
ДЕМО-ДАННЫЕ: статичная фикстура для UI-тестов, НЕ реальная оценка
</div>
{/* #835: страница-результат рендерит HeroSummary как h2 добавляем
визуально-скрытый h1 (page-has-heading-one). На реальной page.tsx h1
есть в page-title; здесь (preview, аудит) обёртки нет. */}

View file

@ -0,0 +1,41 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
/**
* #2205: серверный гейт + noindex для всей ветки /ui-preview/*.
*
* Preview-роут (статичная demo-фикстура «денежного экрана») нужен ТОЛЬКО в
* dev/CI для a11y (axe) / lighthouse. В прод-образе build-arg
* NEXT_PUBLIC_ENABLE_PREVIEW не задан (см. .forgejo/workflows/deploy-tradein.yml)
* ENABLED=false notFound(): страница отдаёт not-found UI БЕЗ фикстурных
* данных (никакой фейк-оценки, адреса, суммы см. #2205).
*
* Гейт продублирован здесь (server) и в page.tsx (client) defense-in-depth:
* даже если один слой снимут, второй закрывает контент. Server-layout запускает
* notFound() ДО рендера client-страницы.
*
* NB по HTTP-статусу: Next отдаёт этот not-found со статусом 200 (роут
* СОВПАДАЕТ с существующим сегментом рендер уже закоммитил 200 до того, как
* notFound() разрешится; чистый 404 Next отдаёт только для НЕсовпавших путей).
* Для #2205 это приемлемо: фикстурные данные не отдаются, а robots:noindex ниже
* убирает страницу из индексации. Жёсткий 404 потребовал бы middleware /
* next.config-rewrite (вне правок этого фикса).
*
* Metadata robots:noindex belt-and-suspenders для non-prod окружений, где
* флаг ВКЛЮЧЁН (staging / случайно собранный образ): даже отрендеренную
* страницу поисковики не индексируют.
*/
const ENABLED = process.env.NEXT_PUBLIC_ENABLE_PREVIEW === "1";
export const metadata: Metadata = {
robots: { index: false, follow: false },
};
export default function UiPreviewLayout({
children,
}: {
children: React.ReactNode;
}) {
if (!ENABLED) notFound();
return <>{children}</>;
}