feat(landing): reintroduce /contact page styled like /demo#5315
Conversation
- Restore the /contact page (removed in #5181) with a two-column layout mirroring /demo: value prop + trusted-by logos on the left, a message form card on the right, on the platform light tokens and chip components - Restore the contact contract, /api/contact route (rate-limit, honeypot, Turnstile, help-inbox notification + visitor confirmation), now fully contract-bound via parseRequest - Add a useSubmitContact React Query mutation hook - Link Contact from the footer Resources column and add it to the sitemap
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview The API path applies per-IP rate limits, honeypot discard, Turnstile verification with a stricter no-captcha bucket when the widget or transport fails, emails Discovery updates: footer Contact link, sitemap Reviewed by Cursor Bugbot for commit 45d333e. Configure here. |
Greptile SummaryThis PR reintroduces the public contact page and its submission flow. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (5): Last reviewed commit: "refactor(contact): TSDoc over inline com..." | Re-trigger Greptile |
- Make captcha server-authoritative: drop the client-trusted captchaUnavailable flag; a valid Turnstile token is the only way past the stricter fallback bucket, so callers can't opt out of the challenge - Re-execute the Turnstile widget on every submit (incl. after expiry) instead of falling into the no-captcha path once the token expires - Reset the pre-submit gate on mutation settle so rapid double-clicks can't fire a duplicate /api/contact request - Map only feature_request to its email type; every other topic resolves to a General Inquiry confirmation so support requests aren't labeled bug reports - Drop the confirmation-email promise from the success copy (it's best-effort) - Collapse the duplicated no-captcha rate-limit branch; hoist shared response constants; read the Turnstile site key as a module constant
|
@cursor review |
The Turnstile site key is already domain-bound in Cloudflare, so pinning expectedHostname to the marketing SITE_URL (www.sim.ai) only rejected valid tokens issued on self-hosted, preview, and apex-vs-www hosts. Remove the pin and rely on Cloudflare's own domain binding.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2b54626. Configure here.
checkRateLimitDirect fails open on limiter-storage errors so a limiter outage
never takes down normal traffic. But the contact route's no-captcha bucket is
the only throttle on token-less submits, so a fail-open there let uncaptcha'd
requests reach the email path unthrottled during an outage.
- Add an opt-in { failClosed } option to checkRateLimitDirect; default behavior
(fail open) is unchanged
- Use failClosed on the contact no-captcha backstop so an unenforceable limit
rejects instead of admitting
- Cover both fail-open and fail-closed paths with tests
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2d44d47. Configure here.
Move the captcha-design rationale into the route handler's TSDoc and drop the inline body/JSX comments, per the project's TSDoc-only comment convention.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 45d333e. Configure here.
Summary
/contactpage (removed in improvement(landing): refine hero and mothership visuals #5181) with a two-column layout mirroring/demo: value proposition + trusted-by logos on the left, a message-form card on the right/api/contactroute (rate-limit, honeypot, Turnstile, help-inbox notification + visitor confirmation email), now fully contract-bound viaparseRequestuseSubmitContactReact Query mutation hook (contract-boundrequestJson)/contactto the sitemapType of Change
Testing
Tested manually.
tsc, biome,check:api-validation:strict,check:react-query, andcheck:client-boundaryall pass.Checklist