Skip to content

feat: PR-6 - Orlando surfaces: salon home, services, city page, JSON-LD, events, engine sitemap - #6

Merged
Eth-Interchained merged 1 commit into
mainfrom
hyperagent/2026-07-07-phase1-pr6-orlando-surfaces
Jul 7, 2026
Merged

feat: PR-6 - Orlando surfaces: salon home, services, city page, JSON-LD, events, engine sitemap#6
Eth-Interchained merged 1 commit into
mainfrom
hyperagent/2026-07-07-phase1-pr6-orlando-surfaces

Conversation

@Eth-Interchained

Copy link
Copy Markdown
Owner

Summary

PR-6: Orlando's public plane goes live. Server-rendered salon home, /services + per-category price tables, the Winter Park city page, HairSalon/BreadcrumbList JSON-LD, click-tracked conversion events, and a sitemap generated from engine queries. Every rendered fact came through the provenance-chained seed — nothing is invented at render time.

Why this matters

This is the storefront that earns: appointment-generation surfaces with honest structured data and attributable conversion events (booking_click, call_click, text_click, direction_click — analytics are one NQL GROUP BY away, per the spec's engine-capability-equals-product-feature doctrine).

What's inside

  • SEO builders (src/lib/seo/): buildHead (canonical locked to the campaign origin) + JSON-LD generators with hard honesty rules — absent entity data = absent property; by-appointment days omitted; no self-marked-up third-party rating (the GBP 4.6/196 renders as attributed text)
  • Page shell (layout.ts): Park Avenue Warm as pure server HTML — no SPA bundle on public pages
  • Surfaces (pages.ts): home / services index / category price tables / city page — all reading PR-5's typed entity queries
  • City gating with real 404s: known-but-held cities return a branded noindex 404. The live suite caught the original design falling through to the SPA shell — 12 indexed soft-404 doorways in production, prevented before first deploy
  • /go/:kind: scheme-allowlisted, click-tracked 302s; events land append-only in the engine
  • Engine-driven sitemap: request-time queries mirror the router's own gating — the sitemap cannot advertise what wouldn't render

Tests run (locally, real engine)

  • tsc --noEmit clean · unit 30/30 (JSON-LD asserted against the REAL Mint seed entity — the seed file is the fixture)
  • Live 4/4 vs nedbd 2.6.1: pages render real NAP/prices/roster · /go event round-trip proven by querying the events collection (source attribution intact) · held-city 404 + noindex · unsafe /go destinations rejected · sitemap includes live surfaces, excludes held cities
  • portal build clean · portal audit unchanged (2 shell-page warnings, tracked since PR-3)

Follow-up work

  • Cache headers + CF purge-on-publish for the public plane (spec §12)
  • City pages 2–13 via the content pipeline with the minimum-content bar (Phase 1 continues)
  • Feeds (feeds.ts) once articles exist (Phase 3)
  • GBP/Search Console alignment after first deploy

Spec: §7 (routing), §8 (SEO engine), §11 (orlando strategy), §14 risks 1+7, §15 Phase 1.

…age, JSON-LD, events, engine-driven sitemap

The revenue site renders. Every fact on every page came through the seed
loader with provenance — nothing is invented at render time.

- src/lib/seo/head.ts: buildHead — titleTemplate, meta description,
  canonical ALWAYS on the campaign origin, OG, noindex flag, JSON-LD
  script injection (</script>-escaped)
- src/lib/seo/jsonld.ts: hairSalonJsonLd + breadcrumbsJsonLd — honest
  fields only: absent data = absent property; by-appointment days omitted
  from openingHoursSpecification; NO self-marked-up Google rating
  (renders as attributed text instead — spec §14 risk 7)
- src/server/layout.ts: Park Avenue Warm page shell — pure HTML, no SPA
  bundle, token values mirroring the blessed design direction
- src/server/pages.ts: / (salon home: real NAP, hours, GBP line as text,
  team, service chips, tracked CTAs), /services, /services/:category
  (real price tables with group heads), /:city, /go/:kind (click-tracked
  302 with scheme allowlist; events fire-and-forget)
- City gating with REAL 404s: known-but-held cities render a branded
  noindex 404 page — found live by the test suite: they previously fell
  through to the SPA shell as indexed 200 soft-404 doorways. Trigger was
  the failing assertion; root cause was fallback ownership of the city
  namespace.
- Sitemap now queried from the ENGINE at request time — it can never
  advertise a page that wouldn't render (held cities excluded by the
  same gating the router uses)
- orlando successEvents += text_click (the salon's favored channel)

Verified locally: tsc clean · unit 30/30 · live 4/4 vs nedbd 2.6.1
(pages render real seeded data; /go event round-trip proven by querying
the events collection; held-city 404s; sitemap contents) · portal build
clean · portal audit unchanged (2 warnings, tracked).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Eth-Interchained
Eth-Interchained merged commit f5e267a into main Jul 7, 2026
1 check passed
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