Commit Graph

113 Commits

Author SHA1 Message Date
belviskhoremk
b4f7c1dce3 fix: exclude nested worktree directories from vitest
Running the suite from the main checkout was picking up each
worktree's full copy of src/ under .claude/worktrees/, silently
running every test twice. The existing supabase/functions/** exclude
only matched at repo root, so it also missed the nested worktree's
copy of that path.

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-12 10:19:15 +02:00
belviskhoremk
35e929c5e1 fix: harden Edge Function notification path per final review
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
2026-08-12 10:15:34 +02:00
belviskhoremk
8c1522a2b4 chore: deploy Phase 2A backend to live Supabase project (Task 9)
Substitutes the real admin UID everywhere the placeholder appeared,
points the Edge Functions base URL at the deployed project, and adds
production JWT verification: trigger functions now send the anon key
as a bearer token so verify_jwt can stay enabled instead of leaving
the functions open to unauthenticated calls from the public internet.

Also adds scripts/create-admin.ts (one-off helper used to create
Mira's admin auth user), documents the seed script's non-VITE env
vars in .env.example, and closes a gitignore gap where plain .env
wasn't excluded alongside .env.local.

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-12 09:59:33 +02:00
belviskhoremk
1181d9a3be feat: add Supabase seed script for products, services, and default schedule
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.
2026-08-08 13:35:14 +00:00
belviskhoremk
27710e18a9 fix: extract Edge Functions base URL into a single shared SQL function
notify_booking_created() and notify_inquiry_created() each held their own
literal copy of the local Edge Functions base URL. Introduce
public.edge_functions_base_url() as the single source of truth so Task 9's
production deploy only needs to update one function definition instead of
two independent literals.
2026-08-08 13:31:07 +00:00
belviskhoremk
7e51c2df37 feat: add on-booking-created and on-inquiry-created Edge Functions with DB-trigger wiring
Wires pg_net-based database triggers on bookings/inquiries to invoke the two
Edge Functions on insert. Two empirically-discovered fixes over the brief's
literal SQL were required to make this work locally:

- ALTER DATABASE ... SET for a custom GUC needs superuser, but the local
  migration role (postgres) isn't superuser in this Supabase CLI stack (only
  supabase_admin is) - inlined the base URL as a literal constant in each
  trigger function instead.
- pg_net's http_post lives in schema `net`, not `extensions.net` - fixed the
  function calls accordingly.

Also disabled verify_jwt for both functions in config.toml since they're
invoked by pg_net (no Authorization header), not by end-user clients.

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-08 13:25:04 +00:00
belviskhoremk
6e615113a7 feat: add Edge Functions workspace with tested email builders
Adds supabase/functions/ (deno.json, _shared/email.ts) with pure
buildBookingNotificationEmail/buildInquiryNotificationEmail functions
for Task 6's Edge Functions, tested via Deno's test runner. Excludes
supabase/functions/** from the root Vitest config, which otherwise
tried to resolve the jsr: import and failed.
2026-08-08 13:12:30 +00:00
belviskhoremk
aacb9dca12 fix: scope GRANT statements to match actual RLS-permitted access per role
Replace the blanket select/insert/update/delete grant to anon/authenticated/
service_role with privilege-scoped grants: anon/authenticated get select-only
on the public-read tables plus insert-only on bookings/inquiries; full CRUD
is reserved for authenticated (narrowed to the admin UID by RLS) and
service_role. Table grants are now a real second layer of defense instead of
mirroring RLS. Updates two pgTAP assertions whose blocking mechanism moved
from RLS-filtered-empty to grant-level permission-denied, and adds a new
assertion proving anon cannot UPDATE bookings.

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-08 13:08:55 +00:00
belviskhoremk
5e3a77fc70 feat: add booked_slots sync trigger and pgTAP RLS/trigger tests
Includes explicit GRANTs for anon/authenticated/service_role on all
public tables: the Supabase CLI's current default no longer
auto-exposes new tables, so RLS policies from the initial schema were
unreachable without them (every request failed at the privilege check
before RLS was evaluated).
2026-08-08 13:01:08 +00:00
belviskhoremk
6c1a8a92c5 feat: add initial database schema, indexes, and RLS policies 2026-08-08 12:54:42 +00:00
belviskhoremk
d98d66b066 feat: add Supabase CLI scaffold and client SDK setup
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.
2026-08-08 12:46:42 +00:00
belviskhoremk
7d8d89d0fc chore: remove Firebase backend code, replaced by Supabase (see 2026-08-08 spec)
Deleted all Firebase-specific files and directories:
- Configuration: .firebaserc, firebase.json, firestore.* files, storage.rules
- Cloud Functions: functions/ directory (package.json, source, config)
- Tests: firebase-tests/, vitest.rules.config.ts
- Scripts: scripts/seed.ts
- Source: src/lib/firebase.ts and .test.ts
- Environment: .env.example

Removed dependencies:
- firebase (main package)
- firebase-admin, firebase-tools (dev)
- @firebase/rules-unit-testing (dev)

Removed scripts:
- test:rules (Firebase emulator tests)
- seed (Firestore seed script)

Updated package.json via npm install (729 packages removed)
Updated .gitignore (removed functions/ entries)
Updated vite.config.ts (removed firebase-tests and functions exclusions)

All tests, builds, and lints pass cleanly. No Firebase references remain in
the codebase (only in historical spec documents in docs/).

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-08 12:39:39 +00:00
belviskhoremk
0dbdee9f95 Add implementation plan for Phase 2 sub-project A on Supabase 2026-08-08 12:34:57 +00:00
belviskhoremk
de845ef6e5 Add design spec for Phase 2 sub-project A on Supabase (replaces Firebase design) 2026-08-08 12:29:21 +00:00
belviskhoremk
5821b630f6 fix: address final review findings — lint, Node engine, remaining-work doc, create-rule validation 2026-08-05 00:35:50 +00:00
belviskhoremk
9ec17d36f9 fix: exclude functions/ sub-project from the root Vitest run 2026-08-05 00:26:48 +00:00
belviskhoremk
95485ea12b feat: add Firestore seed script for products, services, and default schedule 2026-08-05 00:23:19 +00:00
belviskhoremk
5dff5346fe feat: add onBookingCreated and onInquiryCreated Cloud Functions 2026-08-05 00:19:38 +00:00
belviskhoremk
9c47805f37 feat: add Cloud Functions scaffold with tested email builders 2026-08-05 00:15:45 +00:00
belviskhoremk
ffd31ca1da test: add Firestore/Storage security rules tests
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.
2026-08-05 00:09:57 +00:00
belviskhoremk
88e99ae53e feat: add Firebase project config and security rules 2026-08-05 00:03:30 +00:00
belviskhoremk
257e47c2a1 feat: add Firebase client SDK setup
- Install firebase package
- Add environment variable configuration (.env.example)
- Create firebase.ts module that initializes Firebase app, Firestore, Auth, and Storage
- Add comprehensive test coverage for Firebase initialization with mocked Firebase modules
- Update .gitignore to exclude local environment files
2026-08-04 23:59:59 +00:00
belviskhoremk
ca1146a3a8 Add implementation plan for Phase 2 sub-project A: backend foundation 2026-08-04 23:48:03 +00:00
belviskhoremk
c06891eebb Add design spec for Phase 2 sub-project A: backend foundation 2026-08-04 23:39:33 +00:00
belviskhoremk
42c0cf0f46 Redesign footer to fix layout and add visual hierarchy
The old flex layout with justify-content: space-between pushed its
two children to the far edges on wide screens, leaving a large dead
void in the middle. Replaced with a centered, max-width three-column
grid (brand, contact, navigate) with a script wordmark, gold section
labels, a divider separating it from the banner above, and a
copyright line.
2026-08-04 00:26:35 +00:00
belviskhoremk
3d0a275d67 Add real product, style, portrait, and testimonial photography
Sourced from Pexels (free for commercial use, no attribution
required) to complete the image wiring added in the visual overhaul.
Fills the 18 image slots that were previously deferred (products,
signature styles, About Mira portrait, testimonial avatars).
2026-08-04 00:07:43 +00:00
belviskhoremk
1e9609ce23 Replace placeholder salon rules with Mira's real policy text
Kept in French to match how Mira actually messages clients. Updated
RuleIcon's icon set to match the real policy categories (deposit,
hair prep, extensions, lateness, guests, payment) in place of the
placeholder categories.
2026-08-03 23:48:54 +00:00
belviskhoremk
c4180a90bf fix: address final review findings — code-split Home's 3D bundle, bound card widths, fix Book step transition, cleanup
- 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).
2026-08-03 23:40:32 +00:00
belviskhoremk
585c77ba42 feat: add per-rule icons and staggered scroll-in to Rules page
Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-03 23:15:44 +00:00
belviskhoremk
801c4c028f feat: add step progress indicator and animated transitions to Book
Adds StepProgress component showing 4 labeled booking steps (Service,
Date & Time, Contact, Confirmed) and wires it into Book.tsx alongside
framer-motion AnimatePresence/motion.div step transitions.

Deviates from literal brief in two ways, both to avoid known issues:
- Guards the transition with useReducedMotion() (duration: 0 when
  prefers-reduced-motion is set), matching the fix pattern already
  applied to Home.tsx and Shop.tsx after prior review round-trips.
- Drops AnimatePresence's mode="wait" in favor of the default (sync)
  mode: with mode="wait", the incoming step's DOM doesn't mount until
  the outgoing step's exit animation finishes, which broke existing
  synchronous Testing Library queries in Book.test.tsx (real 250ms
  exit animations in jsdom, no fake timers). Sync mode mounts the new
  step immediately while both fade, preserving test synchronicity.

Also updates Book.test.tsx's confirmation assertion since the old
"You're booked!" heading is gone (page now always shows the shared
"Book an Appointment" heading and StepProgress; only the body swaps).
2026-08-03 23:11:29 +00:00
belviskhoremk
3f82e759cb fix: make Shop's sliding filter pill respect prefers-reduced-motion 2026-08-03 23:07:06 +00:00
belviskhoremk
7cd84f1c66 feat: animate Shop's active category filter with a sliding pill indicator 2026-08-03 23:04:38 +00:00
belviskhoremk
e24c1c7be7 fix: make Home's portrait parallax respect prefers-reduced-motion
The About section's portrait image now checks useReducedMotion() and
disables parallax scroll motion when the user has set OS-level reduced
motion preferences.

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-03 23:02:21 +00:00
belviskhoremk
726893ab87 feat: add portrait with parallax, real product cards, and testimonial avatars to Home 2026-08-03 22:59:25 +00:00
belviskhoremk
c690c8292a feat: render service images with hover-zoom in ServiceCard
Claude-Session: https://claude.ai/code/session
2026-08-03 22:56:12 +00:00
belviskhoremk
8be76f77a4 feat: render product images with hover-zoom in ProductCard 2026-08-03 22:53:28 +00:00
belviskhoremk
12beaa990e feat: replace CSS hero motif with a real WebGL 3D braided-crown scene
Adds Hero3DScene, a procedurally-built rotating braid mesh rendered via
@react-three/fiber, replacing the flat CSS-circle Hero3D component. Falls
back to a static gradient circle under prefers-reduced-motion, matching the
old component's fallback behavior.

Also adds a ResizeObserver mock to the test setup, required by
@react-three/fiber's Canvas (via react-use-measure) in jsdom, which doesn't
implement it natively.
2026-08-03 22:49:24 +00:00
belviskhoremk
6244ef11ce chore: add three, @react-three/fiber, @react-three/drei for the 3D hero 2026-08-03 22:41:39 +00:00
belviskhoremk
36569e224c Add implementation plan for frontend visual overhaul 2026-08-03 22:37:09 +00:00
belviskhoremk
bd81222922 Add design spec for frontend visual overhaul (3D hero, imagery, page polish) 2026-08-03 22:30:56 +00:00
belviskhoremk
c458ace903 Merge branch 'worktree-braids-phase1'
# Conflicts:
#	README.md
#	src/App.test.tsx
#	src/App.tsx
#	src/test/setup.ts
2026-08-03 20:43:58 +00:00
belviskhoremk
9f3e037cdc fix: address final review findings — Hero3D static class, InquiryModal a11y, date guards, shared email validation, README
Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-03 20:40:16 +00:00
belviskhoremk
251a6558fb polish: add responsive breakpoints for nav, home, and shop 2026-08-03 20:30:09 +00:00
belviskhoremk
cbcefbc559 feat: add Home landing page assembling all sections 2026-08-03 20:20:22 +00:00
belviskhoremk
7502c160eb feat: add Rules page 2026-08-03 20:15:56 +00:00
belviskhoremk
c733a5afa9 feat: add Book page with the full mock-data booking flow 2026-08-03 17:56:01 +00:00
belviskhoremk
358b5121f0 fix: make useBooking submit() validate synchronously instead of racing setState's updater 2026-08-03 17:51:45 +00:00
belviskhoremk
a270c33c73 feat: add useBooking hook for the booking flow state machine 2026-08-03 17:49:42 +00:00
belviskhoremk
f4687105bb fix: use globalThis instead of Node-only global in test setup to unblock the TypeScript build
Replace 'global.IntersectionObserver' with 'globalThis.IntersectionObserver' to fix
TS2304 "Cannot find name 'global'" error. globalThis is the standard environment-agnostic
reference that type-checks cleanly in browser-targeted tsconfig. Runtime behavior
identical to global in Node/jsdom contexts.

Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-03 17:39:30 +00:00
belviskhoremk
0795efc421 fix: apply CSS module class for active Shop category filter
Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
2026-08-03 17:37:14 +00:00