# KLZ Cables - Deployment Guide

This document explains the deployment process and environment variable management for the KLZ Cables application.

## Table of Contents

- [Overview](#overview)
- [Environment Variables](#environment-variables)
- [Local Development](#local-development)
- [Production Deployment](#production-deployment)
- [Troubleshooting](#troubleshooting)

## Overview

The application uses a clean, robust, **fully automated** environment variable strategy:

- **Build-time variables**: Only `NEXT_PUBLIC_*` variables are baked into the client bundle
- **Runtime variables**: All other variables are loaded from `.env` file at runtime
- **Fully automated**: `.env` file is automatically generated from Gitea secrets on every deployment
- **No manual steps**: No need to manually create or update `.env` files on the server
- **No duplication**: Single source of truth for each environment

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│ CI/CD Workflow (.gitea/workflows/deploy.yml)               │
│                                                             │
│ 1. Build Docker image with NEXT_PUBLIC_* build args        │
│ 2. Push to registry                                        │
│ 3. SSH to server and run deploy.sh                         │
└─────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────┐
│ Production Server (alpha.mintel.me)                         │
│                                                             │
│ /home/deploy/sites/klz-cables.com/                         │
│ ├── .env                    ← Runtime environment vars     │
│ └── docker-compose.yml      ← Loads .env file              │
└─────────────────────────────────────────────────────────────┘
```

## Environment Variables

### Build-Time Variables (NEXT_PUBLIC_*)

These are embedded into the JavaScript bundle during build and are visible to the client:

| Variable | Required | Description |
|----------|----------|-------------|
| `NEXT_PUBLIC_BASE_URL` | ✅ Yes | Base URL of the application (e.g., `https://klz-cables.com`) |
| `NEXT_PUBLIC_UMAMI_WEBSITE_ID` | ❌ No | Umami analytics website ID |
| `NEXT_PUBLIC_UMAMI_SCRIPT_URL` | ❌ No | Umami analytics script URL (default: `https://analytics.infra.mintel.me/script.js`) |

**Important**: These must be provided as `--build-arg` when building the Docker image.

### Runtime Variables

These are loaded from the `.env` file at runtime and are only available on the server:

| Variable | Required | Description |
|----------|----------|-------------|
| `NODE_ENV` | ✅ Yes | Environment mode (`production`, `development`, `test`) |
| `SENTRY_DSN` | ❌ No | GlitchTip/Sentry error tracking DSN |
| `MAIL_HOST` | ❌ No | SMTP server hostname |
| `MAIL_PORT` | ❌ No | SMTP server port (default: `587`) |
| `MAIL_USERNAME` | ❌ No | SMTP authentication username |
| `MAIL_PASSWORD` | ❌ No | SMTP authentication password |
| `MAIL_FROM` | ❌ No | Email sender address |
| `MAIL_RECIPIENTS` | ❌ No | Comma-separated list of recipient emails |
| `REDIS_URL` | ❌ No | Redis connection URL (e.g., `redis://redis:6379/2`) |
| `REDIS_KEY_PREFIX` | ❌ No | Redis key prefix (default: `klz:`) |

## Local Development

### Setup

1. Copy the example environment file:
   ```bash
   cp .env.example .env
   ```

2. Edit `.env` and fill in your local configuration:
   ```bash
   NODE_ENV=development
   NEXT_PUBLIC_BASE_URL=http://localhost:3000
   # Add other variables as needed
   ```

3. Install dependencies:
   ```bash
   npm install
   ```

4. Run the development server:
   ```bash
   npm run dev
   ```

### Testing Docker Build Locally

```bash
# Build with build-time arguments
docker build \
  --build-arg NEXT_PUBLIC_BASE_URL=http://localhost:3000 \
  --build-arg NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-id \
  --build-arg NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js \
  -t klz-cables:local .

# Run with runtime environment file
docker run --env-file .env -p 3000:3000 klz-cables:local
```

## Production Deployment

### Prerequisites

1. **Server Setup**: Ensure the production server has:
   - Docker and Docker Compose installed
   - Traefik reverse proxy running
   - Network `infra` created
   - Project directory exists: `/home/deploy/sites/klz-cables.com`

2. **Gitea Secrets**: Configure the following secrets in your Gitea repository:

   **Registry Access:**
   - `REGISTRY_USER` - Docker registry username
   - `REGISTRY_PASS` - Docker registry password

   **Build-Time Variables:**
   - `NEXT_PUBLIC_BASE_URL` - Production URL (e.g., `https://klz-cables.com`)
   - `NEXT_PUBLIC_UMAMI_WEBSITE_ID` - Umami analytics ID
   - `NEXT_PUBLIC_UMAMI_SCRIPT_URL` - Umami script URL

   **Runtime Variables:**
   - `SENTRY_DSN` - Error tracking DSN
   - `MAIL_HOST` - SMTP server
   - `MAIL_PORT` - SMTP port
   - `MAIL_USERNAME` - SMTP username
   - `MAIL_PASSWORD` - SMTP password
   - `MAIL_FROM` - Sender email
   - `MAIL_RECIPIENTS` - Recipient emails (comma-separated)
   - `REDIS_URL` - Redis connection URL
   - `REDIS_KEY_PREFIX` - Redis key prefix

   **Infrastructure:**
   - `REGISTRY_USER` - Docker registry username
   - `REGISTRY_PASS` - Docker registry password
   - `ALPHA_SSH_KEY` - SSH private key for deployment server

   **Notifications:**
   - `GOTIFY_URL` - Gotify notification server URL
   - `GOTIFY_TOKEN` - Gotify application token

### Deployment Process

The deployment is **fully automated** via Gitea Actions:

1. **Trigger**: Push to `main` branch
2. **Build**: Docker image is built with `NEXT_PUBLIC_*` build arguments
3. **Push**: Image is pushed to private registry
4. **Generate .env**: Workflow creates `.env` file from all Gitea secrets
5. **Upload .env**: File is uploaded to server via SCP and secured (600 permissions)
6. **Deploy**: SSH to server, pull image, and run docker-compose
7. **Notify**: Send success/failure notification via Gotify

**No manual steps required!** The `.env` file is automatically created and deployed on every push.

### Manual Deployment

If you need to deploy manually (not recommended - use the automated workflow):

```bash
# SSH to the server
ssh root@alpha.mintel.me

# Navigate to the project directory
cd /home/deploy/sites/klz-cables.com

# Ensure .env file exists (normally created by workflow)
# If missing, you'll need to create it from Gitea secrets

# Pull the latest image
docker pull registry.infra.mintel.me/mintel/klz-cables.com:latest

# Restart the services
docker-compose down
docker-compose up -d

# Check logs
docker-compose logs -f app
```

**Note**: Manual deployment requires the `.env` file to exist. The automated workflow creates this file from Gitea secrets. If deploying manually, you'll need to create it yourself using [`.env.production`](.env.production) as a template.

## Troubleshooting

### Build Failures

**Problem**: Build fails with "Environment validation failed"

**Solution**: Ensure all required `NEXT_PUBLIC_*` variables are provided as build arguments:
```bash
docker build \
  --build-arg NEXT_PUBLIC_BASE_URL=https://klz-cables.com \
  --build-arg NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-id \
  --build-arg NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js \
  -t klz-cables .
```

### Runtime Failures

**Problem**: Container starts but application crashes

**Solution**: Check that the `.env` file exists and contains all required runtime variables:
```bash
# On the server
cat /home/deploy/sites/klz-cables.com/.env

# Check container logs
docker-compose logs app
```

### Missing Environment Variables

**Problem**: Features not working (email, analytics, etc.)

**Solution**:
1. Check that the secret is configured in Gitea
2. Verify the workflow includes it in the `.env` generation (see `.gitea/workflows/deploy.yml`)
3. Redeploy to regenerate the `.env` file:
   ```bash
   git commit --allow-empty -m "Trigger redeploy"
   git push origin main
   ```

4. Check the variable is loaded on the server:
   ```bash
   ssh root@alpha.mintel.me
   cd /home/deploy/sites/klz-cables.com
   docker-compose exec app env | grep VARIABLE_NAME
   ```

### Docker Compose Issues

**Problem**: `docker-compose up` fails with "env file not found"

**Solution**: The `.env` file should be automatically created by the workflow. If it's missing:
1. Check the workflow logs for errors in the "📝 Preparing environment configuration" step
2. Manually trigger a deployment by pushing to main
3. If still missing, check server permissions and disk space

### Network Issues

**Problem**: Container can't connect to Traefik

**Solution**: Verify the `infra` network exists:
```bash
docker network ls | grep infra
docker network inspect infra
```

## Security Best Practices

1. **Never commit `.env` files** with real credentials to git
2. **Use Gitea/GitHub secrets** for CI/CD workflows
3. **Restrict SSH key access** to deployment server
4. **Rotate credentials regularly** (SMTP passwords, API keys, etc.)
5. **Use HTTPS** for all production URLs
6. **Monitor logs** for suspicious activity

## Additional Resources

- [Next.js Environment Variables](https://nextjs.org/docs/basic-features/environment-variables)
- [Docker Compose Environment Variables](https://docs.docker.com/compose/environment-variables/)
- [Traefik Documentation](https://doc.traefik.io/traefik/)
