Marketing site for MEAI. Single-page React app: practical AI shaped to how a business actually works — from advice to deployment and support.
- React 19 + Vite + TypeScript + Tailwind CSS (pnpm)
- Self-hosted fonts (Playfair Display + Inter via
@fontsource) — no external font/style origins, so the CSP stays tight - No animation/UI libraries — scroll reveals use a small
IntersectionObserverwrapper and respectprefers-reduced-motion - Contact form backed by a Supabase edge function with Cloudflare Turnstile, a honeypot, server-side validation, and per-IP rate limiting
pnpm install
cp .env.example .env.local # fill in Supabase + Turnstile values
pnpm dev # http://localhost:5173pnpm build # tsc -b → vite build → SRI injection (scripts/sri.mjs)
pnpm preview # serve the production build locallyThe build emits content-hashed assets and scripts/sri.mjs injects
integrity + crossorigin (SRI) onto the local script/style references in
dist/index.html.
src/
components/
layout/ Header, Footer
sections/ Hero, WhatWeDo, WhatWeUnderstand, HowWeWork, Contact
forms/ LeadForm, Turnstile
ui/ Button, Container, Section, Reveal
lib/ validation (shared with the edge function), submitLead
public/ robots.txt, sitemap.xml, favicon.svg, 404.html + 404.css
supabase/
migrations/ 0001_leads.sql (leads table + RLS)
functions/ submit-lead/ (authoritative form handler)
leadstable has RLS forced on with no policies — no client role can read or write. Thesubmit-leadedge function (service role) is the only writer.- The edge function verifies the Turnstile token, rejects the honeypot, re-validates every field server-side, rate-limits by salted IP hash, inserts the row, and optionally sends a Telegram notification.
Edge function secrets: TURNSTILE_SECRET_KEY, ALLOWED_ORIGIN, and optionally
TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID. SUPABASE_URL and
SUPABASE_SERVICE_ROLE_KEY are injected by the platform.
deploy.sh builds locally and ships dist/ with an atomic swap; the nginx
server block (nginx-meai.conf) enforces the security headers (CSP, HSTS,
X-Frame-Options, etc.) and returns a real 404 for unknown paths.