feat(mera): публичный лэндинг «МЕРА» — контент и вёрстка #2615
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2615
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/mera-landing"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Первая публичная страница «Меры». Только фронт —
Caddyfile, DNS и бэкенд не тронуты: периметр наmeraocenka.ruидёт отдельным PR, чтобы горячийCaddyfileне менялся параллельно с эпиком «единый вход» (#2597 → #2602 → #2608).Заменяет заглушку из
feat/mera-b2c-perimeter(48 строк «сервис скоро откроется») на страницу целиком: первый экран, как это работает, что человек получает, откуда данные, вопросы-ответы, подвал, страница обработки ПДн.Починен живой баг, из-за которого лэндинг всё равно уводил бы людей на форму входа
RouteGuardрегистрировалuseEffectсrouter.push('/login?next=…')до early-return для публичных путей. Хуки выполняются всегда — поэтому на проде аноним на/mera-publicполучал фоновыйGET /api/v1/me→ 401 → редирект на логин, и «безусловный bypass» ниже по файлу до этого просто не доходил. То есть заглушка в текущем виде была нерабочей, и это выяснилось бы уже после открытия домена.Guard разделён:
RouteGuardтеперь смотрит толькоpathname, а весь закрытый контур (useMe, RBAC, экраны отказа) вынесен вGuardedRouteи подключён черезnext/dynamic. Это точка разрыва графа импортов, а не только логическая развилка — иначе анонимный посетитель продолжал бы скачивать B2B-код.Проверено на живой странице: запросов к
/api/**— ноль.Обещания приведены в соответствие с тем, что продукт делает
Отдельная линза ревью сверяла каждое утверждение с кодом. Нашла 1 critical и 4 high — все про обещания, которых продукт не выполняет:
GET /api/v1/trade-in/estimate/{id}/pdfowner-scoped, анониму 401 by designenabled=false), данных единицы. Теперь честно: полное покрытие — Екатеринбург, по области меньшеestimator.py, IMV/Yandex blend)Тексты и правовые формулировки собраны в
content.tsодним местом, рядом со ссылками на код, который их подтверждает — чтобы обещание и реальность разъезжались заметно, а не молча. Финальная редакция privacy помечена как задача юриста, а не инженерное решение.Форма адреса — честная заглушка, и это вынужденно
Живого автокомплита сейчас быть не может:
_PUBLIC_PATHS«Меры» (rbac.py) открывает анониму толькоhealth/docs/login/logoutи анонимный чат./api/v1/geocode/suggestи/api/v1/trade-in/estimateотдают анониму 401. Открывать их до анти-абуза (этап 2 плана B2C) план называет категорическим запретом — без квот и rate-limit это пайплайн на десятки секунд с пятью внешними сервисами, доступный кому угодно.Поэтому форма честно сообщает, что произойдёт, и не изображает работу, которой нет. Поведение переключается флагом
PUBLIC_ESTIMATE_ENABLED; рядом с флагом — гейт из трёх условий (текст privacy, согласие до записи, наличие пути удаления), без которых его включать нельзя.Проверено живьём, не по отчёту агентов
h1, иерархияH1→H2→H3без пропусков, landmark-разметка (header/main/section×5/footer);/api/**со страницы;tsc --noEmitчист;NB ревьюеру
.claude/rules/ui-*.mdпо frontmatterpaths:матчатfrontend/**— корневой фронт Site Finder, а неtradein-mvp/frontend. Формально этот rulebook сюда не распространяется; страница живёт в дизайн-системеv2/tokens.ts. Tailwind в этом фронте отсутствует вовсе (вёрстка — CSS-модуль + inline-стили), поэтому совет «статический стиль → Tailwind utility» неприменим.Test plan
tsc --noEmit— чистоPDFв тексте страницы не встречаетсяДальше
Периметр на
meraocenka.ru: allowlist (страница,/_next/static,/_next/image,/health), всё непереч��сленное — 404, безusers.caddy.snippet. DNS теперь готов полностью:meraocenka.ru,merahome.ru,meraotsenka.ruи все триwwwуказывают на 46.173.16.127 (проверено авторитативно уns1.beget.ru).merahome.ruиmeraotsenka.ru→ 301 на каноническийmeraocenka.ru.Отдельно учесть при периметре:
next.config.tsредиректит/→/v2, поэтому корень публичного домена должен вести на лэндинг, а не выкидывать посетителя в B2B-приложение.Только фронт. Caddyfile, DNS и бэкенд не тронуты: периметр и домен meraocenka.ru делаются отдельным PR, чтобы горячий Caddyfile не менялся параллельно с эпиком «единый вход». Заменяет заглушку из feat/mera-b2c-perimeter (48 строк «скоро откроется») на полноценную страницу: первый экран, как это работает, что человек получает, откуда данные, вопросы-ответы, подвал и страница обработки ПДн. ## Починен живой баг, из-за которого лэндинг уводил бы людей на форму входа RouteGuard регистрировал useEffect с router.push('/login') ДО early-return для публичных путей. Хуки выполняются всегда, поэтому на проде аноним на /mera-public получал фоновый GET /api/v1/me → 401 → редирект на логин, и «безусловный bypass» до этого просто не доходил. Guard разделён: RouteGuard теперь только смотрит pathname, а весь закрытый контур (useMe, RBAC, экраны отказа) вынесен в GuardedRoute и подключён через next/dynamic — это точка разрыва графа импортов, а не только логическая развилка. Проверено на живой странице: запросов к API — НОЛЬ. ## Обещания приведены в соответствие с продуктом Ревью по честности нашло 1 critical и 4 high — всё это обещания, которых продукт не выполняет. Убрано или переписано: - «Отчёт в PDF» — ручка owner-scoped, анониму отдаёт 401 by design; - «список объектов, на которых построен расчёт» — план прямо запрещает показывать анониму сырые объявления конкурентов; - шесть городов подавались как равнозначные, хотя сбор вне Екатеринбурга выключен (миграция 179, enabled=false) и данных единицы. Теперь честно: полное покрытие — Екатеринбург, по области данных меньше; - «в расчёте два типа данных» умалчивало третий — чужие оценочные модели, которые реально двигают итоговую цифру (estimator.py, IMV/Yandex blend); - страница ПДн обещала удаление данных, механизма которого нет. Тексты и правовые формулировки вынесены в content.ts одним местом, рядом с ссылками на код, который их подтверждает. Финальная редакция privacy — за юристом, это помечено в файле. ## Форма адреса — честная заглушка, и это вынужденно Живого автокомплита быть не может: _PUBLIC_PATHS «Меры» (rbac.py) открывает анониму только health/docs/login/logout и анонимный чат. /geocode/suggest и /trade-in/estimate отдают анониму 401. Открывать их до анти-абуза (этап 2 плана B2C) прямо запрещено планом. Форма честно говорит, что произойдёт, и не изображает работу, которой нет. Переключается флагом PUBLIC_ESTIMATE_ENABLED, рядом с ним — гейт из трёх условий. ## Проверено живьём, не по отчёту - 360px и 390px: горизонтального переполнения нет (единственный элемент за экраном — skip-link, так и задумано); - один h1, иерархия H1→H2→H3 без пропусков, landmark-разметка; - внешних ресурсов ноль — ни CDN, ни шрифтов, ни картинок с чужих доменов; - ноль запросов к /api/** со страницы; - tsc --noEmit чист. NB для ревьюера: .claude/rules/ui-*.md по frontmatter paths: матчат frontend/**, то есть корневой фронт Site Finder, а не tradein-mvp/frontend. Здесь применяется дизайн-система v2/tokens.ts. Tailwind в этом фронте нет.