# Supabase setup (Khady Hair Braiding)

Follow these steps once per environment (staging / production).

## 1. Create a project

1. Go to [supabase.com/dashboard](https://supabase.com/dashboard) and create a project.
2. Wait until the database is ready. Note the **region** you chose.

## 2. Run the database schema

1. In the Supabase dashboard: **SQL Editor** → **New query**.
2. Paste the full contents of `supabase/schema.sql` from this repo and run it.
3. If your `bookings` table already existed from an older version, also run `supabase/migrations/20260430140000_booking_payment_fields.sql` (or the `ALTER TABLE` comments at the bottom of `schema.sql`) so payment columns exist.

This creates:

- `public.bookings` with Row Level Security (RLS)
- Policies so **anon** can **insert** (public booking form) and **select** (admin dashboard — see security note below)
- Storage bucket **`booking-photos`** (private) and an **anon insert** policy for paths under a UUID folder

## 3. API keys → website config

1. Dashboard → **Project Settings** → **API**.
2. Copy **Project URL** and the **anon public** key (not the `service_role` key).
3. Put them **only** in `js/supabase-config.local.js` (that file is **gitignored** so keys are not committed). Keep `js/supabase-config.js` empty in git — it is the safe default for the repo.

   Use the same shape as in that file’s comments, for example:

   ```js
   (function () {
     var o = window.__KHADY_SUPABASE;
     if (!o) return;
     o.url = "https://YOUR_PROJECT_REF.supabase.co";
     o.anonKey = "YOUR_ANON_PUBLIC_KEY";
   })();
   ```

   On a fresh clone, create `js/supabase-config.local.js` if it is missing (you can start from `js/supabase-config.example.js` and paste into the pattern above).

4. Reload `booking.html` and submit a test booking. You should see a row in **Table Editor** → `bookings` and files under **Storage** → `booking-photos` if photos were attached.

**If you see `new row violates row-level security policy for table "bookings"`:** your policies may be fine but **`anon` still needs `GRANT`** on the table. Run **`supabase/fix_bookings_anon_grants.sql`** once in the SQL Editor, then try the booking again.

## 4. Hosting the static site

- Serve the site over **HTTPS** (recommended). `file://` may block or restrict the Supabase JS client and uploads.
- If you use a separate domain, add it under **Authentication** → **URL configuration** only if you later enable Supabase Auth (not required for anon + RLS as shipped).

## 5. Security (important)

The included RLS policy **allows anyone with the anon key to read all bookings** so the simple HTML admin dashboard can query data. That is fine for a private admin URL and a key kept off the public internet, but it is **not** suitable for a fully public anon key embedded in a high-traffic marketing site without further hardening.

**Production hardening options:**

- Replace anon read with **Supabase Auth** (e.g. staff login) and RLS `to authenticated`, or
- Move reads to a **Edge Function** that checks a secret / session and returns only what admins need.

## 6. CLI (optional)

This repo includes `supabase/config.toml` from `supabase init`. To link your remote project:

```bash
npx supabase login
npx supabase link --project-ref YOUR_PROJECT_REF
```

You can use `supabase db push` only if you adopt migrations as the source of truth; today the canonical one-shot script is `schema.sql` in the SQL Editor.

## 7. Stripe Checkout (deposit)

The booking page saves the row in Supabase, then calls an **Edge Function** that creates a **Stripe Checkout Session** (your **secret** key never touches the browser).

### A. Stripe Dashboard

1. [Stripe Dashboard](https://dashboard.stripe.com) → **Developers** → **API keys** — copy **Secret key** (`sk_test_…` or `sk_live_…`).
2. **Developers** → **Webhooks** → **Add endpoint**  
   - URL: `https://<YOUR_PROJECT_REF>.supabase.co/functions/v1/stripe-webhook`  
   - Events: `checkout.session.completed`  
   - Copy the **Signing secret** (`whsec_…`).

### B. Supabase secrets

In Supabase: **Project Settings** → **Edge Functions** → **Secrets** (or CLI `supabase secrets set`), add:

| Name | Value |
|------|--------|
| `STRIPE_SECRET_KEY` | `sk_test_…` or `sk_live_…` |
| `STRIPE_WEBHOOK_SECRET` | `whsec_…` from the webhook above |

`SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` are available to functions automatically on hosted projects.

### C. Deploy Edge Functions

From this repo (with CLI logged in and project linked):

```bash
npx supabase functions deploy create-checkout-session
npx supabase functions deploy stripe-webhook
```

`supabase/config.toml` already sets `verify_jwt = true` for `create-checkout-session` (uses the same anon JWT as the site) and `verify_jwt = false` for `stripe-webhook` (Stripe calls it with a Stripe signature, not Supabase JWT).

### D. Client flags

- `js/stripe-config.js` — `depositCheckoutEnabled: true` (default) turns on “save booking → redirect to Checkout”.
- `js/stripe-config.local.js` — optional; set `depositCheckoutEnabled = false` to skip Checkout while testing.

### E. Flow

1. Guest completes the form → booking row inserted → `create-checkout-session` loads the row, creates Checkout for **deposit** in cents, stores `stripe_checkout_session_id`, returns `url` → browser redirects to Stripe.
2. After payment, Stripe sends `checkout.session.completed` → `stripe-webhook` sets `payment_status` to `deposit_paid` and saves payment intent id.
3. User returns to `booking.html?paid=1` (or `?canceled=1`).

If the Edge Function is missing or Stripe secrets are not set, the booking **still saves** and the page shows a message that online payment could not start.
