# X Factor Peptides — Real Backend Setup

This swaps the localStorage layer for a real Postgres + Auth + Storage + Edge Functions backend on Supabase. The static site stays exactly as-is — only the data path changes. Total time end-to-end: ~30 min including waiting for DNS.

## 1. Supabase project (5 min)

1. https://supabase.com → New project → name `xfactor-peptides` → region `us-east-1` → strong DB password (save it).
2. From the project dashboard, copy:
   - **Project URL** → looks like `https://abcdefg.supabase.co`
   - **anon public key** (Settings → API)
   - **service_role key** (Settings → API — never ships to the browser)
3. Paste the first two into `data.js`:
   ```js
   window.XFP_SUPABASE = {
     url: "https://abcdefg.supabase.co",
     anon: "eyJ...long-anon-key...",
     functionsUrl: ""   // leave blank — derived from url
   };
   ```

## 2. Run the migrations (3 min)

In the Supabase SQL editor, paste and run in order:
1. `supabase/migrations/0001_init.sql`
2. `supabase/migrations/0002_admins_and_helpers.sql`
3. `supabase/seed_products.sql` (idempotent — safe to rerun)

Verify in Table Editor that `products` has 20 rows and `lots` has 13.

## 3. Storage bucket for COAs (1 min)

Storage → New bucket → name `coa` → **private**. Upload one PDF per lot, naming each file `<lot_number>.pdf`. Then run:
```sql
update lots set coa_pdf_path = lot_number || '.pdf';
```

## 4. Deploy the edge functions (5 min)

Install Supabase CLI if you haven't: `brew install supabase/tap/supabase` then `supabase login`.

From repo root:
```bash
cd supabase
supabase link --project-ref <your-project-ref>
supabase functions deploy order-create
supabase functions deploy coinbase-webhook
supabase functions deploy coa-signed-url
supabase functions deploy admin-login
```

Then set the secrets:
```bash
supabase secrets set \
  SUPABASE_URL="https://abcdefg.supabase.co" \
  SUPABASE_ANON_KEY="eyJ..." \
  SUPABASE_SERVICE_ROLE_KEY="eyJ..." \
  SITE_URL="https://xfactorpeptidelab.com" \
  COINBASE_COMMERCE_API_KEY="<from coinbase commerce dashboard>" \
  COINBASE_WEBHOOK_SECRET="<shared secret you set in coinbase>" \
  KLAVIYO_API_KEY="<klaviyo private api key>"
```

## 5. Coinbase Commerce (10 min)

1. https://commerce.coinbase.com — sign up with the business email.
2. Settings → Account → API keys → create one. Paste into `COINBASE_COMMERCE_API_KEY`.
3. Settings → Notifications → add webhook:
   `https://<project-ref>.functions.supabase.co/coinbase-webhook`
4. Set the shared secret → paste into `COINBASE_WEBHOOK_SECRET`.
5. Test with the Coinbase test charge flow → confirm `orders.status` flips to `paid`.

## 6. Klaviyo (5 min, optional but recommended)

1. https://klaviyo.com → create account → US region.
2. Account → Settings → API keys → create a Private API Key with `Events:Write`. Paste into `KLAVIYO_API_KEY`.
3. In Klaviyo, create a Flow triggered by metric `Order Confirmed`. Use the HTML you'll find in `/assets/emails/order-confirmation.html` as the template.
4. Repeat for `Shipped` (`/assets/emails/shipping.html`) and `Refund Processed`.

## 7. Card processor (1-3 weeks — start now in parallel)

RUO peptides get auto-rejected by Stripe, Square, PayPal, and Shopify Payments. The two viable paths:

- **PaymentCloud** — https://paymentcloudinc.com — fill the high-risk merchant application. Documents you'll need: EIN, void check from the Truist deposit account, formation docs, processing history (or letter explaining you're new), 3 months bank statements. Approval typically 5-10 business days.
- **Easy Pay Direct** — https://easypaydirect.com — similar process, often paired with `NMI` gateway. Slightly faster underwriting but smaller volumes capped initially.

When approved, ask the rep for their gateway's REST API docs. The drop-in card endpoint goes in a new `card-charge` edge function (template ready to write once you have the API keys).

## 8. Make yourself the admin (1 min)

In the Supabase SQL editor:
```sql
-- 1) create the auth user
insert into auth.users (email, encrypted_password, email_confirmed_at)
values ('you@xfactorpeptidelab.com', crypt('strong-password-here', gen_salt('bf')), now());

-- 2) link to admins table
insert into admins (auth_uid, email, role)
select id, email, 'owner' from auth.users where email = 'you@xfactorpeptidelab.com';
```

Then log in at `/admin.html` with those credentials. The frontend already calls `XFP_API.adminLogin()` — no changes needed.

## 9. RLS sanity check (1 min)

```sql
-- These should return data (public read):
select count(*) from products where active;        -- ~20
select count(*) from lots where status<>'recalled';-- ~13
-- These should return empty when logged out (write-blocked):
select count(*) from orders;                       -- 0 unless your auth.uid matches
```

## 10. What's still in localStorage (intentionally)

- Cart contents (`xfp_cart`) — should stay client-side until checkout commit
- Recently-viewed products (`xfp_recent`) — UX nicety
- Cookie consent state — required to be client-side

Everything else (orders, customers, COAs, attestations, KYC docs, email subscribers, wholesale leads, reviews, discount usage, admin sessions, inventory) flows through the real backend.

## 11. What you still need outside the site

- Truist business checking account → connected to your card processor
- Custom domain DNS → A records to `185.199.108.153 / 109 / 110 / 111` and `CNAME` file
- Real attorney scan of `/legal/` hub
- Real founder photo for `/about.html`
- Real research@ and wholesale@ inbox routing (Google Workspace, ~$6/user/mo)

That's it. After step 7 lands you're processing live orders.
