Repo robots.txt already matched the deployed file (verified via diff
against https://workroot.in/robots.txt). Added commonly-cited AI agents
that were still missing, each with Allow: /:
- OpenAI: OAI-SearchBot
- Anthropic: ClaudeBot, Claude-SearchBot, Claude-User
- Perplexity: Perplexity-User
- Meta: Meta-ExternalAgent / meta-externalagent
- Apple: Applebot, Applebot-Extended
- Amazon: Amazonbot
- ByteDance: Bytespider
- Cohere: cohere-ai
- DuckDuckGo: DuckAssistBot
- You.com: YouBot
- Diffbot
Disallow list unchanged (/admin/, /private/, /_astro/) so no content
directory needed for citation is blocked. Sitemap line preserved.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconcile inconsistent company facts to the canonical set (single
source of truth):
- Structured-data Organization/LocalBusiness/publisher/provider names
now use the legal entity name "WorkRoot IT Solutions LLP"
(SEO.astro, utils/seo.ts) for NAP consistency. Brand short forms
("WorkRoot", "WorkRoot IT Solutions") retained only as display brand
and alternateName.
- Headline government-reach proof figure unified to "11+ districts"
across all company-level proof bands and marketing/SEO copy
(ProofNumbers, /about, /portfolio, homepage, /services, SEO desc).
Specific Bihar Police Management System case studies / service-page
stat tiles keep the factual "11 districts" — documented rationale.
- Verified phone (+91 9561417403), email (admin@workroot.in),
founded (2022), 20+ projects, 50,000+ records, 99.9% uptime and
IIT Patna partnership are consistent site-wide.
Added .agent/scratch/FACTS-CANONICAL.md as the single source of truth
plus an off-site checklist (LinkedIn, Clutch, GoodFirms, Crunchbase,
GeM) to keep external listings identical. Build passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an LLM-citable "WorkRoot at a glance" section to the homepage with 7
standalone factual sentences that each bundle the company name + a concrete
claim + a number (founded 2022, 20+ projects, 11 districts, 50,000+ records,
99.9% uptime, IIT Patna partnership, GeM empanelment, 15,000+ officers, 8+
years), so each line stays accurate when quoted out of context.
- New companyFacts list + "Custom software vs off-the-shelf ERP" comparison
table in src/pages/index.astro (reuses the table pattern from the custom-ERP
service page; final row carries the canonical 11-districts / 99.9% proof).
- Rewrite vague HomepageFaq answers into definitive, self-contained one-
paragraph answers; visible text still drives the single FAQPage JSON-LD.
- Normalize stray "11+ districts" in the services array to the canonical
"11 districts" for exact sitewide numerical consistency.
Verified: build passes; rendered homepage shows all 7 facts, the comparison
table, definitive FAQ answers, exactly one FAQPage JSON-LD, and no "11+".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add two long-form (1,200+ word) blog posts targeting buyer search
questions, with valid content-collection frontmatter, comparison
tables, India-specific rupee figures, and definitive FAQ blocks:
- how-much-custom-erp-cost-india-2026.md (hero: erp-systems.jpg)
- gem-empanelment-process-software-vendors.md (hero: govt-systems.jpg)
Both use category "Web Development" (valid enum), author "Ajay", and
reuse existing hero images. Verified: astro build passes schema
validation and both render at /blog/<slug> with working hero images
and appear in the blog index.
Also record the 1-2 posts/month editorial cadence in
.agent/scratch/SEO-NOTES.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add five SEO landing pages under /services that reuse existing section
components (GuaranteeBand, InlineLeadForm) and a new prop-driven ServiceFaq:
- /services/custom-erp-development
- /services/university-erp
- /services/government-it-solutions-gem-vendor
- /services/police-management-system
- /services/react-native-app-development
Each page has 1,000+ words of specific copy, a real portfolio-backed case
study (IIT Patna, PSCL Bihar, Police MS, Pophealth), a comparison table /
stat block, a page-specific FAQ that feeds the FAQPage schema, and a CTA into
the existing inline lead form (/api/contact). Service + FAQ + BreadcrumbList
schema are passed into SEO.astro; the visible FAQ accordion does not duplicate
the JSON-LD. All company stats match the canonical site-wide set.
Wire the pages into navigation: deep-dive links from the /services detail
sections, a new "Solutions" group on the HTML sitemap, and entries in both the
dynamic sitemap.xml.ts and the served static public/sitemap.xml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the base Organization + LocalBusiness and WebSite structured data out of
BaseLayout's inline scripts into SEO.astro behind a new `base` prop, rendered
once from BaseLayout's <head> so every route (incl. pages without a
page-specific <SEO>) carries the canonical company schema exactly once.
- Organization/LocalBusiness now includes aggregateRating + Review nodes built
from the three real homepage testimonials (Ajay Pruthi, Dhirendra Singh,
Dilip Raj — all 5-star, reviewCount 3, rating 5.0).
- foundingDate 2022, telephone +91-9561417403, email admin@workroot.in,
areaServed Bihar (AdministrativeArea) + India (Country).
- Description keeps the canonical proof numbers identical to the site:
20+ projects, 11 districts, 50,000+ records, 99.9% uptime.
- Reusable Service node now links provider via @id to #organization and
serves Bihar/India; page-specific schema (Service/FAQ/WebPage/...) stays
opt-in and is gated off the base instance to prevent duplication.
- Homepage still emits a single FAQPage (from HomepageFaq) — no duplicate.
- Add jsdom devDependency required by scripts/validate-schema.js.
Verified: build succeeds; scripts/validate-schema.js passes (24 schemas, 0
issues, 0 warnings); rendered ld+json inspected on homepage, services, and
schema-less pages (privacy/terms/cookies/404).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reorder the shared navLinks array so 'WRNexus' renders as the second
item (right after Home) in both the desktop menubar and the mobile menu
panel. The mobile menu panel already includes a top-right cross close
icon (#mobile-menu-close, aria-label="Close menu") wired to closeMenu().
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restructure the homepage hero from a single centered block into a
responsive two-column grid: left column holds the left-aligned
headline, subtext, CTAs, click-to-call and trust line; right column
holds the framed product dashboard preview.
- Replace `max-w-5xl mx-auto text-center` with
`grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-center`.
- Scale headline down from text-5xl/8xl to a responsive
text-4xl md:text-5xl lg:text-6xl so it no longer overflows.
- Left-align CTAs/links on desktop (justify-start, lg:text-left)
while keeping centered stacking on mobile (grid-cols-1).
- Swap section min-h-screen for lg:min-h-[85vh] and py-24 lg:py-32
so the hero fits the viewport instead of dominating it.
- Preserve existing background gradient and decorative blur elements,
consistent with the about/portfolio heroes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a top-level "WRNexus" navigation item linking to https://wrnexus.com/
that opens in a new tab. Implemented via the data-driven navLinks array
with an `external` flag; desktop and mobile renderers apply
target="_blank" and rel="noopener noreferrer" and skip prefetch/active-state
for external links.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Generate crisp icon set from WorkRoot SVG: favicon.ico (16/32/48),
favicon-32x32.png, apple-touch-icon.png (180), logo.png (512),
and PWA icon-192.png / icon-512.png
- Add favicon.ico link with recommended <head> tag order in BaseLayout
- Reference icon-192/icon-512 in manifest.json for PWA installs
- JSON-LD Organization logo now resolves to the real 512x512 mark
- Header/Footer already render the new mark via /favicon.svg; dark-mode
wordmark contrast (BUG-5) preserved and verified
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add WorkRoot Icon as public/favicon.svg, regenerate logo.png (512x512)
and apple-touch-icon.png (180x180) from the brand vector; add
favicon-32x32.png raster
- Register 32x32 PNG favicon link in BaseLayout <head> alongside the
SVG and apple-touch-icon
- Replace placeholder "W" logo boxes with the WorkRoot mark in the
header, mobile menu, and footer (preserving "WorkRoot" text spans
required by the dark-mode contrast tests and the home link wrapper)
JSON-LD/SEO logo (/logo.png) and PWA manifest icons now resolve to the
real brand assets. Build passes; BUG-5 dark-mode and navigation tests
green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses contact-page audit points 22–27:
- Confirmed no '200+ companies' credibility claim; canonical stat set retained
- Service dropdown now matches real services, led by ERP/Enterprise + Government IT;
removed Cloud Services and AI & ML, added UI/UX Design
- Backend allowlist + labels updated to accept 'ui-ux' and reflect real service names
- H1 paired with value prop: free 1-page proposal in 24 hours
- '< 24h response' promise badge moved above the form
- Clarified contradictory hours to 'We reply within 24 business hours, Mon–Fri'
- Reduced message textarea height (rows 5→4) and max length (5000→2000)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apply portfolio CRO audit points 17-21:
- Add a one-line outcome headline above each project card description
(grid + featured cards), styled with the primary accent per the
design system (e.g. "Cut crematorium slot booking from hours to
minutes across 10+ facilities.").
- Remove the "AI & ML" category filter chip — no project genuinely
fits it (Pophealth is health/mobile) — and correct the ItemList
structured-data description to drop the inaccurate AI/ML claim.
- Stats bar already surfaces the canonical proof set (11 Districts
Deployed, 50,000+ Records Managed) shared with the homepage/services
via ProofNumbers; the weak "4 Specializations" stat is gone.
- "View Case Study" CTAs open the inline case-study modal with full
problem -> solution -> outcome (Challenge / Solution / Key Results),
verified working via headless browser.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Replace generic H1 with outcome-led headline ("Custom software for
enterprises and governments — shipped in weeks, not quarters.")
- Rewrite each service description to lead with the outcome and end
with the tech stack
- Reorder service cards so Government IT and ERP/Enterprise lead,
before Web/Mobile
- Add "What's included" label above each pricing tier's bullet list
(Most Popular badge on Professional retained)
- Unify CTAs to one primary ("Get my free proposal") + one secondary
("See our work" → /portfolio)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Rename WhatsApp label from "WhatsApp" (8 chars) to "Chat" (4) so every
visible label fits the ≤7-char action-verb policy and never triggers
the new text-overflow:ellipsis safety net even at 320px (iPhone SE).
- Bump inline SVG icons to 24×24 (was 22), set min-height 64px and
min-width 44px per Apple HIG / WCAG 2.5.5 tap-target requirements.
- Add white-space:nowrap + text-overflow:ellipsis as defensive safety
net, plus a 320-359px breakpoint that nudges label to 11px / padding
to 4px-horizontal so glyph-width drift can't cause overflow.
- Rewrite aria-labels to be action-led + descriptive even when visible
text is terse: "Call us", "Chat with us on WhatsApp", "Get a free
quote" (WCAG 2.5.3 name-in-name).
- Bump BaseLayout bottom-spacer from 64px → 72px so the new
PricingTimelineBand and GuaranteeBand always have an 8px visual
buffer above the fixed sticky bar (no overlap).
Verified: build green, all 6 tests in tests/sticky-cta.spec.ts pass
against the restarted frontend service. Probed live at 320 / 375 /
414 px — every button is 64px tall, ≥103px wide, icons 24×24, labels
never truncate. Footer fully clears the bar at scroll-bottom.
- TrustStrip.astro: single-row, grayscale-on-default / colour-on-hover
client logo strip under the hero. 6 logos via <img> with explicit
width/height + loading=lazy (CLS-safe), wraps to 3+3 on mobile.
Includes sr-only "Trusted by" heading and dark-mode invert filter
vetted against THEME_ACCESSIBILITY_AUDIT.md. Replaces the older
ClientLogos placement on the homepage.
- GuaranteeBand.astro: 3-up risk-reversal band wedged between
PricingTimelineBand and InlineLeadForm. Three claims (30-day
satisfaction guarantee, no long-term contracts, fixed-price quotes)
with icon + headline + supporting body. Stacks vertically on mobile.
- public/images/logos/: 6 placeholder SVG wordmarks (plnr, rentec,
iit-patna, moc-soft, gov-bihar, pscl). Replace at same path with
real client-supplied artwork when handed off.
- index.astro: wires the two new components, repoints the hero
scroll indicator to #trust-strip, preserves legacy #client-logos
anchor for any external deep-links.
The team-member count read as a small-shop signal next to the new ProofNumbers band. Swap it for a stronger value-prop (team seniority) on both
index.astro and about.astro. Rename the about-page "Years of Experience" stat
to "Years in Business" to disambiguate from the new team-experience metric, and
refresh the about-page SEO description accordingly. The new label doesn't
collide with any ProofNumbers entry (Projects Delivered / Client Rating /
Districts Deployed / Avg Page Load), so the two bands stay non-redundant.
Adds a new PricingTimelineBand component that sits directly above the
homepage InlineLeadForm with two side-by-side cards answering the two
final pre-conversion questions every buyer has:
1. "Projects from $X,XXX" — includes discovery, design, build, QA,
and post-launch support.
2. "Typical timeline: 4–8 weeks" — discovery week 1, weekly demos,
launch by week 8.
A subtle "Custom quote available — tell us about your project" line
with a downward chevron visually bridges the band into the form below.
Implementation notes:
- Anchor id="pricing-timeline" so the mobile sticky CTA bar / nav can
deep-link to it.
- grid-cols-1 md:grid-cols-2 → stacks vertically on mobile, side-by-
side on md+ (>=768px).
- Each card has an explicit min-h-[260px] sm:min-h-[280px] so the
band reserves its own vertical space at first paint, keeping
Lighthouse CLS unchanged.
- Uses existing design tokens (primary-* / accent-* / secondary-*,
rounded-3xl, container-wrapper, gradient-br) so the band feels
native to the page.
- Placeholder copy ($X,XXX and 4–8 weeks) is flagged with
data-stakeholder-confirm markers + HTML comments so the marketing/
leadership team knows what still needs sign-off.
- Reduced-motion-respecting CSS animation on the bridging chevron.
Swaps the soft-adjective benefits section (Rapid Development, Enterprise
Security, Built to Scale, 24/7 Support) for a compact horizontal stat
band so the first below-the-fold surface leads with hard, scannable
numbers instead of generic copy.
- New src/components/ProofNumbers.astro renders 4 large gradient numbers
with one-line captions: 20+ Projects Delivered, 5★ Client Rating,
11 Districts Deployed, < 2s Avg Page Load. Numbers carry a TODO for
stakeholder confirmation; defaults mirror existing hero/stat copy.
- Responsive grid: 2×2 on mobile (<md), 4×1 horizontal band on desktop,
with subtle vertical dividers between columns on md+.
- Matches site typography tokens (text-secondary-* / text-primary-*)
with full dark-mode parity (gradients shift to primary-400/300).
- Removes now-unused `benefits` data array and inline SVG icons from
src/pages/index.astro along with the surrounding section markup.
- Add `image`/`imageAlt`/`initials`/`metric`/`metricLabel` fields to the
homepage testimonials data so each card surfaces a concrete client
outcome (e.g. "3× faster loan processing", "+42% organic traffic")
next to the quote.
- Render a 56–64px rounded avatar with lazy-loaded `<img>` (width/height
set to prevent CLS) and a brand-tinted metric badge in the card
header. Initials sit behind the image as an automatic fallback if
the avatar 404s or fails to decode.
- Ship 3 neutral SVG initial-avatars under public/images/testimonials/
(ajay-pruthi, dhirendra-singh, dilip-raj) as placeholders until real
headshots are licensed — flagged in the data-array comment so future
edits know to swap in JPG/WebP at the same path.
- Tighten responsive sizing: card padding scales 8→14, quote text
scales 20→30, avatar 56→64, and the star+metric row now wraps on
narrow viewports so the layout reads cleanly at 360/768/1280.
The homepage rendered two FAQ blocks — an inline "Common Questions" section
plus the <HomepageFaq /> component above the final CTA — which produced two
FAQPage JSON-LD entries and a redundant accordion. Consolidate on
HomepageFaq (self-contained, polished accordion, better a11y) and:
- delete the inline FAQ <section>, the `faqs` array, the `faq={faqs}` prop
on <SEO>, the orphan .faq-question/.faq-answer/.faq-icon CSS, and the
initFAQ() boot script + its call in index.astro
- merge the 4 unique inline questions (support, process, team augmentation,
security) into HomepageFaq's moneyFaqs; the 2 duplicates (technologies,
timeline) were already covered there
- refresh HomepageFaq's lead-in copy and comments to reflect it as the
single canonical homepage FAQ
Result: one FAQ heading + one accordion in the DOM, exactly one FAQPage
JSON-LD with 10 Q&A pairs, no broken anchor links.
Both honeypots now use off-screen positioning (position:absolute; left:-9999px;
width:1px; height:1px; overflow:hidden) instead of relying on a parent's
aria-hidden alone, and the input itself carries tabindex="-1",
autocomplete="off", and aria-hidden="true". Labels are sr-only and sit as
siblings of the input (no nested label/input). Avoid display:none and
visibility:hidden so bots that skip those still trip the trap.
Verified: rendered honeypot HTML matches spec on both /contact and the
homepage inline lead form, and /api/contact still 200s a populated `website`
silently (bot path) while accepting empty `website` payloads as real leads.
Both the contact form (/contact) and the homepage "Tell us about your project"
inline lead form post to /api/contact. Updated that single handler to build
the nodemailer transport from a clean set of SMTP_* env vars per spec:
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS
SMTP_FROM + SMTP_FROM_NAME -> "From: Ajay Ghanwat <ghanwat.ajay@workroot.in>"
MAIL_ADMIN_TO -> admin notification recipient
(falls back to SMTP_FROM, then legacy
CONTACT_EMAIL_TO / CONTACT_EMAIL / SMTP_USER)
SMTP_REQUIRE_TLS -> force STARTTLS upgrade on port 587
SMTP_CONNECTION_TIMEOUT_MS -> defaults to 10000
SMTP_GREETING_TIMEOUT_MS -> defaults to 10000
SMTP_SOCKET_TIMEOUT_MS -> defaults to 10000
Behaviour preserved:
- Existing user-facing auto-reply (the block previously at L270) kept.
Subject + body now adapt for project-inquiry sources (homepage-inline,
homepage-hero, homepage-final-cta, mobile-sticky) so the admin inbox
can triage [Project Inquiry] vs [Contact Form] at a glance.
- Graceful degradation per FORM_INTEGRATION.md: missing env vars or a
failed nodemailer import logs a structured warning and returns 200 —
the site never 500s on email config.
- Rate limiting, honeypot, CORS, validation, and fire-and-forget
background dispatch are untouched.
Observability:
- Structured console logs at: transport created, admin accepted (with
messageId), user auto-reply accepted (with messageId), and send-failure
(with smtp code/command/response). SMTP_PASS is never logged.
Misc:
- .env.example updated to document the new variables and the legacy
aliases that are still honored.
Expand the CI/CD env-var table to list all SMTP_*, MAIL_ADMIN_TO,
SMTP_FROM, SMTP_FROM_NAME and STARTTLS/timeout knobs that the contact
and "Tell us about your project" forms now rely on. Adds a note that
the production secrets live in the Default environment's platform
env-var store and that the frontend service must be restarted after
any change.
Mounts a 3-field lead-capture form (name, email-or-phone, project type)
between the FAQ/tech-stack block and the final CTA band so visitors who
are ready to start a project can submit without leaving the homepage.
Cuts the friction step of routing every CTA through /contact.
- New src/components/InlineLeadForm.astro:
* Heading, micro-trust subhead, honeypot, client-side validation
* Smart contact-field routing: detects email vs phone and synthesises
a placeholder email for phone-only leads so the existing /api/contact
validator accepts them (the real phone is preserved and surfaced in
the admin notification)
* In-place success state with phone + WhatsApp fallbacks; no navigation
* 48px touch targets, dark-mode safe, autocomplete + inputmode attrs
- src/pages/api/contact.ts: accept and surface `source` / `projectType`
metadata (allowlisted source values, free-text projectType capped at
80 chars), add `erp-solutions` and `government-systems` subject codes,
and include the source/project info in both the admin email and logs.
- src/pages/index.astro: import + mount InlineLeadForm above the final
CTA section.
- tests/inline-lead-form.spec.ts: 8 specs covering UI render, mobile
attributes, blank-field validation, email-submit + phone-submit
payload routing, and server-side acceptance of the new payload shape,
new subjects, and unknown-source fallback.
- WhatsAppFab: 56px brand-green floating button (wa.me/919561417403), shown
on every page; safe-area aware; lifts above the mobile CTA bar on <md.
- MobileStickyCtaBar: 3-column sticky bottom bar (Call / WhatsApp / Quote)
visible only below the md breakpoint, with safe-area padding, 48px+ touch
targets, and dark-mode-aware styling. Bottom spacer keeps the footer
clear of the bar on mobile.
- Mounted both components globally via BaseLayout.
- Added tests/sticky-cta.spec.ts covering 360px and 1280px viewports,
link integrity, no-overflow, hidden-at-md, and FAB/bar non-overlap.
The stats tiles ("Projects Delivered" etc.) could end up frozen at
0+/0%/0+/0 whenever the IntersectionObserver never fired (tall
sections on mobile, threshold too strict, JS error, prefers-reduced-motion).
- Server-render the final value as the initial textContent so the
numbers are correct on first paint, with JS disabled, and on any
hydration failure.
- Lower observer threshold to 0.1 and add rootMargin so the animation
triggers reliably on tall viewports.
- Detect prefers-reduced-motion and render the final value without
animating.
- Fall back to immediate animation when IntersectionObserver is
unavailable or the section is already in view at load.
- Reset to 0 only at the moment the animation starts (and snap to
the exact target at the end) so a mid-flight failure can never
leave the counter visibly stuck.
- Boot all homepage scripts after DOMContentLoaded.
Hero
- Tightened H1 to a benefit-led, audience-first value prop
("Custom Software That Powers Enterprises & Governments")
- Replaced generic subhead with a ~135-char outcome line that names
the audience (startups, enterprises, government bodies)
- Swapped primary CTA copy to an action verb ("Get a free consultation")
and secondary to "See our work"; added source query params + data-cta
hooks so analytics can attribute CTA clicks
- Added a micro-trust line under the CTAs (free 30-min call, reply within
1 business day, no commitment)
Social proof
- New ClientLogos.astro component rendered below the hero. Grayscale
strip with hover pop, image+wordmark fallback, TODO documenting the
five required SVG assets in public/images/clients/
- Default roster sourced from the live portfolio (PLNR, RENTEC, IIT
Patna, MOC Soft Technologies, Govt. of Bihar)
- Existing testimonials carousel left intact (3 quotes with name/role)
Services preview
- Reframed the 4 cards around outcome headlines and added deep links
to /services#<slug> for each service detail section
- Renamed "Learn More" to "Learn more" and made it a real <a> link
with aria-label for screen readers
Final CTA band
- New conversion-focused headline ("Ready to ship your next production
system?") and a one-line offer with explicit response SLA
- Added a "what you'll get" reassurance row (discovery call, fixed-price
scope, NDA on request)
- Primary CTA now "Get my free consultation" with source attribution;
secondary "See case studies" preserved
- Process-section CTA renamed to "Book a discovery call" and tagged
SEO
- Updated meta description on BaseLayout invocation to match the new
positioning; FAQPage schema and existing structured data untouched