Skip to content

Improve SEO, GEO, and AEO for ditectrev.com - #19

Merged
danieldanielecki merged 3 commits into
masterfrom
cursor/seo-improvements-48bb
Sep 17, 2026
Merged

danieldanielecki merged 3 commits into
masterfrom
cursor/seo-improvements-48bb

Conversation

@danieldanielecki

@danieldanielecki danieldanielecki commented Sep 17, 2026 •

Copy link
Copy Markdown
Member

Summary

High-impact SEO plus GEO (Generative Engine Optimization), AEO (Answer Engine Optimization), and AIO (AI Overviews / AI optimization) for the Angular SSR/prerender site. Copy is taken from existing page content only—no invented claims, reviews, ratings, or keyword stuffing.

SEO (earlier on this PR)

  • Per-page titles, descriptions, Open Graph, and Twitter tags. Every indexable route now gets unique metadata via SeoService (wired from router navigation so it is present in SSR/prerender HTML). Defaults in index.html were cleaned up: emojis removed, relative OG image replaced with an absolute PNG, Twitter tags use name, and fabricated og:locale:alternate values were removed (the site is English-only).
  • Canonical URLs. Each page now has a self-referencing rel=canonical matching the sitemap URL shape (https://ditectrev.com/ for home, no trailing slash elsewhere).
  • JSON-LD. Organization/ProfessionalService, WebSite, BreadcrumbList on all pages; FAQPage from existing FAQ answers (HTML stripped); Service nodes on the three service detail pages. No aggregate ratings or review schema.
  • robots.txt / sitemap.xml. Explicit Allow: /, Disallow: /health, and stale 2021 lastmod dates removed so we do not send inaccurate modification signals.
  • Heading hierarchy & semantic HTML. Real <h1> page titles (keeping existing title attributes for e2e). Service cards use <h2>. HTML sitemap section labels are headings. 404 page has an <h1> and a homepage link.
  • Crawlability. Service CTAs are <a routerLink> instead of <button>, with descriptive link text from existing tooltips. Gallery “Learn more” links use routerLink (still emit href). Unknown SSR routes now return HTTP 404 plus X-Robots-Tag: noindex, follow.
  • Images / CWV-related SEO. More specific alt text, loading="lazy" on below-fold images, decoding="async", and intrinsic width/height on 100×100 testimonial portraits to reduce CLS.
  • CodeQL. stripHtml loops to a fixpoint and then removes leftover <> so nested/unclosed tags cannot remain.

GEO / AEO / AIO (this follow-up)

  • /llms.txt and /llms-full.txt. Spec-style markdown overview plus a citation fact sheet and Q&A, all paraphrased or quoted from existing About, FAQ, services, methodology, and legal copy. Built as Angular assets so Express static, Firebase Hosting, and Vercel serve them before the SSR fallback.
  • AI crawler policy. Wildcard already allowed crawling; robots.txt now also names GPTBot, ChatGPT-User, OAI-SearchBot, ClaudeBot/User/SearchBot, PerplexityBot/User, Google-Extended, Google-CloudVertexBot, CCBot, Applebot/Applebot-Extended, Bingbot, and DuckAssistBot. Site intent is public education and consulting, so training and citation bots are allowed. Google AI Overviews use Googlebot (covered by User-agent: *), not Google-Extended.
  • Snippet eligibility for AI Overviews. index,follow,max-snippet:-1,max-image-preview:large,max-video-preview:-1 so Google can use full passages in overviews and snippets.
  • Crawler discovery. rel=describedby and rel=alternate type=text/markdown point to llms.txt. XML sitemap lists both LLM files.
  • Entity / answer structured data (visible-page content only where Google FAQ/HowTo rules apply):
    • Organization identity: legal name, founder, tax ID, contact point, knowsAbout, offer catalog of the three service lines.
    • Home WebPage.mainEntity Q&A from existing FAQ (What is Ditectrev, what we do, location, Scrum).
    • FAQPage on /faq from the live FAQ tree.
    • HowTo on /methodology from the five existing delivery stages.
    • OfferCatalog on each service page from the existing service names.
    • DefinedTermSet on /glossary from existing glossary terms.
    • ItemList on /services for the three service lines.

Remaining opportunities (skipped)

  • Hero tagline as <h2>. Changing it to a <p> would require rewriting a large letter-animation stylesheet; left as-is to avoid a visual redesign.
  • 1200×630 Open Graph banner. No existing landscape share image; we use the square 512×512 PWA icon with twitter:card=summary rather than inventing marketing art.
  • hreflang. Site content is English-only. Alternate locale tags were removed instead of adding fake language versions.
  • Review / AggregateRating schema. Testimonials exist but have no ratings; we did not invent stars.
  • WebSite SearchAction. There is no site-wide search URL (glossary filter is client-side only).
  • SpeakableSpecification. Google documents this for news/article publishers, not this site type.
  • FAQ JSON-LD on service pages. Service-specific Q&A lives on /faq, not on the service templates; adding FAQPage there would not match visible content.
  • Blocking AI training crawlers. Would conflict with public education/consulting discovery; policy is allow.
  • Per-route .md mirrors / .well-known/llms.txt / WebMCP. Duplicative or experimental relative to root llms.txt.
  • HTML sitemap link to llms.txt. routerLink would 404 inside the SPA; crawlers already get robots.txt, sitemap.xml, and describedby.
  • Performance overhaul. particles.js, Three.js, GTM, and route fade animation affect LCP/INP but are product/design, not accurate SEO copy or metadata.
  • Legal-page h3 → h2. Would enlarge section titles visually; skipped to stay out of redesign territory.

Test plan

  • Unit tests for SeoService (13 passed, including HowTo, DefinedTermSet, ItemList, describedby/alternate, sanitizer)
  • Playwright e2e/seo.spec.ts (home/about titles, llms.txt, llms-full.txt, sitemap discovery, 404 noindex)
  • Existing page smoke (e2e/pages.spec.ts, e2e/smoke.spec.ts) still passes (from earlier SEO work)
  • Key routes render: /, /about-us, /services, /faq, /contact (covered by Playwright page specs)
  • CodeQL incomplete HTML sanitization: stripHtml now loops to a fixpoint and removes leftover <>; SeoService specs cover nested/unclosed tags
Open in Web Open in Cursor 

Add route-specific titles, descriptions, canonicals, and Open Graph/Twitter
tags, plus JSON-LD for Organization, FAQ, and services. Improve heading
markup, crawlable service links, sitemap freshness, and 404 noindex status
without changing page copy or inventing claims.

Co-authored-by: ✅ Daniel Danielecki <danieldanielecki@users.noreply.github.com>
Comment thread src/app/services/seo.service.ts Fixed
Loop tag removal until the string is stable and drop leftover angle
brackets so nested or unclosed tags cannot survive a single regex pass.

Co-authored-by: ✅ Daniel Danielecki <danieldanielecki@users.noreply.github.com>
@cursor
cursor Bot deployed to Preview September 17, 2026 09:06 Active
@cursor
cursor Bot deployed to Production September 17, 2026 09:06 Active
Publish llms.txt and llms-full.txt, allow major AI crawlers, and extend JSON-LD with FAQ, HowTo, glossary terms, service catalogs, and snippet-friendly robots so answer engines can cite existing site facts.

Co-authored-by: ✅ Daniel Danielecki <danieldanielecki@users.noreply.github.com>
@cursor
cursor Bot deployed to Preview September 17, 2026 09:53 Active
@cursor
cursor Bot deployed to Production September 17, 2026 09:53 Active
@cursor cursor Bot changed the title Improve on-page SEO for ditectrev.com Improve SEO, GEO, and AEO for ditectrev.com Sep 17, 2026
@danieldanielecki
danieldanielecki marked this pull request as ready for review September 17, 2026 11:02

@danieldanielecki danieldanielecki left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

approved

@danieldanielecki
danieldanielecki merged commit f5e68ca into master Sep 17, 2026
21 checks passed
@danieldanielecki
danieldanielecki deleted the cursor/seo-improvements-48bb branch September 17, 2026 11:06

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 40353e8. Configure here.

Comment thread src/server.ts
if (!isIndexablePath(req.path || req.url)) {
res.status(404);
res.set('X-Robots-Tag', 'noindex, follow');
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Trailing slashes skip true 404s

Medium Severity

isIndexablePath and getPageSeo strip trailing slashes before lookup, so /about-us/ is treated as the real About page. The router has no empty-child route for those paths, so the wildcard 404 view can still render. Crawlers then get HTTP 200, index,follow, and the real page’s title and canonical on a not-found body.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 40353e8. Configure here.

items.push(...this.flattenFaq(node.questions, nextPrefix));
}
}
return items;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

FAQ schema prefixes visible questions

Medium Severity

flattenFaq builds JSON-LD question names as category: question, so /faq markup says Company: What is Ditectrev? while the page shows What is Ditectrev?. FAQ rich results and answer engines expect the marked-up question to match the visible text, so this FAQPage block is likely ignored or treated as mismatched content.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 40353e8. Configure here.

This branch was successfully deployed

2 active deployments
Preview — 40353e81 Deployed Sep 17, 2026 by cursor[bot] via Build (staging) #79
Production — 40353e81 Deployed Sep 17, 2026 by cursor[bot] via Build (production) #79
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.

3 participants