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