Skip to content

content: homepage answers the live 'apa calda' intent (status + FAQ) - #19

Open
tiXor-code wants to merge 3 commits into
mainfrom
content/home-live-status-faq
Open

tiXor-code wants to merge 3 commits into
mainfrom
content/home-live-status-faq

Conversation

@tiXor-code

Copy link
Copy Markdown
Owner

TLDR: GSC shows the generic query 'apa calda' landing on the homepage at position 8.2 with 1,412 impressions, and the live SERP is led by CMTEB's own live-status pages, so the intent is 'is there hot water right now' -- which the homepage never answered. This adds a citywide answer-first live-status block with a per-sector table, tunes the homepage title/description to that intent, and adds a five-question citywide FAQ with FAQPage JSON-LD. All numbers come from the nightly termo-data bundle.

Why

SERP for 'apa calda' (checked 2026-09-14): positions 1-4 are all CMTEB (live status page, system map, Facebook, homepage), position 5 is Digi24 news about the Berceni avarie. We cannot beat the supplier on 'official now', but we win on aggregation by sector, history and street-level lookup. The homepage was 100% historical with zero live content; sector pages already answer per-sector, the homepage now answers citywide and routes people to them.

What changed (app/page.tsx)

  • New section 'Sunt avarii de apa calda in Bucuresti acum?' directly under the hero: one answer-first sentence (PTs currently off, how many from avarii, worst sector -- 'cele mai multe in Sectorul X' only when a single sector holds the maximum), then a compact per-sector table (PTs off now / of which avarii) linking all six /sector/ pages, then the honest nightly-freshness caveat with a nofollow cmteb.ro pointer, same as the sector template. Counts are distinct PT slugs from the same getSectorLive rollups the sector pages already compute; the numeric table is data-nosnippet like the homepage's other stat blocks, the sentence stays snippetable on purpose.
  • Five-question citywide FAQ ('De ce nu am apa calda?', 'Cand revine apa calda dupa o avarie?', 'Cine opreste si reporneste apa calda in Bucuresti?', 'Cat de des ramane Bucurestiul fara apa calda?', 'Apa e doar calduta sau abia curge -- e tot oprire?') with FAQPage JSON-LD through the escaping faqJsonLd/JsonLd helpers. Answers are plain strings matching the visible text exactly and use only bundle aggregates (median PT days, share hit, episode count, oprire vs deficienta split) -- no scraped names enter the new sections.
  • Title: 'Apa calda Bucuresti: avarii azi si istoric | Fara Apa Calda' (59 rendered chars; the layout's title.template applies only to child segments, so the root page carries the brand suffix itself). Description now leads with live avarii + daily update, keeps the street-history half (150 chars).

Also in this branch

Verification

  • npm test: 137/137 pass (was 136/137 on main before the OngoingBand fix).
  • npm run build: zero errors, all pages prerendered against bundle data_through 2026-09-14.
  • Rendered .next/server/app/index.html inspected: title 59 chars, description 150 chars, answer-first sentence renders with real data (59 PTs off, 45 from avarii, worst Sector 4 -- consistent with the ongoing Magistrala Berceni avarie), all six sector links present, FAQPage JSON-LD carries exactly the five visible questions.

Generated by SEO Sentinel (order 71). PR only, human review required before merge.

🤖 Generated with Claude Code

tiXor-code and others added 2 commits September 14, 2026 10:44
GSC: 'apa calda' at position 8.2 with 1,412 impressions lands on the
homepage, and the live SERP is led by CMTEB's status pages - the intent
is 'is there hot water right now', which the homepage never answered.

- Citywide answer-first block: one sentence with PTs currently off,
  how many from avarii and the worst sector, computed from the same
  getSectorLive rollups the sector pages use (distinct PT slugs).
- Per-sector live table (PTs off now / of which avarii) linking all six
  /sector/ pages; numeric table is data-nosnippet like the other blocks.
- Five-question citywide FAQ + FAQPage JSON-LD via the escaping
  faqJsonLd/JsonLd helpers; answers use only bundle aggregates.
- Title carries the live intent ('avarii azi si istoric', 59 rendered
  chars incl. brand - the layout template does not apply to the root
  page); description leads with avarii + daily update.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR #14 merged after #17 added the no-direct-next/link rule, so main's
vitest suite fails on link-prefetch.test.ts. One-line swap to the
wrapper that defaults prefetch={false}.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
termo-site Ready Ready Preview Oct 12, 2026 7:36am UTC

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full diff. Verified:

  • cityStatusSentence (app/page.tsx:60-77) and the per-sector live table correctly reuse getSectorLive (same call pattern/year as app/sector/[id]/page.tsx:118), counting distinct PT slugs via Set so a PT with multiple ongoing episodes isn't double-counted; ptsAvarie is a proper subset of pts. Singular/plural and "de" agreement (fmtZile/deFor) handled correctly, including the total === 1 and tied-max-sector edge cases.
  • FAQ answers are built from existing, already-verified bundle aggregates (cityHeadlineDays, cityDeficientaDays, summary, totalEpisodes) with no scraped names entering the new sections, and are rendered as plain strings that match the JSON-LD faqJsonLd/JsonLd output verbatim — consistent with the CLAUDE.md JSON-LD escaping rule.
  • Title (59 chars) and description (150 chars) fit the site's established rendered-length windows.
  • The components/OngoingBand.tsx fix is a correct minimal swap to the prefetch-off @/components/Link wrapper, directly fixing link-prefetch.test.ts.

No correctness, security, or quality issues found. Approving.

Conflict resolution for app/page.tsx: main's Oct 5 title and indexable
intro section win (they postdate this branch); the branch's citywide
live-status section, five-question FAQ with FAQPage JSON-LD, and
live-first meta description are re-applied on top.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tiXor-code

Copy link
Copy Markdown
Owner Author

TLDR: branch refreshed on 2026-10-12 — merged main (was 44 commits behind, conflicted), build and all 137 tests pass. GSC now shows 'apa calda bucuresti' at position 9.4 with 3,080 impressions, and today's live SERP (checked 2026-10-12) is positions 1-5 news coverage of an ongoing major avarie plus RADET, which re-confirms the live intent this PR answers.

Conflict resolution: main's newer homepage title ('Apa calda Bucuresti: intreruperi pe strazi', Oct 5) and the indexable intro section were kept; this branch's citywide live-status section with per-sector table, the five-question FAQ with FAQPage JSON-LD, and the live-first meta description were re-applied on top. The OngoingBand Link fix in this branch had already landed on main and merged away cleanly.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the current diff (post-merge-conflict-resolution commit adbec88, superseding the earlier approval on 5b8f80c).

Verified:

  • cityStatusSentence/fmtPuncteTermice (app/page.tsx:49-82) and the per-sector table correctly reuse getSectorLive(sector, lcy) with the same call signature as app/sector/[id]/page.tsx:135,171; PT counts are deduped via Set on slug, so multi-episode PTs aren't double-counted, and ptsAvarie is a proper subset of pts.
  • Singular/plural/"de" agreement (fmtZile/deFor, app/page.tsx:49-82) correctly handles the 0/1/tied-max-sector/all-avarie/no-avarie branches.
  • FAQ answers (app/page.tsx:133-176) are plain strings built only from existing bundle aggregates, rendered verbatim into both the visible <p> and faqJsonLd/JsonLd — satisfies the CLAUDE.md JSON-LD escaping rule, and no scraped names enter the new sections.
  • days vs days_deficienta are reported separately in FAQ #5, never summed, per CLAUDE.md.
  • components/OngoingBand.tsx fix correctly swaps to the prefetch-off @/components/Link wrapper.
  • cmteb.ro nofollow link matches the existing pattern in app/sector/[id]/page.tsx:376.

Minor non-blocking note: cityStatusSentence/fmtPuncteTermice have several grammar branches (0/1/tie/partial-avarie) but aren't unit tested, unlike the project's convention of testing grammar helpers in test/format.test.ts. Worth a follow-up, not a blocker for this content PR.

This branch was successfully deployed

1 active deployment
Preview — adbec880 Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant