# Deploy Checklist — `takedowns.vesamuni.com`

> One-pager for moving the rebranded **takedowns** app onto its new domain on your existing cPanel.
> Total time: ~25 min (most of it is DNS + AutoSSL).
> Pre-flight: you should have `ncii-shield-deploy.zip` from the local build (v1.6, 2.31 MB).

---

## 0. Pre-flight (5 min, on your laptop)

- [ ] Open `ncii-shield-deploy.zip`, confirm it contains: `app.js`, `package.json`, `public/`, `routes/`, `models/`, `services/`, `jobs/`, `middleware/`, `config/`, `data/ncii.sqlite`, `scripts/`, `.env` (or `.env.example`), but **NOT** `.htaccess` (that's intentional — keep reading).
- [ ] Confirm Stripe webhook URL field is editable (you'll change it in step 8).
- [ ] Have Resend dashboard open in a tab (step 9).

---

## 1. DNS (5 min)

In your DNS provider for **`vesamuni.com`**:

| Type  | Name        | Value                              | TTL   |
| ----- | ----------- | ---------------------------------- | ----- |
| CNAME | `takedowns` | `vesamuni.com.` (or cPanel server) | 3600  |

A-record also works if your cPanel IP is static. CNAME is easier to maintain.

Verify before moving on:

```bash
nslookup takedowns.vesamuni.com
# should resolve to the same host as vesamuni.com
```

---

## 2. cPanel — Add-on domain (3 min)

**cPanel → Domains → Add-on Domains**

| Field               | Value                              |
| ------------------- | ---------------------------------- |
| New domain name     | `takedowns.vesamuni.com`           |
| Subdomain           | (auto-fills, leave it)             |
| Document root       | `public_html/takedowns.vesamuni.com` |

cPanel creates the vhost and the empty `public_html/takedowns.vesamuni.com/` directory.

---

## 3. TLS — AutoSSL (5 min, then wait)

**cPanel → SSL/TLS Status → Run AutoSSL** for `takedowns.vesamuni.com`.

Status goes from *“awaiting DNS”* → *“cert issued”* in 2–10 min. Don't move on until the cert is live.

Verify:

```bash
curl -I https://takedowns.vesamuni.com
# expect: HTTP/2 200 (or 308/404 from Apache default doc — that's fine, it's the cert we needed to confirm)
```

---

## 4. Upload the deploy zip (3 min)

**Important:** cPanel File Manager treats `takedowns.vesamuni.com/` as "home" — files you upload via the UI land in `/home/<user>/takedowns.vesamuni.com/`, NOT in `~/`.

**cPanel → File Manager → `takedowns.vesamuni.com/`** (the empty dir from step 2)

- [ ] Upload `ncii-shield-deploy.zip` here
- [ ] Right-click → **Extract** → unzip into this same folder (overlap OK, it's empty)

Sanity-check from SSH (paths diverge between UI and SSH):

```bash
ls /home/<user>/takedowns.vesamuni.com/
# expect: app.js  package.json  public/  ...  .env  data/
```

---

## 5. `.env` (2 min)

Edit the deployed `.env` on the server. **Critical keys**:

```ini
PUBLIC_BASE_URL=https://takedowns.vesamuni.com
APP_URL=https://takedowns.vesamuni.com
COOKIE_DOMAIN=takedowns.vesamuni.com
SESSION_COOKIE_SECURE=true
NODE_ENV=production
PORT=3000                  # or whatever cPanel "Setup Node.js App" mapped
```

Everything else (DB path, Stripe keys, Scrape.do, MiniMax, Resend API key, SMTP) carries over from your existing `.env` — copy them across too.

---

## 6. `.htaccess` — generate fresh, don't reuse the old one (2 min)

The repo's `.htaccess` is a **template** with `yourcpanel` placeholders — that's why `build-deploy-zip.py` strips it from the zip. You must let cPanel build a real one against the new domain.

**cPanel → Setup Node.js App → click your app entry (which now points at `takedowns.vesamuni.com/`)**

- [ ] Click **"Restart"** — cPanel regenerates a real `.htaccess` and `passenger.log` for the new domain
- [ ] If the app isn't there yet: **"Create Application"** → Application root = `takedowns.vesamuni.com/`, Application URL = `takedowns.vesamuni.com`, Application startup file = `app.js`, Passenger log file = `logs/node.log`. Then **Restart**.

Verify `.htaccess` looks right (it should reference the new domain, not your old one):

```bash
cat /home/<user>/takedowns.vesamuni.com/.htaccess
# expect: PassengerAppRoot etc. with takedowns.vesamuni.com
```

---

## 7. Install + restart (3 min)

From SSH:

```bash
cd /home/<user>/takedowns.vesamuni.com
npm ci --omit=dev      # production-only deps, fresh native modules for el8
```

Then force a clean restart — **`touch tmp/restart.txt` does NOT work on LiteSpeed + lsnode**.
Kill the worker and let LiteSpeed respawn it:

```bash
pgrep -af 'lsnode:takedowns.vesamuni.com'    # find the pid
kill -9 <pid>
sleep 8
pgrep -af 'lsnode:takedowns.vesamuni.com'    # confirm a NEW pid appeared
```

Watch the log:

```bash
tail -f /home/<user>/takedowns.vesamuni.com/logs/node.log
# expect: "takedowns listening on :3000" or similar boot line
```

> **Gotcha**: if you `unzip` the zip over a running DB, the new `data/ncii.sqlite` gets a new inode while the old worker still holds the old one — you'll get "INVALID_CREDENTIALS" on routes even with correct password. Killing the worker (above) after replacing any DB file fixes it.

---

## 8. Stripe webhook (2 min)

**Stripe Dashboard → Developers → Webhooks → your endpoint → Edit**

URL change:

```
OLD: https://takedowns.vesamuni.com/webhook/stripe
NEW: https://takedowns.vesamuni.com/webhook/stripe
```

Send a test event from the Stripe dashboard. Expect a `200` in the log within 1 sec.

---

## 9. Resend sender domain (5 min)

**Resend Dashboard → Domains → Add Domain → `takedowns.vesamuni.com`**

Add the DKIM / SPF records they give you (usually 3 CNAMEs + 1 TXT) to your DNS.

While you're verifying (Resend takes a few minutes), update `.env`:

```ini
EMAIL_FROM="takedowns <noreply@takedowns.vesamuni.com>"
```

---

## 10. Smoke test (3 min)

Walk this list top to bottom:

- [ ] `https://takedowns.vesamuni.com/` — landing page, new wordmark top-left, hero illustration on the right
- [ ] Browser tab favicon — small indigo→coral ring with slash (no shield icon)
- [ ] All asset URLs in the HTML use `takedowns.vesamuni.com` (View Source → search `takedowns.vesamuni.com` should be **0 results**)
- [ ] Sign in as the superadmin (`admin@yourdomain.com`) → `/admin/`
- [ ] `/admin/user/1` — Nisali's two-column detail page loads at a real URL (no modal)
- [ ] Dashboard `/dashboard/` — 3 outcome cards, **"Actions ▾"** button on each takedown row (no `⋯`)
- [ ] Trigger a Stripe test event → check `node.log` for the webhook receipt
- [ ] Trigger an email test → check the message arrives `from: noreply@takedowns.vesamuni.com`

---

## 11. Decommission the old domain (next week, optional)

Don't rush this — DNS caches are everywhere.

1. Set `takedowns.vesamuni.com` to redirect → `takedowns.vesamuni.com` (301).
2. Wait 7 days for the redirect to propagate through caches and clients.
3. Then you can remove the old add-on domain in cPanel.

Until then both URLs work; the old one redirects to the new one.

---

## Rollback

If something's wrong after step 7:

```bash
cd /home/<user>/
mv takedowns.vesamuni.com takedowns.vesamuni.com.broken
unzip /path/to/ncii-shield-deploy.zip -d takedowns.vesamuni.com   # fresh
cd takedowns.vesamuni.com && npm ci --omit=dev
# cPanel → Setup Node.js App → Restart
```

The old `takedowns.vesamuni.com` keeps running the previous code throughout, so you're never down.

---

**Estimated total:** ~30 min, most of it waiting on AutoSSL + DNS.
**Reversible:** Yes — keep the old `takedowns.vesamuni.com` add-on untouched until step 11.
