# SiteBuilder SaaS — Deployment Guide

This document covers deploying the SiteBuilder SaaS application to your server,
configuring all integrations (Stripe, GoDaddy, WHM/cPanel), and setting up
the reverse proxy so the app is accessible via your domain.

## Table of Contents

1. [System Requirements](#1-system-requirements)
2. [Quick Start (Automated Setup)](#2-quick-start-automated-setup)
3. [Manual Step-by-Step Setup](#3-manual-step-by-step-setup)
4. [Configuration: Stripe](#4-configuration-stripe)
5. [Configuration: GoDaddy Domain API](#5-configuration-godaddy-domain-api)
6. [Configuration: WHM/cPanel API](#6-configuration-whmcpanel-api)
7. [Configuration: OpenAI (Optional)](#7-configuration-openai-optional)
8. [Reverse Proxy Setup](#8-reverse-proxy-setup)
9. [SSL/HTTPS Setup](#9-sslhttps-setup)
10. [Stripe Webhook Configuration](#10-stripe-webhook-configuration)
11. [Admin Settings (Web UI)](#11-admin-settings-web-ui)
12. [PM2 Process Management](#12-pm2-process-management)
13. [The Full Customer Workflow](#13-the-full-customer-workflow)
14. [Troubleshooting](#14-troubleshooting)

---

## 1. System Requirements

- **Node.js**: 20 LTS (v20.x) — required
- **npm**: 10.x+ (comes with Node.js 20)
- **OS**: Linux (Ubuntu/Debian/CentOS/RHEL) — tested on Debian 12
- **RAM**: Minimum 1GB, recommended 2GB+
- **Disk**: 500MB for the app + dependencies
- **OpenSSL**: For generating encryption keys (usually pre-installed)
- **SQLite**: Bundled with Prisma (no separate install needed)

### For the full customer hosting workflow:
- **WHM/cPanel**: Root or reseller access with API token creation rights
- **GoDaddy Developer Account**: With a Personal Access Token (PAT) for domain purchasing
- **Stripe Account**: For subscription payments
- **Dedicated IP or nameservers**: For assigning to customer domains

---

## 2. Quick Start (Automated Setup)

After uploading and extracting the package to your server:

```bash
cd sitebuilder
chmod +x setup.sh
./setup.sh
```

The setup script will:
1. Install all npm dependencies
2. Generate encryption keys and JWT secret automatically
3. Create the `.env` configuration file
4. Create the SQLite database
5. Seed the admin user (admin@instantsitz.com / ChangeMeNow2025!)
6. Build the Next.js app for production
7. Install PM2 for process management
8. Start the app on port 3000

After setup completes, edit the `.env` file to fill in your credentials
(Stripe, GoDaddy, WHM), then restart:

```bash
pm2 restart sitebuilder
```

---

## 3. Manual Step-by-Step Setup

If you prefer to set up manually instead of using the setup script:

### Step 1: Install Node.js 20 LTS

```bash
# Ubuntu/Debian
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

# Verify
node --version   # should show v20.x
npm --version    # should show 10.x
```

### Step 2: Install dependencies

```bash
cd sitebuilder
npm install
```

### Step 3: Generate encryption keys

```bash
# Generate two random keys (run twice)
openssl rand -hex 32    # → use for ENCRYPTION_KEY
openssl rand -hex 32    # → use for JWT_SECRET
```

### Step 4: Create .env file

```bash
cp .env.production .env
```

Edit `.env` and fill in the values:
- `ENCRYPTION_KEY` — paste the first key from step 3
- `JWT_SECRET` — paste the second key from step 3
- `APP_BASE_URL` — your server's public URL (e.g., `https://instantsitz.com`)
- `ADMIN_EMAIL` / `ADMIN_PASSWORD` — your admin login credentials
- All Stripe, GoDaddy, and WHM credentials (see sections below)

### Step 5: Create the database

```bash
npx prisma db push
```

This creates the SQLite database at `prisma/dev.db` with all tables.

### Step 6: Seed the admin user

```bash
npm run db:seed
```

This creates the admin user with the email and password from your `.env` file.

### Step 7: Build for production

```bash
npm run build
```

This creates the optimized production build in the `.next/` directory.

### Step 8: Install PM2

```bash
npm install -g pm2
```

### Step 9: Start the app

```bash
pm2 start ecosystem.config.js
pm2 save
```

The app is now running on port 3000.

### Step 10: Enable PM2 on boot

```bash
sudo env PATH=$PATH:$(dirname $(which node)) pm2 startup systemd -u $(whoami) --hp $HOME
pm2 save
```

---

## 4. Configuration: Stripe

Stripe handles subscription payments. When a customer pays, the webhook
activates their subscription and triggers the domain purchase + cPanel
account creation flow.

### Get your API keys:

1. Log in to [Stripe Dashboard](https://dashboard.stripe.com)
2. Go to **Developers** → **API Keys**
3. Copy the **Secret key** (starts with `sk_live_` or `sk_test_`)
4. Copy the **Publishable key** (starts with `pk_live_` or `pk_test_`)

### Create a recurring price:

1. Go to **Products** → **Add product**
2. Name it "SiteBuilder Monthly" (or similar)
3. Set pricing to **Recurring**, monthly, enter your price (e.g., $29.00/month)
4. Save the product
5. Copy the **Price ID** (starts with `price_`)

### Fill in .env:

```
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxx
STRIPE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxx
STRIPE_PRICE_ID=price_xxxxxxxxxxxxx
```

### Webhook secret:

See [Section 10: Stripe Webhook Configuration](#10-stripe-webhook-configuration)

---

## 5. Configuration: GoDaddy Domain API

GoDaddy's API is used to purchase domains for customers and manage nameservers
and auto-renew settings.

### Create a GoDaddy PAT (Personal Access Token):

1. Go to [GoDaddy Developer Portal](https://developer.godaddy.com)
2. Sign in with your GoDaddy account
3. Go to **API Keys** → **Create API Key**
4. Select **Personal Access Token (PAT)**
5. Set the environment to **Production**
6. Grant the following scopes:
   - `domains.domain:read` — check availability
   - `domains.domain:write` — purchase domains
   - `domains.domain:manage` — set nameservers, auto-renew
7. Copy the PAT token

### Set your nameservers:

The nameservers that purchased domains will be pointed to. These should be
the nameservers of your WHM/cPanel server.

```
GODADDY_PAT=your_pat_token_here
GODADDY_NAMESERVERS=["ns1.yourserver.com","ns2.yourserver.com"]
```

You can also configure the GoDaddy PAT and nameservers via the Admin Settings
UI in the web app (Settings page) — these will override the .env values.

---

## 6. Configuration: WHM/cPanel API

The WHM API is used to create cPanel hosting accounts for customers after
they purchase a domain, and to suspend accounts when subscriptions are cancelled.

### Create a WHM API Token:

1. Log in to **WHM** (usually at `https://your-server:2087`)
2. Go to **Server Configuration** → **Tweak Settings**
3. Ensure **API Tokens** are enabled
4. Go to **Development** → **Manage API Tokens** (or search "API Token" in WHM search)
5. Click **Generate Token**
6. Name it "SiteBuilder"
7. Grant the following permissions:
   - `createacct` — create cPanel accounts
   - `suspendacct` — suspend accounts
   - `unsuspendacct` — unsuspend accounts
   - `accountsummary` — view account details
8. Copy the token

### Create a hosting package/plan:

1. In WHM, go to **Packages** → **Add a Package**
2. Name it (e.g., "sitebuilder_default")
3. Set the resource limits (disk space, bandwidth, etc.)
4. Save

### Fill in .env:

```
WHM_API_URL=https://your-server.com:2087
WHM_API_TOKEN=your_whm_api_token_here
WHM_USERNAME=root
WHM_PACKAGE_NAME=sitebuilder_default
WHM_IP_ADDRESS=your.server.ip.address
```

- **WHM_API_URL**: The URL to your WHM instance (include the `:2087` port)
- **WHM_API_TOKEN**: The token you generated above
- **WHM_USERNAME**: Your WHM username (usually `root` for root access)
- **WHM_PACKAGE_NAME**: The package/plan name you created
- **WHM_IP_ADDRESS**: The IP address to assign to new accounts (leave blank for shared IP)

You can also configure these via the Admin Settings UI.

---

## 7. Configuration: OpenAI (Optional)

OpenAI is used for AI content generation (GPT-4) and AI image generation (DALL-E 3).
If not configured, the app uses built-in mock generators that produce sample content.

### Get an API key:

1. Go to [OpenAI Platform](https://platform.openai.com)
2. Create an account and add billing
3. Go to **API Keys** → **Create new secret key**
4. Copy the key

### Fill in .env:

```
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
```

You can also set this via the Admin Settings UI without restarting the server.

---

## 8. Reverse Proxy Setup

The app runs on port 3000. To make it accessible on port 80/443 (standard HTTP/HTTPS),
configure a reverse proxy.

### Option A: Apache (with mod_proxy)

If your server uses Apache (common with cPanel servers):

1. Enable required modules:
```bash
sudo a2enmod proxy proxy_http proxy_wstunnel rewrite ssl
sudo systemctl restart apache2
```

2. Create a virtual host configuration:
```apache
# /etc/apache2/sites-available/sitebuilder.conf
<VirtualHost *:80>
    ServerName instantsitz.com
    ServerAlias www.instantsitz.com

    # Proxy to the Next.js app
    ProxyPreserveHost On
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

    # WebSocket support (needed for Next.js hot reload in dev, optional in prod)
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteRule /(.*) ws://localhost:3000/$1 [P,L]

    ErrorLog ${APACHE_LOG_DIR}/sitebuilder_error.log
    CustomLog ${APACHE_LOG_DIR}/sitebuilder_access.log combined
</VirtualHost>
```

3. Enable the site:
```bash
sudo a2ensite sitebuilder
sudo systemctl reload apache2
```

### Option B: Nginx

1. Install nginx:
```bash
sudo apt-get install nginx
```

2. Create a server block:
```nginx
# /etc/nginx/sites-available/sitebuilder
server {
    listen 80;
    server_name instantsitz.com www.instantsitz.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}
```

3. Enable the site:
```bash
sudo ln -s /etc/nginx/sites-available/sitebuilder /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```

### Important for cPanel servers:

If your server is a cPanel server itself, Apache virtual hosts may be managed
by cPanel. In that case, you can create a **custom proxy domain** via:

1. WHM → **Account Functions** → **Create Account** (for the SaaS app domain)
2. Or add the ProxyPass directives to the domain's `.htaccess` or via
   cPanel's **Apache Include Editor**

Alternatively, you can use a separate non-cPanel port and point DNS directly.

---

## 9. SSL/HTTPS Setup

### With Let's Encrypt (certbot):

```bash
# Install certbot
sudo apt-get install certbot python3-certbot-nginx   # for nginx
# or
sudo apt-get install certbot python3-certbot-apache   # for apache

# Get SSL certificate
sudo certbot --nginx -d instantsitz.com -d www.instantsitz.com
# or
sudo certbot --apache -d instantsitz.com -d www.instantsitz.com
```

Certbot will automatically configure your reverse proxy for HTTPS and set up
auto-renewal.

### With cPanel's AutoSSL:

If using cPanel, AutoSSL can provision free SSL certificates. Go to:
- WHM → **SSL/TLS** → **Manage AutoSSL**

After SSL is set up, update your `.env`:
```
APP_BASE_URL=https://instantsitz.com
```

Then restart:
```bash
pm2 restart sitebuilder
```

---

## 10. Stripe Webhook Configuration

The Stripe webhook is how Stripe notifies your app about payment events
(successful payments, cancellations, etc.). This triggers the domain purchase
and cPanel account creation.

### Create a webhook endpoint:

1. Go to [Stripe Dashboard](https://dashboard.stripe.com) → **Developers** → **Webhooks**
2. Click **Add endpoint**
3. Set the URL to: `https://instantsitz.com/api/webhooks/stripe`
   (Replace with your actual domain)
4. Select events to listen for:
   - `checkout.session.completed`
   - `customer.subscription.updated`
   - `customer.subscription.deleted`
5. Click **Add endpoint**
6. Copy the **Signing secret** (starts with `whsec_`)

### Fill in .env:

```
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx
```

### Webhook fallback (polling):

If webhooks can't reach your server (firewall, DNS propagation, etc.), the app
has a built-in polling fallback. After a customer completes checkout, the site
page automatically polls Stripe's API to check the payment status and activate
the subscription. This means the flow works even if webhooks are delayed or
unreachable — but webhooks are still recommended for real-time updates
(cancellations, payment failures, etc.).

---

## 11. Admin Settings (Web UI)

After logging in as admin, you can configure many settings via the web UI
without editing `.env` or restarting the server:

1. Log in at `https://instantsitz.com/login`
   - Email: `admin@instantsitz.com`
   - Password: `ChangeMeNow2025!` (or whatever you set in .env)

2. Go to **Settings** (admin only)

3. Configure:
   - **OpenAI API Key** — for AI content/image generation
   - **GoDaddy PAT** — for domain purchasing
   - **GoDaddy Nameservers** — JSON array, e.g. `["ns1.instantsitz.com","ns2.instantsitz.com"]`
   - **Monthly Price** — subscription price in dollars
   - **WHM Settings** — API URL, token, username, package name, IP

4. **Change your admin password immediately** after first login!

---

## 12. PM2 Process Management

PM2 manages the Node.js process, keeping it running and auto-restarting on crash.

### Common commands:

```bash
# Check status
pm2 status

# View logs (real-time)
pm2 logs sitebuilder

# View last 100 lines of logs
pm2 logs sitebuilder --lines 100

# Restart the app (after .env changes or code updates)
pm2 restart sitebuilder

# Stop the app
pm2 stop sitebuilder

# Delete the app from PM2
pm2 delete sitebuilder

# Start the background worker too
pm2 start ecosystem.config.js
```

### The ecosystem config:

The `ecosystem.config.js` file defines two processes:
- **sitebuilder** — the Next.js server on port 3000
- **sitebuilder-worker** — a background job processor (for export/deploy jobs)

Both auto-restart on crash and have memory limits set.

### Updating the app:

When you upload new code or change configuration:

```bash
cd sitebuilder
npm install              # if dependencies changed
npx prisma db push       # if schema changed
npm run build            # rebuild
pm2 restart all          # restart both processes
```

---

## 13. The Full Customer Workflow

Here's the complete flow from a customer's perspective:

### 1. Sign Up
- Customer goes to `https://instantsitz.com/register`
- Creates an account with email + password

### 2. Design Their Site
- Customer goes through the 4-step onboarding wizard:
  - Step 1: Business basics (name, industry, keywords)
  - Step 2: Domain selection (choose a domain, check availability)
  - Step 3: Branding (colors, fonts, logo upload)
  - Step 4: Contact info + review
- AI generates content and images for the site
- Customer can preview and make edits

### 3. Preview & Review
- Customer previews their site
- Can edit content, change colors, upload logo, regenerate AI content
- Free preview includes 2 AI revision generations

### 4. Pay Subscription
- Customer clicks "Subscribe" / "Publish"
- Redirected to Stripe Checkout
- Enters payment info and completes payment
- Redirected back to the site dashboard
- The app polls Stripe to confirm payment (fallback if webhook is slow)

### 5. Domain Purchased (Automatic)
- After payment confirmed, the app calls GoDaddy API to purchase the domain
- Domain is registered for 1 year
- Nameservers are set to your server's nameservers
- Auto-renew is enabled on the domain

### 6. cPanel Account Created (Automatic)
- After domain purchase, the app calls WHM API to create a cPanel account
- The cPanel account uses the purchased domain name
- FTP credentials are auto-generated and stored in the database

### 7. Site Deployed (Automatic)
- After cPanel account creation, the site is exported to static HTML/CSS
- Files are uploaded via FTP to the new cPanel account's `public_html`
- The customer's site is now live on their domain

### 8. Future Updates
- When the customer edits their site and clicks "Publish":
  - New snapshot is created (for rollback)
  - Site is re-exported
  - Files are re-uploaded via FTP to the same cPanel account

### 9. Subscription Cancelled
- If the customer cancels their subscription:
  - Stripe subscription is cancelled
  - GoDaddy domain auto-renew is set to OFF (domain expires at end of period)
  - cPanel account is suspended (site goes offline)

### 10. Subscription Reactivated
- If the customer resubscribes:
  - cPanel account is unsuspended
  - Domain auto-renew is re-enabled
  - Site comes back online

---

## 14. Troubleshooting

### The app won't start

```bash
# Check PM2 logs
pm2 logs sitebuilder --lines 50

# Common issues:
# - Port 3000 already in use: change PORT in ecosystem.config.js
# - Missing .env file: run setup.sh or copy .env.production to .env
# - Database not created: run npx prisma db push
```

### Database issues

```bash
# Recreate the database (WARNING: this deletes all data)
rm prisma/dev.db
npx prisma db push
npm run db:seed
```

### FTP deploy fails

```bash
# Check if FTP credentials are correct
# Go to the site's dashboard → Domain/Deploy tab
# Verify the host, username, and path

# Check deploy logs in the database
# Or check PM2 logs for error messages
pm2 logs sitebuilder --lines 100 | grep -i deploy
```

### GoDaddy domain purchase fails

```bash
# Check if the PAT is valid
# Go to Admin Settings → verify GoDaddy PAT
# Check that the PAT has the correct scopes

# Check server logs
pm2 logs sitebuilder --lines 100 | grep -i godaddy
```

### WHM/cPanel account creation fails

```bash
# Verify WHM API token
# Go to Admin Settings → verify WHM API URL and token
# Test the WHM API directly:
curl -H "Authorization: whm root:YOUR_TOKEN" "https://your-server:2087/json-api/accountsummary?user=test"

# Check server logs
pm2 logs sitebuilder --lines 100 | grep -i whm
pm2 logs sitebuilder --lines 100 | grep -i cpanel
```

### Stripe webhook not receiving events

```bash
# 1. Verify the webhook URL is accessible from the internet
#    Go to Stripe Dashboard → Developers → Webhooks → your endpoint
#    Check if there are any failed delivery attempts

# 2. Verify the webhook secret in .env matches Stripe Dashboard

# 3. The polling fallback should still work even without webhooks
#    After checkout, the site page polls /api/billing/activate

# 4. Test the webhook endpoint:
curl -X POST https://instantsitz.com/api/webhooks/stripe
# Should return a 400 (missing signature) if the endpoint is reachable
```

### Changing the port

If port 3000 is in use, edit `ecosystem.config.js`:

```javascript
apps: [{
  name: 'sitebuilder',
  script: 'node_modules/next/dist/bin/next',
  args: 'start -p 3001',  // change to your desired port
  ...
}]
```

Then restart:
```bash
pm2 restart sitebuilder
```

Update your reverse proxy configuration to point to the new port.

---

## File Structure

```
sitebuilder/
├── app/                    # Next.js App Router pages and API routes
│   ├── api/               # API routes (auth, billing, domains, admin, etc.)
│   ├── (pages)/           # Web pages (login, register, dashboard, settings, etc.)
│   └── globals.css        # Global styles
├── components/             # React components
├── lib/                    # Core libraries
│   ├── ai-content.ts      # AI content generation (OpenAI / mock)
│   ├── ai-image.ts        # AI image generation (DALL-E / mock)
│   ├── auth.ts            # Authentication (JWT cookies)
│   ├── blocks.ts          # Block type definitions
│   ├── crypto.ts          # AES-256-GCM encryption for FTP passwords
│   ├── deploy.ts          # FTP deployment (basic-ftp)
│   ├── export-site.ts     # Export site to static HTML/CSS
│   ├── generate.ts        # Site generation pipeline
│   ├── godaddy.ts         # GoDaddy v3 API (domain purchase, nameservers, auto-renew)
│   ├── palettes.ts        # Color palette definitions
│   ├── prisma.ts          # Prisma client singleton
│   ├── publish.ts         # Publish flow (snapshot → export → deploy)
│   ├── queue.ts           # Job queue
│   ├── render.ts          # Block rendering to HTML
│   ├── seed.ts            # Admin user seeder
│   ├── settings.ts        # Settings store (DB + env)
│   ├── stripe.ts          # Stripe integration (checkout, webhooks, subscriptions)
│   ├── tones.ts           # Content tone definitions
│   ├── usage.ts           # Usage tracking
│   ├── whm.ts             # WHM/cPanel API (create/suspend accounts)
│   └── worker.ts          # Background job worker
├── prisma/
│   ├── schema.prisma      # Database schema
│   └── dev.db             # SQLite database (created on setup)
├── public/                # Static assets
├── exports/               # Exported sites (gitignored)
├── .env.production        # Environment template
├── ecosystem.config.js    # PM2 process config
├── setup.sh               # Automated setup script
├── package.json           # Dependencies and scripts
├── tsconfig.json          # TypeScript config
├── next.config.js         # Next.js config
└── tailwind.config.js     # Tailwind CSS config
```

---

## Support

For issues or questions, check:
1. PM2 logs: `pm2 logs sitebuilder`
2. This deployment guide
3. The Admin Settings page for configuration

The app includes a mock mode for all integrations (Stripe, GoDaddy, WHM, OpenAI).
When credentials are not configured, the app uses mock providers so you can test
the full workflow without setting up external services first.
