# Deployment — Nuweiba Camps

Production target: **Ubuntu VPS + aaPanel**, MySQL 8, Nginx reverse proxy, PM2 (or Docker).

## 1. Environment
Create `.env` (never commit it):
```
DATABASE_URL=mysql://user:pass@127.0.0.1:3306/nuweiba
AUTH_SECRET=<64+ random chars>
NODE_ENV=production
# Optional integrations (leave unset to keep the feature dormant):
# STRIPE_SECRET_KEY=...            # F6 live card payments
# SMTP_URL=...                     # F16 email delivery
# WHATSAPP_TOKEN=... META_APP_SECRET=...  # F12–F14
```
> ⚠️ Rotate any secret ever shared in plaintext (including the old server's root SSH key and the legacy WhatsApp/Meta/OpenAI tokens). Never import old secrets.

## 2. Database
```
npm run db:migrate          # apply all Drizzle migrations
```
Charset must be `utf8mb4` (Arabic). Import legacy content only if needed:
`npm run db:import -- ./old-data.json`.

## 3a. Run with PM2 (simple)
```
npm ci
npm run build
pm2 start ecosystem.config.cjs
pm2 save && pm2 startup
```

## 3b. Run with Docker (isolated)
```
docker build -t nuweiba-camps .
docker run -d --name nuweiba -p 3000:3000 --env-file .env \
  -v /srv/nuweiba/uploads:/app/public/uploads nuweiba-camps
```
Mount a volume for `/app/public/uploads` so receipts/images survive restarts
(or switch the storage adapter in `src/server/storage.ts` to S3).

## 4. Nginx
Use `deploy/nginx.conf` (adjust `server_name` + the uploads `alias` path), then
issue TLS via aaPanel/Certbot and enable the 80→443 redirect.

## 5. Scheduled iCal sync (F10)
Add a cron that hits the sync, e.g. every 15 min:
```
*/15 * * * * curl -fsS -X POST https://beta.nuweibacamps.com/api/trpc/channels.syncAll \
  -H "content-type: application/json" -d '{"0":{"json":null}}' -b "nuweiba_session=<service-token>"
```
(or call `syncAll()` from a small server cron script).

## 6. Health
- Security headers are set in `next.config.ts`.
- Rate limiting is in-memory (single instance). For multiple instances, back it
  with Redis in `src/lib/rate-limit.ts`.
