diff --git a/README.md b/README.md index e2ffbe7..17471e6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ RF4DB/RF4-STAT/RF4MAP/RF4 Posts сначала принимаются в изо На сайте у каждой записи отображается источник, а у агрегированной активности — все вошедшие в расчёт источники. Неполные community-наблюдения публикуются сразу в отдельной ленте «Полевые сигналы» с предупреждением и перечнем отсутствующих полей; до подтверждения полноты они не влияют на индекс клёва. +Базовый SEO-контур готов для `rf4spotter.ru`: страницы имеют уникальные метаданные, canonical, Open Graph/Twitter Card и JSON-LD; доступны динамические `/robots.txt` и `/sitemap.xml`, административные и ошибочные страницы закрыты от индексации, добавлена собственная страница 404. Фирменное OG-изображение и индексируемые страницы рыб/водоёмов остаются следующими пакетами в roadmap. + Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md). Результаты проверки интерфейса и пять приоритетных UX-пакетов описаны в [`docs/UI_UX_AUDIT.md`](docs/UI_UX_AUDIT.md). Production-контур для домена `rf4spotter.ru`, TLS, секреты, backup/restore и команды первого запуска описаны в [`deploy/README.md`](deploy/README.md). Он использует отдельный `compose.production.yaml`; локальный `compose.yaml` остаётся средой разработки. Production seed добавляет только справочники — демонстрационные уловы отключены. Изолированные проверки `deploy/test-production-bootstrap.sh` и `deploy/test-backup-restore.sh` подтверждают старт с пустых volumes и восстановление данных. diff --git a/apps/web/astro.config.mjs b/apps/web/astro.config.mjs index 495c34c..03a0f1d 100644 --- a/apps/web/astro.config.mjs +++ b/apps/web/astro.config.mjs @@ -2,6 +2,7 @@ import { defineConfig } from "astro/config"; import node from "@astrojs/node"; export default defineConfig({ + site: process.env.PUBLIC_SITE_URL || "https://rf4spotter.ru", output: "server", adapter: node({ mode: "standalone" }), server: { host: true, port: 4321 }, diff --git a/apps/web/src/layouts/Layout.astro b/apps/web/src/layouts/Layout.astro index 0e6de31..f033751 100644 --- a/apps/web/src/layouts/Layout.astro +++ b/apps/web/src/layouts/Layout.astro @@ -1,12 +1,47 @@ --- import "../styles/global.css"; import FishingIcon from "../components/FishingIcon.astro"; -const { title = "RF4 Spotter" } = Astro.props; +const { + title = "RF4 Spotter — свежие точки клёва Russian Fishing 4", + description = "Свежие точки, уловы и честная оценка активности в Russian Fishing 4 с обязательным указанием источников.", + noindex = false, + image = "/lake-dawn.png", + structuredData = null, +} = Astro.props; const path = Astro.url.pathname; +const siteUrl = import.meta.env.PUBLIC_SITE_URL || "https://rf4spotter.ru"; +const canonical = new URL(path, siteUrl).toString(); +const socialImage = new URL(image, siteUrl).toString(); +const preventIndexing = noindex || path.startsWith("/admin/"); +const websiteJsonLd = { "@type": "WebSite", name: "RF4 Spotter", url: siteUrl, inLanguage: "ru" }; +const jsonLd = JSON.stringify({ + "@context": "https://schema.org", + "@graph": structuredData ? [websiteJsonLd, structuredData] : [websiteJsonLd], +}).replaceAll("<", "\\u003c"); --- - {title} + + + + + + + + + + + + + + + + + + +