# Puffin App - Deployment Guide

This guide covers deploying the Puffin Offset application with **two separate containers** (frontend + backend) using Gitea Actions for automated builds and Docker Compose for orchestration.

## Architecture Overview

```
Code Push → Gitea → Actions Build → Container Registry → Production Server
                              ↓                              ↓
                    [Frontend Image]              Docker Compose Stack
                    [Backend Image]               ├─ Frontend (port 3800)
                                                  └─ Backend (port 3001)
                                                         ↑
                                                   Host Nginx
                                                   (SSL + routing)
```

## CI/CD Pipeline

### Automated Build Process

When code is pushed to the `main` branch:

1. **Gitea Actions triggers** automatically
2. **Docker image is built** using the multi-stage Dockerfile
3. **Image is pushed** to Gitea's container registry with two tags:
   - `latest` - Always points to the most recent build
   - `main-<commit-sha>` - Specific commit for rollback capability

### Registry Location

Images are stored at:
```
code.puffinoffset.com/matt/puffin-app:latest
code.puffinoffset.com/matt/puffin-app:main-<sha>
```

## Portainer Deployment

### Prerequisites

1. **Portainer installed and accessible**
2. **Gitea registry credentials configured in Portainer**
3. **Environment variables prepared** (see below)

### Step 1: Configure Gitea Registry in Portainer

1. Navigate to **Portainer → Registries**
2. Click **"Add registry"**
3. Configure:
   - **Name**: `Gitea - code.puffinoffset.com`
   - **Registry URL**: `code.puffinoffset.com`
   - **Authentication**: Enabled
   - **Username**: Your Gitea username (e.g., `matt`)
   - **Password**: Gitea access token or password
4. Click **"Add registry"**

### Step 2: Prepare Environment Variables

Create a `.env` file on your server with the required variables:

```bash
# Example: /path/to/puffin-app/.env
VITE_WREN_API_TOKEN=your-wren-api-token
VITE_FORMSPREE_CONTACT_ID=your-formspree-contact-id
VITE_FORMSPREE_OFFSET_ID=your-formspree-offset-id
```

**Note**: The env.sh script in the Docker image will inject these at runtime.

### Step 3: Create Portainer Stack

#### Option A: Using Portainer UI

1. Navigate to **Portainer → Stacks**
2. Click **"Add stack"**
3. Configure:
   - **Name**: `puffin-app`
   - **Build method**: "Web editor"
4. Paste the contents of `docker-compose.portainer.yml`
5. In **Environment variables** section, add:
   - Name: `ENV_FILE_PATH`
   - Value: `/path/to/your/.env`
6. Click **"Deploy the stack"**

#### Option B: Using Git Repository

1. Navigate to **Portainer → Stacks**
2. Click **"Add stack"**
3. Configure:
   - **Name**: `puffin-app`
   - **Build method**: "Repository"
   - **Repository URL**: `https://code.puffinoffset.com/matt/puffin-app.git`
   - **Repository reference**: `refs/heads/main`
   - **Compose path**: `docker-compose.portainer.yml`
   - **Authentication**: Configure with your Gitea credentials
4. Click **"Deploy the stack"**

### Step 4: Verify Deployment

1. Check that the container is running:
   - Navigate to **Portainer → Containers**
   - Look for `puffin-app-web-1` or similar
   - Status should be "running"

2. Test the application:
   - Access: `http://your-server:3800`
   - Or via your Nginx reverse proxy configuration

3. Check logs if needed:
   - Click on the container
   - Select **"Logs"** tab

## Updating to New Versions

### Method 1: Using Portainer UI (Recommended)

1. Navigate to **Portainer → Stacks**
2. Click on **puffin-app** stack
3. Click **"Update the stack"**
4. Enable **"Pull latest image version"**
5. Enable **"Re-pull image and redeploy"**
6. Click **"Update"**

Portainer will:
- Pull the latest image from Gitea registry
- Recreate the container with the new image
- Maintain your environment variables and configuration

### Method 2: Pull Specific Version

To rollback or deploy a specific commit:

1. Edit the stack in Portainer
2. Change the image tag from `latest` to `main-<commit-sha>`
   ```yaml
   image: code.puffinoffset.com/matt/puffin-app:main-abc1234
   ```
3. Update the stack

## Monitoring Build Status

### Check Gitea Actions

1. Go to your Gitea repository: `https://code.puffinoffset.com/matt/puffin-app`
2. Navigate to **"Actions"** tab
3. View recent workflow runs
4. Click on a run to see detailed logs

### Verify Image in Registry

1. In Gitea, navigate to **"Packages"** or **"Registry"**
2. Look for `puffin-app` images
3. Verify tags: `latest` and `main-<sha>` tags should be present

## Troubleshooting

### Build Failed in Gitea Actions

**Check the workflow logs:**
1. Go to Gitea → puffin-app → Actions
2. Click on the failed run
3. Review error messages

**Common issues:**
- Registry authentication failed: Check secrets.GITHUB_TOKEN is available
- Build errors: Review Dockerfile and build logs
- Network issues: Check runner connectivity

### Image Pull Failed in Portainer

**Error:** `unauthorized: authentication required`

**Solution:**
1. Verify registry is configured in Portainer (Step 1)
2. Check credentials are correct
3. Ensure registry URL is `code.puffinoffset.com` (no `https://`)

### Container Won't Start

**Check environment variables:**
1. Verify `.env` file exists on the host
2. Ensure volume mount path is correct in docker-compose.portainer.yml
3. Check container logs for missing env var errors

**Check port conflicts:**
1. Ensure port 3800 is not already in use
2. Run `netstat -tuln | grep 3800` on the host

### Application Not Accessible

**Verify container is running:**
```bash
docker ps | grep puffin-app
```

**Check nginx reverse proxy:**
- Review host Nginx configuration (`nginx-host.conf`)
- Ensure proxy_pass points to correct container port
- Test direct access: `http://server-ip:3800`

**Check firewall:**
```bash
# Example for ufw
sudo ufw status
sudo ufw allow 3800/tcp
```

## Environment Variables Reference

| Variable | Description | Required |
|----------|-------------|----------|
| `VITE_WREN_API_TOKEN` | Wren Climate API authentication token | Yes |
| `VITE_FORMSPREE_CONTACT_ID` | Formspree contact form endpoint ID | Yes |
| `VITE_FORMSPREE_OFFSET_ID` | Formspree offset order form endpoint ID | Yes |
| `NODE_ENV` | Node environment (set to `production`) | Auto-set |

## Rollback Procedure

To rollback to a previous version:

1. Find the commit SHA of the working version
2. In Portainer, edit the stack
3. Change image tag to `main-<previous-sha>`
4. Update the stack

Example:
```yaml
# Before (current broken version)
image: code.puffinoffset.com/matt/puffin-app:latest

# After (rollback to specific commit)
image: code.puffinoffset.com/matt/puffin-app:main-ab0dbbd
```

## Security Best Practices

1. **Never commit `.env` file to git** (already in .gitignore)
2. **Use Gitea access tokens** instead of passwords for registry auth
3. **Restrict registry access** to necessary users
4. **Review Gitea Actions logs** for sensitive data exposure
5. **Keep base images updated** (node:20-alpine, nginx:alpine)

## Next Steps

- Set up monitoring/alerting for failed builds
- Configure automatic backups of `.env` file
- Implement health checks in docker-compose
- Set up SSL certificates via Let's Encrypt
- Configure log aggregation for production debugging
