# Environment Variables Migration Guide

This guide helps you migrate from the old fragile environment variable setup to the new clean, robust system.

## What Changed?

### Before (Fragile & Overkill)

❌ **Problems:**

- Environment variables passed individually via SSH (12+ vars)
- Duplicate definitions in Dockerfile, docker-compose.yml, and deploy.yml
- Build args included runtime-only variables (SENTRY*DSN, MAIL*_, REDIS\__)
- No single source of truth
- Difficult to maintain and error-prone

```yaml
# Old deploy.yml - FRAGILE!
ssh root@alpha.mintel.me \
"MAIL_FROM='${{ secrets.MAIL_FROM }}' \
MAIL_HOST='${{ secrets.MAIL_HOST }}' \
MAIL_PASSWORD='${{ secrets.MAIL_PASSWORD }}' \
MAIL_PORT='${{ secrets.MAIL_PORT }}' \
MAIL_RECIPIENTS='${{ secrets.MAIL_RECIPIENTS }}' \
MAIL_USERNAME='${{ secrets.MAIL_USERNAME }}' \
NEXT_PUBLIC_BASE_URL='${{ secrets.NEXT_PUBLIC_BASE_URL }}' \
... (12+ variables) \
/home/deploy/deploy.sh"
```

### After (Clean & Robust)

✅ **Benefits:**

- Single `.env` file on server contains all runtime variables
- Only `NEXT_PUBLIC_*` variables passed as build args (3 vars)
- Clear separation: build-time vs runtime
- Easy to maintain and update
- Single source of truth per environment

```yaml
# New deploy.yml - CLEAN!
ssh root@alpha.mintel.me "/home/deploy/deploy.sh"
```

## Migration Steps

### Step 1: Update Gitea Secrets

**Remove these secrets** (no longer needed in CI/CD):

- ❌ `MAIL_FROM`
- ❌ `MAIL_HOST`
- ❌ `MAIL_PASSWORD`
- ❌ `MAIL_PORT`
- ❌ `MAIL_RECIPIENTS`
- ❌ `MAIL_USERNAME`
- ❌ `NODE_ENV`
- ❌ `REDIS_URL`
- ❌ `REDIS_KEY_PREFIX`
- ❌ `SENTRY_DSN` (from build args)

**Keep these secrets** (still needed for build):

- ✅ `NEXT_PUBLIC_BASE_URL`
- ✅ `NEXT_PUBLIC_BASE_URL`
- ✅ `UMAMI_WEBSITE_ID`
- ✅ `UMAMI_API_ENDPOINT`
- ✅ `REGISTRY_USER`
- ✅ `REGISTRY_PASS`
- ✅ `ALPHA_SSH_KEY`
- ✅ `GOTIFY_URL`
- ✅ `GOTIFY_TOKEN`

### Step 2: Create .env File on Server

SSH to the production server and create the `.env` file:

```bash
ssh root@alpha.mintel.me

# Create .env file
cat > /home/deploy/sites/klz-cables.com/.env << 'EOF'
# Application
NODE_ENV=production
NEXT_PUBLIC_BASE_URL=https://klz-cables.com

# Analytics
UMAMI_WEBSITE_ID=your-actual-id
UMAMI_API_ENDPOINT=https://analytics.infra.mintel.me

# Error Tracking
SENTRY_DSN=your-actual-dsn

# Email
MAIL_HOST=smtp.eu.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=your-actual-username
MAIL_PASSWORD=your-actual-password
MAIL_FROM=KLZ Cables <noreply@klz-cables.com>
MAIL_RECIPIENTS=info@klz-cables.com

# Redis
REDIS_URL=redis://redis:6379/2
REDIS_KEY_PREFIX=klz:

# Varnish
VARNISH_CACHE_SIZE=256m
EOF

# Secure the file
chmod 600 /home/deploy/sites/klz-cables.com/.env
chown deploy:deploy /home/deploy/sites/klz-cables.com/.env
```

**Important**: Replace all `your-actual-*` placeholders with real values from your old Gitea secrets.

### Step 3: Update Deployment Script

Update `/home/deploy/deploy.sh` to use the new approach:

