Fixes issues raised by the whole-branch review before merge:
- Critical: the previous migration hardcoded the live production
functions URL and anon key as the committed default, so every local
`supabase db reset` silently pointed dev/test triggers at the real
project. Adding a new migration instead of editing the already-applied
one (checksum/drift safety), with local dev values as the committed
default; production values are applied out-of-band, never committed.
- Important: verify_jwt=true plus sending the anon key as a bearer
token didn't actually stop anyone, since the anon key is public
(ships in the frontend bundle) — confirmed empirically, a request
with a valid anon key but no shared secret now gets a real 401.
Added a random shared secret known only to the database and the
Edge Functions' secret store.
- Important: notification emails interpolated raw contact fields into
HTML with no escaping. Added escapeHtml() and tests proving injected
markup renders as literal text, not live markup.
- Important: the URL/key/secret functions moved from public to a
private schema with EXECUTE revoked from anon/authenticated, closing
an unintended PostgREST RPC endpoint (verified 404 after the fix).
Also adds a test:functions npm script now that Deno is confirmed
available and the shared email builders' tests pass (12 total incl.
the new escaping cases).
Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
The brief's literal script copies source fields verbatim, but src/data
uses camelCase (inStock, durationMinutes, priceFrom) while the DB
columns are snake_case (in_stock, duration_minutes, price_from), so
that version fails with PGRST204. Map fields explicitly instead of
spreading the rest.
Initializes the local Supabase project (supabase/config.toml) and adds
a thin src/lib/supabase.ts wrapper around @supabase/supabase-js that
reads connection details from Vite env vars, tested with a mocked
createClient.
Adds emulator-backed rules-unit tests verifying the Firestore rules
committed in Task 3, including the global constraint that
bookings/inquiries are never publicly readable. Excludes
firebase-tests/ from the default vitest run since it needs the
emulator (via `npm run test:rules`) rather than jsdom.
- Lazy-load Home in App.tsx so three/@react-three/fiber (~238 kB gzip) only ships to the
Home route, not to Shop/Book/Rules.
- Add max-width: 260px to ProductCard/ServiceCard so real images won't collapse Home/Book
grid layouts.
- Restore AnimatePresence mode="wait" in Book.tsx to eliminate the exit/enter double-stack
during step transitions, updating the three Book.test.tsx assertions that raced the
transition to findBy* queries.
- Hero3DScene: drop the meaningless "static" className string in favor of a dedicated
data-testid, add aria-hidden to the reduced-motion fallback branch, and remove the
unused @react-three/drei dependency (adding @types/three directly since it was only
present transitively via drei).