Commit Graph

10 Commits

Author SHA1 Message Date
null fef8b0718c fix(seo): descriptions were two sentences run together on all eleven detail pages
Live until now, on every service and industry page:

  "...seamless integration Delivered by Queue North, a veteran-owned..."
  "...for medical providers Queue North delivers phone, contact center..."

clampDescription joined its fragments with a space, and no shortDesc in
services.js or industries.js ends in a full stop. Nothing added one. The
description is the first thing a searcher reads, and it read as a run-on on
eleven of the eighteen pages.

buildDescription replaces it and joins fragments AS SENTENCES. It also takes an
`approved` description, which it emits verbatim: never joined, never clamped.
Levi's approved copy for the two long-form pages is 164 and 191 characters, and
the old 158-character clamp would have cut his sentences off with an ellipsis.
ServiceDetail reads it from `page.seo`, which the content commit fills in.

ServiceDetail and IndustryDetail now build their canonical from SITE_URL rather
than repeating the origin. The three files release.sh greps for that literal are
untouched, so the origin guard still has three copies to compare.

Verified against a build, page by page: all 11 detail descriptions gained
exactly a full stop and changed in no other way, and no other page's description
moved.

Closes #234.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 04:28:25 -05:00
null ac6f5d1f78 feat(seo): publish privacy policy, remove street address, prerender all routes (batch 0.9.3)
Client directive (Levi Halford, 2026-08-01) ahead of Google/Meta lead forms.

Privacy policy:
- Publish approved policy verbatim at /privacy-policy (src/data/privacyPolicy.js
  is the single source of truth; 292/292 source lines verified present)
- Privacy Policy link in the footer of every page
- Effective/Last Updated 2026-07-31, privacy@queuenorth.com as mailto

Remove St. Petersburg street address from every surface named in the brief:
footer, contact page, schema markup, SEO metadata, Google Maps links. Collapse
ProfessionalService + Organization schema into a single Organization with
areaServed: United States; drop geo coordinates, priceRange, openingHours.
Add the approved US-coverage sentence to About. No replacement address.

Crawler visibility (the site previously served 0 bytes of body HTML without JS):
- Prerender all 19 routes at build time via src/entry-server.jsx + scripts/prerender.js
- Hoist title/meta/canonical/JSON-LD into <head>; renderToString does not do this
  and react-helmet-async's context is empty under React 19
- Serve prerendered HTML; return a real 404 for unknown paths instead of 200
- Hydrate instead of discarding the prerendered markup

SEO/perf:
- Titles <=60 and descriptions <=160 chars across all pages
- Add BreadcrumbList to interior pages, WebSite to home
- Generate sitemap.xml from the route list with git-derived lastmod
- 301 duplicate URL forms (trailing slash, //, /index.html), preserving query
- Immutable caching for content-hashed assets; no-cache for HTML
- Split the 522 KB bundle into app/react-vendor/router/icons
- loading/decoding/fetchpriority + per-route hero preload; drop unused asset

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 01:45:52 -05:00
null 05b27d216a feat: Dockerfile/docker-compose updates, server improvements, contact form with recaptcha, API integration (batch 0.9.0) 2026-06-14 15:37:26 -05:00
null afec6547c1 RECAPTCHA 2026-05-25 20:20:15 -05:00
null 09926fed6d Contact.jsx (line 23): added ZIP to validation/error state, rendered it as required, and shows ZIP code is required.
server/index.js (line 253): backend Zod schema now rejects missing or blank ZIP.
api.js (line 3): preserves backend field errors for display.
2026-05-25 18:17:16 -05:00
null 2c002c2f82 fix: remove React Query, add HTTPS redirect, document CSP Zoho note (#128 #127 #129) (batch 10.0) 2026-05-17 22:33:11 -05:00
null 4f3e20b7a0 fix: dead code cleanup, timeout middleware, Zoho error handling (closes #53, #54, #55, #56, #57)
- Delete broken barrel exports ui/index.jsx and ui/all.jsx (#53)
- Remove duplicate QueryClient instance and dead queryClient.js (#55)
- Remove unused queryClient import/export from api.js (#55)
- Move timeoutMiddleware before catch-all routes so it actually fires (#54)
- Fix async error handling in forwardToZoho - add .catch() (#56)
- Add ZOHO_CLIENT_ID to credential guard, normalize defaults to null (#57)
(batch 0.6.4)
2026-05-17 17:46:54 -05:00
null 56bdf07216 fix: close issues #12 #15 #17 #18 — CSP nonce, API retry, input debounce, caching verified (batch 0.6.1) 2026-05-17 16:10:10 -05:00
null e11aefd184 fix: audit issues #10 #14 #16 #19 — CORS errors, JSON middleware, Zoho fields, noValidate (batch 0.6.8) 2026-05-17 15:46:59 -05:00
null b7f7765a72 feat: complete phase 1 foundation 2026-05-12 01:04:17 -05:00