Skip to content

Date structurate: Article, FAQPage și traseu pe fiecare pagină

Vitalie requested to merge 19_structured-data into main

Închide #19 (closed).

Până acum HTML-ul randat descria doar produsul și colecția. Blogul, pagina de întrebări frecvente și toate paginile statice plecau spre motoarele de căutare fără niciun bloc de date structurate — 27 din cele 42 de adrese din sitemap, în câte trei limbi.

Ce se schimbă

Traseu pe fiecare pagină statică. staticPage își construiește singur BreadcrumbList din rootCrumb plus pagina curentă; parametrul extra dispare. Două trepte și numai două: nici /therapy, nici /legal, nici /support nu are pagină proprie în router, deci nu există treaptă intermediară de numit. Pagina principală păstrează Organization în loc de un traseu care ar arăta spre ea însăși, iar paginile ținute în afara căutării (/account, /comanda, /order-confirmation) nu mai emit nimic.

Șapte pagini nu aveau nume scurt în fișierele de traducere, deci treapta ar fi purtat titlul întreg — „Termeni și condiții de comandă și livrare", 41 de caractere. Au primit unul, în cuvintele cu care meniul și subsolul le numesc deja. seoLength.test.ts cere acum un nume pentru fiecare pagină statică, nu doar pentru cele opt care apăreau într-un traseu înainte.

Article pe cele 72 de articole. Titlul întreg (nu cel scurtat pentru lățimea unui rezultat), rezumatul, fotografia de pe pagină și magazinul ca editor. Fără author și fără dateModified: corpusul nu înregistrează nici autor, nici o modificare editorială — updatedAt înregistrează un import — iar o valoare inventată e o afirmație făcută unui motor de căutare pe care datele nu o susțin. Traseul articolului primește și treapta lipsă spre pagina principală.

datePublished se citește din data pe care o tipărește pagina, nu din instantul stocat: dateISO a fost normalizat la UTC la import și pentru 41 din 72 de articole cade cu o zi după data de sub titlu (toate cele 72 de valori dateDisplay sunt exact dateISO afișat în America/Los_Angeles — fusul pe care importul l-a pierdut).

FAQPage pe pagina de întrebări frecvente și pe cele 42 de produse cu acordeon. Răspunsurile produsului vin din baza de date, în limba cititorului. Răspunsurile paginii de asistență ajung la randare prin fișierul de șiruri pe care build-ul frontend îl emite deja, dintr-un fișier nou pe care aplicația nu îl încarcă niciodată — deci nu îngreunează pachetul de traduceri al niciunui vizitator. Un test randează pagina și cere ca textul stocat să fie exact textul afișat: marcaj care răspunde altfel decât pagina de sub el e singurul lucru pe care ghidul Google îl interzice explicit.

Curățenie adusă de schimbare: adresa logoului era scrisă în două locuri (structured-data.ts și email-template.ts); acum stă o singură dată, în lib/company.ts.

Verificare

  • backend: npm run build curat, npx vitest run — 600 de teste în 39 de fișiere, trecute (29 dintre ele noi, în tests/structured-data.test.ts).
  • frontend: npx oxlint — un singur avertisment preexistent în src/App.tsx; tsc --noEmit -p tsconfig.app.json și -p tsconfig.test.json curate; npx vitest run — 433 de teste în 33 de fișiere, trecute; npm run build curat.
  • Randare reală: frontend construit, servit local, backend pornit peste dev.db. 93 de pagini randate (15 pagini statice + 6 articole + 5 produse + 5 colecții, în trei limbi): fiecare bloc trece prin JSON.parse, 90 de trasee cu poziții 1..n contigue și adrese absolute cu prefixul de limbă corect, 18 blocuri Article, 18 blocuri FAQPage, nicio pagină cu două blocuri de același tip. Zero probleme.
  • Baza de dezvoltare a rămas la valorile de referință: 61 de produse, 11 colecții, 72 de articole, o comandă.

Criteriul de acceptare, punctual

  • /blogs/hyperhub/<slug> × 3 limbi: Article + BreadcrumbList, ambele parsabile; datePublished 2026-02-01 acolo unde pagina scrie „February 1, 2026", deși instantul stocat e 2026-02-02T07:58:21Z.
  • /about, /therapy/recovery, /support/faq, /legal/terms, /recovery-rooms, /gift-cards × 3 limbi: câte un BreadcrumbList, poziții 1 și 2, adrese cu prefixul corect.

Rămâne în afara acestei lucrări

/gift-cards afișează un acordeon real cu trei întrebări, ale cărui texte stau în tabelul de conținut editabil din panou, nu în fișierele de traducere. Nu primește FAQPage aici; primește issue propriu.

Merge request reports