# Phase 2F — SEO + JSON-LD for Online Board

> **Parent plan:** `2026-04-14-phase-2-online-board-master.md` (sub-plan 2F)
> **Depends on:** 2E (route pages), 1F-seo (`SeoHead`, `buildHreflangSet`, `JsonLdRenderer`), 1C (i18n)

## Goal

Wire SEO metadata (title, description, canonical, hreflang, OG, Twitter Card) and JSON-LD structured data (`Flight`, `ItemList`) into all 6 Online Board route pages. SEO builders are pure functions; JSON-LD builders produce `schema-dts` typed objects.

## Deliverables

1. `src/features/online-board/seo.ts` — 6 builder functions returning `SeoHeadProps`
2. `src/features/online-board/json-ld.ts` — 2 JSON-LD builder functions
3. Updated route pages wiring `<SeoHead>` and `<JsonLdRenderer>`
4. Populated EN locale SEO keys (RU already has values)

## Tasks

### T1 — Populate EN locale SEO keys

The EN locale file has empty SEO.BOARD keys. Add English translations matching the Russian pattern.

- File: `src/i18n/locales/en/common.json`
- Keys: `SEO.BOARD.MAIN`, `SEO.BOARD.FLIGHT-SEARCH`, `SEO.BOARD.DEPARTURE-SEARCH`, `SEO.BOARD.ARRIVAL-SEARCH`, `SEO.BOARD.ROUTE-SEARCH`, `SEO.BOARD.FLIGHT-DETAILS`

### T2 — TDD: SEO builder functions (`seo.ts`)

Write tests first in `src/features/online-board/seo.test.ts`, then implement in `src/features/online-board/seo.ts`.

**Functions:**
- `buildOnlineBoardStartSeo(locale, canonicalOrigin)` — start page SEO
- `buildFlightSearchSeo(params, locale, canonicalOrigin, cityNames?)` — flight number search
- `buildDepartureSearchSeo(params, locale, canonicalOrigin, cityNames?)` — departure search
- `buildArrivalSearchSeo(params, locale, canonicalOrigin, cityNames?)` — arrival search
- `buildRouteSearchSeo(params, locale, canonicalOrigin, cityNames?)` — route search
- `buildFlightDetailsSeo(flight, locale, canonicalOrigin)` — flight details page

Each returns `SeoHeadProps` with title, description, canonical, hreflang, og, twitter.

**Test strategy:** Unit tests with mocked i18n `t()` function verifying:
- Correct translation keys passed to `t()`
- Correct interpolation variables
- Canonical URL structure
- Hreflang set included
- OG tags populated
- Twitter card set

### T3 — TDD: JSON-LD builder functions (`json-ld.ts`)

Write tests first in `src/features/online-board/json-ld.test.ts`, then implement in `src/features/online-board/json-ld.ts`.

**Functions:**
- `buildFlightJsonLd(flight: ISimpleFlight)` — returns `schema-dts` `Flight` thing
- `buildFlightListJsonLd(flights: ISimpleFlight[], searchDescription: string)` — returns `ItemList`

**Test strategy:** Unit tests verifying:
- Correct `@type` set
- Flight number, departure/arrival airports mapped
- Departure/arrival times mapped
- `ItemList` wraps flights as `ListItem` elements
- Type-checks against `schema-dts` types

### T4 — Wire SEO into route pages

Update the 6 route page files to import and use `<SeoHead>` with appropriate builder + `<JsonLdRenderer>`. No TDD for this step (visual verification).

- `src/routes/[lang]/onlineboard/page.tsx` — start page
- `src/routes/[lang]/onlineboard/flight/[params]/page.tsx` — flight search
- `src/routes/[lang]/onlineboard/departure/[params]/page.tsx` — departure search
- `src/routes/[lang]/onlineboard/arrival/[params]/page.tsx` — arrival search
- `src/routes/[lang]/onlineboard/route/[params]/page.tsx` — route search
- `src/routes/[lang]/onlineboard/[params]/page.tsx` — flight details

### T5 — Export from barrel

Add SEO + JSON-LD exports to `src/features/online-board/index.ts`.

### T6 — Verify

Run `pnpm typecheck && pnpm lint && pnpm test && pnpm build:standalone`.

## Commit plan

1. **Commit 1:** EN locale SEO keys + SEO builder tests + implementation (`seo.ts`)
2. **Commit 2:** JSON-LD builder tests + implementation (`json-ld.ts`)
3. **Commit 3:** Wire SEO into route pages + barrel exports + verify
