feat(landing): Russian default + SEO head, icons and OG card #157

Merged
developer merged 1 commits from feature/landing-seo into development 2026-07-01 23:29:28 +00:00
Owner

The landing is invisible to search engines today: an empty client-rendered shell with lang="en", a bare , no metadata at all, and the locale auto-detected from the browser — so crawlers (Googlebot renders with en-US) index English content on a Russian-audience site. /favicon.ico falls through to the caddy catch-all and returns the landing HTML with 200.

Russian by default. The landing now always boots in Russian: landing.ts sets the locale before mount (first paint is Russian), Landing.svelte drops the navigator.language guess (prefs.locale ?? 'ru'), and document.documentElement.lang follows the 🌐 switch. A saved language choice still wins. Deterministic for every crawler; owner decision from the interview.

Static SEO head in landing.html (Russian, absolute URLs pinned to https://erudit-game.ru/): title + meta description, canonical (the test contour now canonicalises to production instead of being indexed separately), the Open Graph card Telegram/VK previews use, twitter:card, JSON-LD (WebApplication/GameApplication), theme-color and the favicon set. The SPA shell (index.html, /app/+/telegram/+/vk/) turns noindex, gets the same icons and the tab title «Эрудит (Скрэббл)». robots.txt is allow-all on purpose — a Disallow would hide the noindex from crawlers.

Icons + OG card are generated by the new assets/icons/ pipeline (same «Э»-tile design as the VK loader, glyph outlines from LiberationSans, PNGs screenshotted with the ui package's Playwright — no new dependencies): favicon.svg, favicon.ico (hand-assembled PNG-in-ICO), apple-touch-icon.png, og-image.png 1200×630, committed to ui/public/. Served by the existing landing-container try_files — no caddy changes.

Tests: the landing e2e now asserts the Russian default under the en-US test browser, the head tags, and the lang switch; full local suite green (svelte-check 0/0, 371 unit, 160 e2e chromium+webkit, bundle gates ok — public/ statics don't count against them).

Docs: FUNCTIONAL (+_ru mirror) and ARCHITECTURE §13.

Caveats: og:image points at the production URL, so link-preview images 404 until the next prod release (text части карточки работают сразу); Яндекс.Вебмастер / Search Console verification is a separate owner-side step.

The landing is invisible to search engines today: an empty client-rendered shell with lang="en", a bare <title>Scrabble</title>, no metadata at all, and the locale auto-detected from the browser — so crawlers (Googlebot renders with en-US) index English content on a Russian-audience site. /favicon.ico falls through to the caddy catch-all and returns the landing HTML with 200. **Russian by default.** The landing now always boots in Russian: `landing.ts` sets the locale before mount (first paint is Russian), `Landing.svelte` drops the `navigator.language` guess (`prefs.locale ?? 'ru'`), and `document.documentElement.lang` follows the 🌐 switch. A saved language choice still wins. Deterministic for every crawler; owner decision from the interview. **Static SEO head** in `landing.html` (Russian, absolute URLs pinned to `https://erudit-game.ru/`): title + meta description, canonical (the test contour now canonicalises to production instead of being indexed separately), the Open Graph card Telegram/VK previews use, `twitter:card`, JSON-LD (`WebApplication`/`GameApplication`), theme-color and the favicon set. The SPA shell (`index.html`, `/app/`+`/telegram/`+`/vk/`) turns `noindex`, gets the same icons and the tab title «Эрудит (Скрэббл)». `robots.txt` is allow-all on purpose — a Disallow would hide the noindex from crawlers. **Icons + OG card** are generated by the new `assets/icons/` pipeline (same «Э»-tile design as the VK loader, glyph outlines from LiberationSans, PNGs screenshotted with the ui package's Playwright — no new dependencies): `favicon.svg`, `favicon.ico` (hand-assembled PNG-in-ICO), `apple-touch-icon.png`, `og-image.png` 1200×630, committed to `ui/public/`. Served by the existing landing-container `try_files` — no caddy changes. Tests: the landing e2e now asserts the Russian default under the en-US test browser, the head tags, and the lang switch; full local suite green (svelte-check 0/0, 371 unit, 160 e2e chromium+webkit, bundle gates ok — public/ statics don't count against them). Docs: FUNCTIONAL (+_ru mirror) and ARCHITECTURE §13. Caveats: og:image points at the production URL, so link-preview images 404 until the next prod release (text части карточки работают сразу); Яндекс.Вебмастер / Search Console verification is a separate owner-side step.
developer added 1 commit 2026-07-01 23:25:39 +00:00
feat(landing): Russian default + SEO head, icons and OG card
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 57s
CI / conformance (pull_request) Successful in 8s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m20s
1ed624eaf1
The landing now always opens in Russian (saved 🌐 choice still wins) —
browser-language detection made the indexed content nondeterministic
(Googlebot renders with en-US). landing.html gains the static Russian
SEO head: title/description, canonical pinned to the production origin,
Open Graph card (Telegram/VK link previews), twitter:card, JSON-LD,
theme-color and the favicon set; the SPA shell turns noindex and its
tab title becomes «Эрудит (Скрэббл)». New assets/icons generator
(same tile design as the VK loader) produces favicon.svg/ico,
apple-touch-icon.png and og-image.png into ui/public/, plus robots.txt.
owner approved these changes 2026-07-01 23:26:11 +00:00
developer merged commit 2ab01ed8f7 into development 2026-07-01 23:29:28 +00:00
developer deleted branch feature/landing-seo 2026-07-01 23:29:29 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#157