# Placebo.mk Deployment Guide (Coolify)

Complete deployment guide for the Placebo.mk satirical news platform on a VPS using Coolify.

## Table of Contents

1. [Architecture Overview](#architecture-overview)
2. [Prerequisites](#prerequisites)
3. [Coolify Setup](#coolify-setup)
4. [Database Configuration](#database-configuration)
5. [Service Deployments](#service-deployments)
6. [Environment Variables Reference](#environment-variables-reference)
7. [Domain & SSL Configuration](#domain--ssl-configuration)
8. [Push Notifications Setup](#push-notifications-setup)
9. [Post-Deployment Checklist](#post-deployment-checklist)
10. [Troubleshooting](#troubleshooting)

---

## Architecture Overview

```
                         ┌──────────────────────────────────────┐
                         │         Coolify Reverse Proxy        │
                         │           (Traefik/Caddy)            │
                         └────────────────┬─────────────────────┘
                                          │
         ┌────────────────────────────────┼────────────────────────────────┐
         │                                │                                │
         ▼                                ▼                                ▼
┌─────────────────┐              ┌─────────────────┐              ┌─────────────────┐
│    Frontend     │              │       PWA       │              │       CMS       │
│  (React+Vite)   │              │ (React+Vite+SW) │              │    (Strapi)     │
│    nginx:80     │              │    nginx:80     │              │   Node.js:1337  │
│ placebo.mk      │              │ app.placebo.mk  │              │ cms.placebo.mk  │
└────────┬────────┘              └────────┬────────┘              └────────┬────────┘
         │                                │                                │
         │                                │                                │
         │                                │                                │
         └────────────────────────────────┼────────────────────────────────┘
                                          │
                                          ▼
                                ┌─────────────────┐
                                │     Backend     │
                                │    (NestJS)     │
                                │   Node.js:3000  │
                                │ api.placebo.mk  │
                                └────────┬────────┘
                                         │
                                         ▼
                                ┌─────────────────┐
                                │   PostgreSQL    │
                                │     :5432       │
                                └─────────────────┘
```

### Tech Stack

| Service | Technology | Port | Purpose |
|---------|------------|------|---------|
| Frontend | React 19 + Vite + Tailwind | 80 | Main website (SSG) |
| PWA | React 19 + Vite + Workbox | 80 | Progressive Web App with push |
| Backend | NestJS + TypeORM | 3000 | REST API |
| CMS | Strapi 5 | 1337 | Content management |
| Database | PostgreSQL 16 | 5432 | Primary data store |

---

## Prerequisites

### Server Requirements

| Resource | Minimum | Recommended |
|----------|---------|-------------|
| RAM | 4GB | 8GB |
| CPU | 2 vCPU | 4 vCPU |
| Storage | 40GB SSD | 80GB SSD |
| OS | Ubuntu 22.04 | Ubuntu 24.04 |

### Domain Setup

Configure these DNS A records pointing to your VPS IP:

| Type | Name | Purpose |
|------|------|---------|
| A | `@` | Main website (frontend) |
| A | `www` | WWW redirect |
| A | `api` | Backend API |
| A | `app` | PWA |
| A | `cms` | Strapi admin |

### Required Before Deployment

- [ ] Coolify installed and accessible
- [ ] Domain DNS configured
- [ ] GitHub repository connected to Coolify
- [ ] SMTP server (optional, for emails)

---

## Coolify Setup

### 1. Create Project

1. Login to Coolify dashboard
2. Navigate to **Projects**
3. Click **+ New Project**
4. Name: `placebo`
5. Click **Create**

### 2. Create Environment

1. Inside `placebo` project
2. Click **+ New Environment**
3. Name: `production`
4. Click **Create**

### 3. Connect Repository

1. Go to **Configuration** → **Source**
2. Click **Connect GitHub**
3. Authorize Coolify to access your repositories
4. Select repository: `your-org/placeboMk`

---

## Quick Deploy (Docker Compose)

Deploy all services in one step using Docker Compose.

### Step 1: Create Service

1. In `production` environment, click **+ New Resource**
2. Select **Docker Compose** (not Dockerfile)
3. Name: `placebo-stack`
4. Repository: Select your connected repo
5. Compose File: `docker-compose.coolify.yml`

### Step 2: Set Environment Variables

Click **Environment Variables** and add these secrets:

| Variable | How to Generate |
|----------|-----------------|
| `DATABASE_PASSWORD` | `openssl rand -base64 32` |
| `JWT_SECRET` | `openssl rand -base64 64 \| tr -d '\n'` |
| `VAPID_PUBLIC_KEY` | Run `npm run generate-vapid` locally |
| `VAPID_PRIVATE_KEY` | Run `npm run generate-vapid` locally |
| `STRAPI_APP_KEYS` | See generation command below |
| `STRAPI_API_TOKEN_SALT` | `openssl rand -base64 32` |
| `STRAPI_ADMIN_JWT_SECRET` | `openssl rand -base64 32` |
| `STRAPI_TRANSFER_TOKEN_SALT` | `openssl rand -base64 32` |
| `STRAPI_JWT_SECRET` | `openssl rand -base64 32` |
| `STRAPI_API_TOKEN` | Get from CMS admin after first deploy |

**Generate Strapi APP_KEYS** (4 comma-separated keys):
```bash
for i in {1..4}; do node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"; done | paste -sd "," -
```

**Generate VAPID Keys** (run locally):
```bash
cd backend
npm install
npm run generate-vapid
```

### Step 3: Configure Domains

The compose file uses Traefik labels with these domains:
- `placebo.mk` - Frontend
- `www.placebo.mk` - Frontend (redirect)
- `api.placebo.mk` - Backend API
- `app.placebo.mk` - PWA
- `cms.placebo.mk` - CMS (Strapi)

Ensure DNS is configured before deploying.

### Step 4: Deploy

1. Click **Deploy**
2. Wait for all services to start (2-5 minutes)
3. Check logs if any service fails

### Step 5: Create CMS Admin

1. Visit `https://cms.placebo.mk/admin`
2. Create your admin user
3. Generate API token for backend
4. Add `STRAPI_API_TOKEN` to environment variables
5. Redeploy

---

## Manual Deploy (Individual Services)

If you prefer deploying each service separately, follow these steps.

---

## Database Configuration

### Create PostgreSQL Service

1. In `production` environment, click **+ New Resource**
2. Select **Database** → **PostgreSQL**
3. Configure:

| Setting | Value |
|---------|-------|
| Name | `placebo-db` |
| Version | `16-alpine` |
| PostgreSQL User | `placebo_user` |
| PostgreSQL Password | `<generate-secure-password>` |
| PostgreSQL Database | `placebo_db` |
| Persistent Volume | Enabled |

4. Click **Deploy`

### Note Connection Details

After deployment, note the internal hostname:
```
Host: placebo-db
Port: 5432
Database: placebo_db
Username: placebo_user
Password: <your-password>
```

---

## Service Deployments (Manual)

### 1. Backend (NestJS API)

#### Create Service

1. Click **+ New Resource** → **Service**
2. Select **Dockerfile** (not Docker Compose)
3. Name: `placebo-backend`
4. Repository: Select your connected repo

#### Configuration

| Setting | Value |
|---------|-------|
| Dockerfile Location | `backend/Dockerfile` |
| Build Context | `backend` |
| Port | `3000` |

#### Environment Variables

```env
NODE_ENV=production
PORT=3000

# Database
DATABASE_TYPE=postgres
DATABASE_HOST=placebo-db
DATABASE_PORT=5432
DATABASE_USERNAME=placebo_user
DATABASE_PASSWORD=<your-db-password>
DATABASE_NAME=placebo_db
DATABASE_SYNCHRONIZE=false
DATABASE_LOGGING=false

# JWT Authentication
JWT_SECRET=<generate-64-char-secret>
JWT_EXPIRATION=86400

# CORS
CORS_ORIGIN=https://placebo.mk,https://www.placebo.mk,https://app.placebo.mk

# Strapi CMS
STRAPI_URL=https://cms.placebo.mk
STRAPI_API_TOKEN=<your-strapi-api-token>

# Push Notifications
VAPID_SUBJECT=mailto:contact@placebo.mk
VAPID_PUBLIC_KEY=<generated-public-key>
VAPID_PRIVATE_KEY=<generated-private-key>
```

#### Generate Secrets

**JWT Secret:**
```bash
openssl rand -base64 64 | tr -d '\n'
```

**VAPID Keys** (run locally):
```bash
cd backend
npm install
npm run generate-vapid
```

#### Health Check

| Setting | Value |
|---------|-------|
| Path | `/health` |
| Interval | 30s |
| Timeout | 10s |
| Retries | 3 |

#### Domain

1. Go to **Domains** tab
2. Add: `api.placebo.mk`
3. Enable **HTTPS** (Let's Encrypt)

---

### 2. Frontend (Main Website)

#### Create Service

1. Click **+ New Resource** → **Service** → **Dockerfile**
2. Name: `placebo-frontend`

#### Configuration

| Setting | Value |
|---------|-------|
| Dockerfile Location | `frontend/Dockerfile` |
| Build Context | `frontend` |
| Port | `80` |

#### Build Arguments

Vite requires environment variables at build time. Add these as **Build Args**:

```env
VITE_API_URL=https://api.placebo.mk/api/v1
VITE_CMS_URL=https://cms.placebo.mk
```

#### Domain

1. Add: `placebo.mk`
2. Add: `www.placebo.mk`
3. Enable **HTTPS**

---

### 3. PWA (Progressive Web App)

#### Create Service

1. Click **+ New Resource** → **Service** → **Dockerfile**
2. Name: `placebo-pwa`

#### Configuration

| Setting | Value |
|---------|-------|
| Dockerfile Location | `pwa/Dockerfile` |
| Build Context | `pwa` |
| Port | `80` |

#### Build Arguments

```env
VITE_API_URL=https://api.placebo.mk/api/v1
VITE_CMS_URL=https://cms.placebo.mk
```

#### Persistent Volume (Optional)

For service worker and cache:
- Container Path: `/usr/share/nginx/html`
- Host Path: `pwa-dist`

#### Domain

1. Add: `app.placebo.mk`
2. Enable **HTTPS**

---

### 4. CMS (Strapi)

#### Create Service

1. Click **+ New Resource** → **Service** → **Dockerfile**
2. Name: `placebo-cms`

#### Configuration

| Setting | Value |
|---------|-------|
| Dockerfile Location | `cms/cms/Dockerfile` |
| Build Context | `cms/cms` |
| Port | `1337` |

#### Environment Variables

```env
NODE_ENV=production
HOST=0.0.0.0
PORT=1337

# Database
DATABASE_CLIENT=postgres
DATABASE_HOST=placebo-db
DATABASE_PORT=5432
DATABASE_NAME=placebo_db
DATABASE_USERNAME=placebo_user
DATABASE_PASSWORD=<your-db-password>
DATABASE_SSL=false

# Security Keys (generate unique values for each)
APP_KEYS=<generate-4-keys>
API_TOKEN_SALT=<32-char-secret>
ADMIN_JWT_SECRET=<32-char-secret>
TRANSFER_TOKEN_SALT=<32-char-secret>
JWT_SECRET=<32-char-secret>

# CORS
CORS_ORIGIN=https://placebo.mk,https://app.placebo.mk,https://api.placebo.mk
```

#### Generate Strapi Keys

**For APP_KEYS** (4 comma-separated keys):
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# Run 4 times, join with commas
```

**For other secrets:**
```bash
openssl rand -base64 32
```

#### Persistent Volumes

Add these volumes for data persistence:

| Container Path | Purpose |
|----------------|---------|
| `/app/public/uploads` | Media uploads |
| `/app/.tmp` | Temporary files |

#### Domain

1. Add: `cms.placebo.mk`
2. Enable **HTTPS**

---

## Environment Variables Reference

### Backend

| Variable | Required | Description |
|----------|----------|-------------|
| `NODE_ENV` | Yes | Set to `production` |
| `DATABASE_HOST` | Yes | PostgreSQL hostname |
| `DATABASE_PORT` | Yes | PostgreSQL port (5432) |
| `DATABASE_USERNAME` | Yes | Database username |
| `DATABASE_PASSWORD` | Yes | Database password |
| `DATABASE_NAME` | Yes | Database name |
| `DATABASE_SYNCHRONIZE` | Yes | Set to `false` in production |
| `JWT_SECRET` | Yes | 64+ character secret |
| `CORS_ORIGIN` | Yes | Comma-separated allowed origins |
| `VAPID_PUBLIC_KEY` | Yes | For push notifications |
| `VAPID_PRIVATE_KEY` | Yes | For push notifications |
| `STRAPI_URL` | Yes | CMS URL |
| `STRAPI_API_TOKEN` | Yes | API token from Strapi |

### Frontend/PWA (Build Args)

| Variable | Required | Description |
|----------|----------|-------------|
| `VITE_API_URL` | Yes | Backend API URL |
| `VITE_CMS_URL` | Yes | CMS URL |

### CMS (Strapi)

| Variable | Required | Description |
|----------|----------|-------------|
| `APP_KEYS` | Yes | 4 comma-separated 32-byte keys |
| `API_TOKEN_SALT` | Yes | Random 32-byte string |
| `ADMIN_JWT_SECRET` | Yes | Random 32-byte string |
| `JWT_SECRET` | Yes | Random 32-byte string |
| `TRANSFER_TOKEN_SALT` | Yes | Random 32-byte string |

---

## Domain & SSL Configuration

### Configure Each Service

For each deployed service:

1. Go to service → **Configuration** → **Domains**
2. Click **Add Domain**
3. Enter domain (e.g., `api.placebo.mk`)
4. Enable **HTTPS**
5. Select **Let's Encrypt**
6. Click **Request Certificate**

### SSL Certificate Generation

Coolify automatically handles SSL via Let's Encrypt. Ensure:
- DNS is properly configured
- Port 80 and 443 are open
- Domain is accessible from internet

---

## Push Notifications Setup

### 1. Generate VAPID Keys

Run locally in the backend directory:

```bash
cd backend
npm install
npm run generate-vapid
```

Output:
```
Generating VAPID keys...
VAPID keys generated and added to .env file:
  Public Key: BIAna-ulT88Ek5ZdiAiXJikks3T5JEuZjBstuO7bEbUJ6RAoSmXAbum1Pf7JIbo-YQfwXM1Yi-rGTttOuNJUpUE
  Private Key: DGtRu68SmAxng-xx3BiTCa9NrztQbsSoECRuzry9VD4
```

### 2. Configure Backend

Add to backend environment variables:
```env
VAPID_SUBJECT=mailto:contact@placebo.mk
VAPID_PUBLIC_KEY=<your-public-key>
VAPID_PRIVATE_KEY=<your-private-key>
```

### 3. Verify Setup

1. Deploy backend with VAPID keys
2. Visit: `https://api.placebo.mk/api/v1/push/vapid-public-key`
3. Should return JSON with your public key

### 4. Test in PWA

1. Open `https://app.placebo.mk`
2. Wait for notification banner
3. Click "Вклучи" (Enable)
4. Accept browser permission
5. Verify subscription in admin dashboard

---

## Post-Deployment Checklist

### Backend

- [ ] Health check passing: `https://api.placebo.mk/health`
- [ ] API docs accessible: `https://api.placebo.mk/api/v1`
- [ ] Database connected (check logs)
- [ ] JWT authentication working
- [ ] CORS accepting frontend origins
- [ ] Push notification endpoint working

### Frontend

- [ ] Site loads: `https://placebo.mk`
- [ ] No console errors
- [ ] API calls successful (check Network tab)
- [ ] Images and assets loading
- [ ] Navigation working correctly
- [ ] Admin dashboard accessible

### PWA

- [ ] Site loads: `https://app.placebo.mk`
- [ ] Service worker registered (DevTools → Application)
- [ ] Install prompt appears
- [ ] Notification banner shows
- [ ] Push subscription successful
- [ ] Works offline (cached resources)

### CMS

- [ ] Admin panel: `https://cms.placebo.mk/admin`
- [ ] First admin user created
- [ ] API token generated for backend
- [ ] Media uploads working
- [ ] Content types created

---

## Troubleshooting

### Backend Won't Start

**Symptoms:** Container keeps restarting

**Solutions:**
1. Check logs: Coolify → Service → Logs
2. Verify database connection:
   - `DATABASE_HOST` should be service name (e.g., `placebo-db`)
   - Check password matches database password
3. Verify all required env vars are set
4. Check JWT_SECRET is at least 32 characters

### Frontend Shows Blank Page

**Symptoms:** Page loads but nothing displays

**Solutions:**
1. Check browser console for errors
2. Verify build args were set:
   - `VITE_API_URL` must be set at build time
3. Check Network tab for failed API calls
4. Rebuild with correct environment variables

### CORS Errors

**Symptoms:** Browser blocks API requests

**Solutions:**
1. Add all frontend domains to `CORS_ORIGIN`:
   ```env
   CORS_ORIGIN=https://placebo.mk,https://www.placebo.mk,https://app.placebo.mk
   ```
2. Restart backend after changing
3. Clear browser cache

### Push Notifications Not Working

**Symptoms:** Subscription fails or notifications don't arrive

**Solutions:**
1. Verify HTTPS is enabled (required for push)
2. Check VAPID keys are set in backend
3. Test endpoint: `/api/v1/push/vapid-public-key`
4. Check service worker is registered
5. Verify browser notification permission is granted

### Database Connection Issues

**Symptoms:** Backend can't connect to database

**Solutions:**
1. Verify database service is running
2. Check hostname matches database service name
3. Verify credentials are correct
4. Ensure both services are on the same network
5. Check database logs for errors

### CMS Admin Not Accessible

**Symptoms:** 404 or redirect loop on `/admin`

**Solutions:**
1. Verify all Strapi secrets are set
2. Check `HOST=0.0.0.0` is set
3. Clear browser cache and cookies
4. Check CMS logs for startup errors

---

## Maintenance

### Updating Deployments

1. Push changes to GitHub main branch
2. Coolify → Service → **Redeploy**
3. Or enable automatic deployments on push

### Database Backups

1. Coolify → Database → **Backups**
2. Enable scheduled backups
3. Recommended retention: 7-30 days
4. Store backups off-server periodically

### Log Management

- **View logs:** Coolify → Service → Logs
- **Download logs:** Available in service settings
- **Log rotation:** Configured automatically

### Monitoring

1. Set up Coolify notifications for:
   - Service down
   - High resource usage
   - Deployment failures
2. Monitor disk usage (uploads, logs)
3. Check SSL certificate expiration

---

## Security Checklist

- [ ] All secrets are 32+ characters
- [ ] HTTPS enabled on all services
- [ ] Database not exposed to internet
- [ ] CORS restricted to your domains only
- [ ] CMS admin protected (consider IP whitelist)
- [ ] Regular security updates applied
- [ ] Backups configured and tested
- [ ] Monitoring and alerts enabled

---

## Support

For issues specific to:
- **Coolify**: [Coolify Documentation](https://coolify.io/docs)
- **NestJS**: [NestJS Documentation](https://docs.nestjs.com)
- **Strapi**: [Strapi Documentation](https://docs.strapi.io)
- **Vite/PWA**: [Vite PWA Plugin](https://vite-pwa-org.netlify.app)
