diff --git a/.forgejo/workflows/deploy-tradein.yml b/.forgejo/workflows/deploy-tradein.yml index 87f8c111..b58f73ad 100644 --- a/.forgejo/workflows/deploy-tradein.yml +++ b/.forgejo/workflows/deploy-tradein.yml @@ -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: | diff --git a/tradein-mvp/frontend/src/app/ui-preview/estimate/page.tsx b/tradein-mvp/frontend/src/app/ui-preview/estimate/page.tsx index 5651cacd..106b02b1 100644 --- a/tradein-mvp/frontend/src/app/ui-preview/estimate/page.tsx +++ b/tradein-mvp/frontend/src/app/ui-preview/estimate/page.tsx @@ -114,6 +114,25 @@ function PreviewContent() { {/* Те же layout-классы, что у реальной страницы (page.tsx): .page → .result-col (flex-column gap, --container ширина). Без них карточки рендерились узко/«мобильно». */}
+ {/* #2205: заметный баннер — эта страница НЕ реальная оценка, а статичная + demo-фикстура для UI-тестов (axe/lighthouse). Контентный блок (не + перекрывает), не ломает audit-сценарии. */} +
+ ДЕМО-ДАННЫЕ: статичная фикстура для UI-тестов, НЕ реальная оценка +
{/* #835: страница-результат рендерит HeroSummary как h2 — добавляем визуально-скрытый h1 (page-has-heading-one). На реальной page.tsx h1 есть в page-title; здесь (preview, аудит) обёртки нет. */} diff --git a/tradein-mvp/frontend/src/app/ui-preview/layout.tsx b/tradein-mvp/frontend/src/app/ui-preview/layout.tsx new file mode 100644 index 00000000..ba0c865e --- /dev/null +++ b/tradein-mvp/frontend/src/app/ui-preview/layout.tsx @@ -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}; +}