# BT Web Group — Submissions Admin

Two services:
- `api/` — Express + SQLite. Receives checkout submissions, geolocates by IP, emails via SendGrid, serves the admin panel data.
- `web/` — Vite + React admin panel.

## API setup
```bash
cd api
cp .env.example .env        # fill JWT_SECRET, SENDGRID_API_KEY, ALLOWED_ORIGIN
npm install
npm run seed                # creates admin@btwebgroup.com / admin123 + default settings
npm start                   # http://localhost:4000
```
First login forces a password change (the seed password is intentionally weak).

`npm start` also seeds on boot, so `npm run seed` is only needed if you want to seed without starting the server.

### Geo-IP (optional but recommended)
Download MaxMind **GeoLite2-City.mmdb** (free account at maxmind.com) and place it at `api/data/GeoLite2-City.mmdb` (or set `GEOIP_DB`). Without it, submissions still save; location fields are left blank.

### Email
Uses the SendGrid HTTP API. Set `SENDGRID_API_KEY` in `.env` and a **verified sender** as `from_email` in the panel Settings. Edit templates + the admin-notify address in Settings. Without a key, submissions still save; emails are skipped (failures never block a lead).

## Web setup
```bash
cd web
echo "VITE_API_URL=http://localhost:4000" > .env   # point at the API origin
npm install
npm run dev          # http://localhost:5173
npm run build        # production build -> web/dist
```

## Connecting checkout.html (production)
In WordPress/Beaver Builder, before the checkout `<script>`, define the API origin:
```html
<script>window.BTW_API_URL = "https://api.yourdomain.com";</script>
```
Set the API's `ALLOWED_ORIGIN` to `https://btwebgroup.com` so CORS permits the POST.

## Security notes
- Passwords are bcrypt-hashed; sessions are JWTs signed with `JWT_SECRET`.
- The CSV download link passes the JWT as a `?t=` query param (an `<a href>` cannot send an `Authorization` header). Query-string tokens can leak via access logs, browser history, and `Referer` headers — keep the JWT TTL short (the API currently issues 12h tokens; lower `expiresIn` in `src/middleware/auth.js` if you expose the panel beyond a trusted internal network) and serve the panel over HTTPS only.
- `TRUST_PROXY=true` configures Express to trust a single proxy hop (nginx/Cloudflare). If the deployment chains multiple proxies, set the hop count accordingly in `src/server.js` (e.g. `app.set("trust proxy", 2)`).
- The public `POST /api/submissions` endpoint is rate-limited (20/min/IP) and CSV uploads are capped at 5MB, CSV-only. Uploaded files are stored outside any web root and served only through the authenticated download route.
- Runtime state (`api/data/` — the SQLite DB, uploads, the GeoLite2 file) and all `.env` files are git-ignored.

## Tests
```bash
cd api && npm test
cd web && npm test
```
