fix(tradein): не запекать preview-флаг в прод-образ + noindex/баннер (#2205)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m0s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m0s
build-frontend больше не передаёт NEXT_PUBLIC_ENABLE_PREVIEW=1 → фейк-оценка /ui-preview/estimate уходит в notFound в проде (фикстурные данные не отдаются). Server-layout: robots noindex/nofollow + серверный notFound-гейт (defense-in-depth поверх client-гейта). Видимый ДЕМО-баннер для non-prod. HTTP-статус остаётся 200 (Next коммитит статус до notFound на матчнутом client-сегменте) — контент гейтится, индексация снята; жёсткий 404 = middleware, вне скоупа. Refs #2205
This commit is contained in:
parent
e6000cb029
commit
ae825dc19d
3 changed files with 64 additions and 1 deletions
|
|
@ -232,10 +232,13 @@ jobs:
|
||||||
context: ./tradein-mvp/frontend
|
context: ./tradein-mvp/frontend
|
||||||
push: true
|
push: true
|
||||||
# basePath=/trade-in baked-in во время build (Next.js)
|
# 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: |
|
build-args: |
|
||||||
NEXT_PUBLIC_BASE_PATH=/trade-in
|
NEXT_PUBLIC_BASE_PATH=/trade-in
|
||||||
NEXT_PUBLIC_API_BASE_URL=/trade-in
|
NEXT_PUBLIC_API_BASE_URL=/trade-in
|
||||||
NEXT_PUBLIC_ENABLE_PREVIEW=1
|
|
||||||
cache-from: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache
|
cache-from: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache
|
||||||
cache-to: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache,mode=max
|
cache-to: type=registry,ref=${{ env.IMAGE_FRONTEND }}:buildcache,mode=max
|
||||||
tags: |
|
tags: |
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,25 @@ function PreviewContent() {
|
||||||
{/* Те же layout-классы, что у реальной страницы (page.tsx): .page → .result-col
|
{/* Те же layout-классы, что у реальной страницы (page.tsx): .page → .result-col
|
||||||
(flex-column gap, --container ширина). Без них карточки рендерились узко/«мобильно». */}
|
(flex-column gap, --container ширина). Без них карточки рендерились узко/«мобильно». */}
|
||||||
<main className="page">
|
<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 — добавляем
|
{/* #835: страница-результат рендерит HeroSummary как h2 — добавляем
|
||||||
визуально-скрытый h1 (page-has-heading-one). На реальной page.tsx h1
|
визуально-скрытый h1 (page-has-heading-one). На реальной page.tsx h1
|
||||||
есть в page-title; здесь (preview, аудит) обёртки нет. */}
|
есть в page-title; здесь (preview, аудит) обёртки нет. */}
|
||||||
|
|
|
||||||
41
tradein-mvp/frontend/src/app/ui-preview/layout.tsx
Normal file
41
tradein-mvp/frontend/src/app/ui-preview/layout.tsx
Normal 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}</>;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue