# Deploying EduAdvise CRM to Vercel

This runbook deploys the production app: a **Next.js 16 (App Router)** frontend on
**Vercel**, backed by **Supabase** (Postgres + Auth + Storage).

- GitHub repo: `github.com/alliancestreetgoa-lang/eduadvise`
- Supabase project ref: `jbzzwjxshsgwjaxdzgav` (region `ap-southeast-1`)

---

## 1. Prerequisites

- [ ] GitHub repo pushed (already at `github.com/alliancestreetgoa-lang/eduadvise`).
- [ ] A **Supabase** project (this one: ref `jbzzwjxshsgwjaxdzgav`). Note its URL,
      anon key, and service-role key from **Project → Settings → API**.
- [ ] A **Vercel** account with access to the GitHub org/repo.
- [ ] (Optional) A **Resend** account + API key if you want outbound email.
- [ ] (Optional) A custom domain (e.g. `crm.eduadvise.com`).

---

## 2. Supabase setup

### 2a. Apply migrations and seeds (in order)

Run each file in the **Supabase SQL Editor** (or via `psql`), in this exact order.
Migrations live in `db/migrations/`, seeds in `db/seed/`.

**Migrations (0001 → 0014):**

1. `db/migrations/0001_phase1_foundation.sql` — tables + triggers
2. `db/migrations/0002_phase1_rls.sql` — RLS helpers + policies
3. `db/migrations/0003_phase2_leads.sql` — leads schema
4. `db/migrations/0004_phase2_rls.sql` — leads RLS
5. `db/migrations/0005_phase2_rls_fix.sql` — leads RLS fix
6. `db/migrations/0006_phase3_courses.sql` — course catalogue
7. `db/migrations/0007_phase3_rls.sql` — catalogue RLS
8. `db/migrations/0008_phase4_applications.sql` — applications
9. `db/migrations/0009_phase4_rls.sql` — applications RLS
10. `db/migrations/0010_phase5_finance.sql` — finance
11. `db/migrations/0011_phase5_rls.sql` — finance RLS
12. `db/migrations/0012_phase6_marketing.sql` — marketing
13. `db/migrations/0013_phase6_rls.sql` — marketing RLS
14. `db/migrations/0014_phase7_indexes.sql` — performance indexes

**Seeds:**

15. `db/seed/0001_roles_permissions.sql` — 8 roles, permission catalogue, default grants

> Apply migrations **before** seeds. Re-running is generally safe (idempotent where
> possible), but prefer a clean run in order on a fresh project.

### 2b. Bootstrap the first Super Admin

1. **Supabase → Authentication → Users → Add user** (email + password). Copy the new
   user's UUID.
2. Open `db/seed/0002_bootstrap_admin.sql`, replace the placeholder UUID/email with the
   real values, and run it in the SQL Editor. (It creates the Head Office branch, the
   `users` row with the `super-admin` role, and the `user_branches` link.)
   See `db/README.md` for the exact SQL if you prefer to run it inline.

### 2c. Confirm Storage buckets

**Supabase → Storage**. Ensure both buckets exist and are **private** (not public):

- `documents` — application documents
- `marketing` — promotional materials

If missing, create them (Storage → New bucket, "Public bucket" **off**). Access is
mediated server-side through RLS / signed URLs.

---

## 3. Vercel setup (dashboard)

1. **Vercel → Add New → Project → Import** the `alliancestreetgoa-lang/eduadvise` repo.
2. **Framework Preset**: Next.js (auto-detected). Root directory: repo root. Build
   command and output are the Next.js defaults — no overrides needed.
3. **Environment Variables** — add each of the following (Production, and Preview if you
   want preview deploys to work):

   | Variable | Secret? | Where to get it / value |
   |---|---|---|
   | `NEXT_PUBLIC_SUPABASE_URL` | No | Supabase → Settings → API → Project URL (`https://jbzzwjxshsgwjaxdzgav.supabase.co`) |
   | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | No | Supabase → Settings → API → anon/publishable key |
   | `SUPABASE_SERVICE_ROLE_KEY` | **Yes — server-only** | Supabase → Settings → API → service_role key. Never prefix with `NEXT_PUBLIC_`. |
   | `NEXT_PUBLIC_APP_URL` | No | Your deployed URL, e.g. `https://eduadvise.vercel.app` (or the custom domain once set). |
   | `RESEND_API_KEY` | **Yes — server-only** | Resend → API Keys. Optional; leave unset to disable email. |
   | `WHATSAPP_PHONE_NUMBER_ID` | Yes | Optional — reserved for future messaging; leave unset. |
   | `WHATSAPP_ACCESS_TOKEN` | Yes | Optional — reserved; leave unset. |
   | `WHATSAPP_VERIFY_TOKEN` | Yes | Optional — reserved; leave unset. |
   | `MSG91_AUTH_KEY` | Yes | Optional — reserved; leave unset. |
   | `MSG91_SENDER_ID` | Yes | Optional — reserved; leave unset. |

   > The WhatsApp/MSG91 variables are not yet read by the application code — they are
   > placeholders for future SMS/WhatsApp integration and can be omitted.

4. Click **Deploy**. Note the assigned URL (e.g. `https://eduadvise.vercel.app`).
5. If you set `NEXT_PUBLIC_APP_URL` to a guessed value, update it to the real Vercel URL
   now and **redeploy** (env changes require a new build to take effect, since
   `NEXT_PUBLIC_*` values are inlined at build time).

---

## 4. Post-deploy: Supabase Auth URLs

So that login redirects and **password-reset / set-password** links point at the live
site (not `localhost`):

**Supabase → Authentication → URL Configuration:**

- **Site URL**: your production URL, e.g. `https://eduadvise.vercel.app` (or the custom
  domain).
- **Redirect URLs** (add each that applies):
  - `https://eduadvise.vercel.app/**`
  - `https://eduadvise.vercel.app/set-password`
  - `https://eduadvise.vercel.app/auth/**`
  - (and the custom domain equivalents once configured, e.g.
    `https://crm.eduadvise.com/**`)

Save. Verify by triggering a password reset and confirming the email link opens the
deployed `/set-password` page.

---

## 5. Custom domain (optional)

1. **Vercel → Project → Settings → Domains → Add** `crm.eduadvise.com`.
2. At your DNS provider, add the record Vercel shows — typically a `CNAME` for the
   subdomain pointing at `cname.vercel-dns.com` (Vercel displays the exact target).
3. Wait for DNS to propagate and the TLS certificate to issue (Vercel handles certs).
4. Update `NEXT_PUBLIC_APP_URL` to `https://crm.eduadvise.com` and **redeploy**.
5. Add the custom domain to Supabase Auth **Site URL** and **Redirect URLs** (Step 4).

---

## 6. Health checks

A public route handler exists at **`/healthz`** returning `{ status: "ok", time }` (200).

**Caveat:** `middleware.ts` gates all non-public paths, and `/healthz` is **not** in the
middleware allow-list, so an unauthenticated request is **redirected (307) to `/login`**
before reaching the handler. Two options for an uptime monitor:

- **Easiest:** point the monitor at `/healthz` and treat **any 2xx or 3xx** response as
  "up" (a redirect still proves the app is serving requests).
- **Clean 200:** add `/healthz` to the `isPublic` check in
  `lib/supabase/middleware.ts` so the route returns 200 directly. (Not changed here —
  out of scope.)

---

## 7. CLI alternative (Vercel CLI)

Instead of the dashboard import:

```bash
npm i -g vercel          # install the CLI
vercel login             # authenticate

# from the repo root:
vercel                   # first run: links the project, creates a preview deploy
vercel --prod            # promote / deploy to production

# add environment variables (repeat per variable; prompts for the value + targets):
vercel env add NEXT_PUBLIC_SUPABASE_URL
vercel env add NEXT_PUBLIC_SUPABASE_ANON_KEY
vercel env add SUPABASE_SERVICE_ROLE_KEY
vercel env add NEXT_PUBLIC_APP_URL
vercel env add RESEND_API_KEY            # optional

vercel --prod            # redeploy so new env vars take effect
```

`NEXT_PUBLIC_*` variables are inlined at build time, so always redeploy after changing
them.

---

## Quick deploy checklist

- [ ] Migrations `0001`→`0014` applied in order
- [ ] Seed `0001_roles_permissions.sql` applied
- [ ] `0002_bootstrap_admin.sql` run with real UUID/email
- [ ] `documents` and `marketing` buckets exist (private)
- [ ] All env vars set in Vercel (`SUPABASE_SERVICE_ROLE_KEY` + `RESEND_API_KEY` secret)
- [ ] First deploy succeeded; `NEXT_PUBLIC_APP_URL` matches the live URL (redeployed)
- [ ] Supabase Auth Site URL + Redirect URLs point at the live domain
- [ ] Logged in as Super Admin at `/login`