```bash
cat > /home/deploy/deploy.sh << 'EOF'
#!/bin/bash
set -e

PROJECT_DIR="/home/deploy/sites/klz-cables.com"

echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ KLZ Cables - Deployment Script                                              ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""

cd "$PROJECT_DIR"

# Check if .env file exists
if [ ! -f .env ]; then
    echo "❌ ERROR: .env file not found at $PROJECT_DIR/.env"
    exit 1
fi

echo "🔐 Logging into Docker registry..."
echo "$REGISTRY_PASS" | docker login registry.infra.mintel.me -u "$REGISTRY_USER" --password-stdin

echo "🔄 Pulling latest image..."
docker pull registry.infra.mintel.me/mintel/klz-cables.com:latest

echo "🔄 Stopping existing containers..."
docker-compose down

echo "🚀 Starting new containers..."
docker-compose up -d

echo "⏳ Waiting for services to be healthy..."
sleep 10

echo "🔍 Checking service status..."
docker-compose ps

echo ""
echo "✅ Deployment complete!"
EOF

chmod +x /home/deploy/deploy.sh
```

### Step 4: Deploy Updated Code

The new code is already in the repository. Just push to trigger deployment:

```bash
git push origin main
```

The CI/CD workflow will:

1. Build with only `NEXT_PUBLIC_*` build args
2. Push to registry
3. SSH to server and run deploy.sh
4. Deploy.sh will use the `.env` file for runtime vars

### Step 5: Verify Migration

After deployment, verify everything works:

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

# Check containers are running
cd /home/deploy/sites/klz-cables.com
docker-compose ps

# Verify environment variables are loaded
docker-compose exec app env | grep -E "NODE_ENV|NEXT_PUBLIC|MAIL|REDIS"

# Check application logs
docker-compose logs -f app

# Test the website
curl -I https://klz-cables.com
```

## Comparison Table

| Aspect            | Before                          | After                        |
| ----------------- | ------------------------------- | ---------------------------- |
| **Gitea Secrets** | 15+ secrets                     | 8 secrets                    |
| **Build Args**    | 4 vars (including runtime-only) | 3 vars (NEXT*PUBLIC*\* only) |
| **Runtime Vars**  | Passed via SSH command          | Loaded from .env file        |
| **Maintenance**   | Update in 3 places              | Update in 1 place            |
| **Security**      | Secrets in CI logs              | Secrets only on server       |
| **Clarity**       | Confusing duplication           | Clear separation             |
| **Robustness**    | Fragile SSH command             | Robust file-based config     |

## Rollback Plan

If you need to rollback to the old system:

1. Revert the changes in git:

   ```bash
   git revert HEAD
   git push origin main
   ```

2. Re-add the removed Gitea secrets

3. The old deployment will work again

## FAQ

**Q: Why keep `NEXT_PUBLIC_*` in both build args and .env file?**

A: `NEXT_PUBLIC_*` variables are special in Next.js - they're embedded into the JavaScript bundle at build time. They must be provided as build args. However, they're also needed at runtime for server-side rendering, so they're in the .env file too.

**Q: Can I update environment variables without rebuilding?**

A: Yes, for runtime-only variables (MAIL*\*, REDIS*\*, SENTRY_DSN, etc.). Just edit the `.env` file on the server and restart containers:

```bash
nano /home/deploy/sites/klz-cables.com/.env
docker-compose down && docker-compose up -d
```

For `NEXT_PUBLIC_*` variables, you need to rebuild the Docker image since they're baked into the client bundle.

**Q: Where should I store the .env file backup?**

A: Keep a secure backup outside the server:

```bash
# Download from server
scp root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/.env \
    ~/secure-backups/klz-cables.env.backup

# Store in password manager or encrypted storage
```

**Q: What if I accidentally commit .env to git?**

A:

1. Remove it immediately: `git rm .env && git commit -m "Remove .env"`
2. Rotate all credentials in the file
3. Update the `.gitignore` to ensure it doesn't happen again (already done)

## Support

If you encounter issues during migration:

1. Check the logs: `docker-compose logs -f app`
2. Verify .env file exists and has correct permissions
3. Ensure all required variables are set
4. Review [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed troubleshooting

## Summary

The new system is:

- ✅ **Simpler**: One .env file instead of scattered variables
- ✅ **Cleaner**: Clear separation of build vs runtime
- ✅ **Robust**: File-based config instead of fragile SSH commands
- ✅ **Secure**: Secrets stay on server, not in CI logs
- ✅ **Maintainable**: Single source of truth per environment

You've successfully migrated from a fragile, overkill setup to a clean, production-ready configuration! 🎉
