puffin-app/DEPLOYMENT.md
Matt bc9e2d3782
All checks were successful
Build and Push Docker Images / docker (push) Successful in 1m22s
Implement comprehensive Stripe security fixes and production deployment
CRITICAL SECURITY FIXES:
- Add webhook secret validation to prevent signature bypass
- Implement idempotency protection across all webhook handlers
- Add atomic database updates to prevent race conditions
- Improve CORS security with origin validation and logging
- Remove .env from git tracking to protect secrets

STRIPE INTEGRATION:
- Add support for checkout.session.expired webhook event
- Add Stripe publishable key to environment configuration
- Fix webhook handlers with proper idempotency checks
- Update Order model with atomic updatePaymentAndStatus method
- Add comprehensive logging for webhook processing

DEPLOYMENT ARCHITECTURE:
- Split into two Docker images (frontend-latest, backend-latest)
- Update CI/CD to build separate frontend and backend images
- Configure backend on port 3801 (internal 3001)
- Add production-ready docker-compose.yml
- Remove redundant docker-compose.portainer.yml
- Update nginx configuration for both frontend and backend

DOCUMENTATION:
- Add PRODUCTION-SETUP.md with complete deployment guide
- Add docs/stripe-security-fixes.md with security audit details
- Add docs/stripe-checkout-sessions.md with integration docs
- Add docs/stripe-webhooks.md with webhook configuration
- Update .env.example with all required variables including Stripe publishable key

CONFIGURATION:
- Consolidate to single .env.example template
- Update .gitignore to protect all .env variants
- Add server/Dockerfile for backend container
- Update DEPLOYMENT.md with new architecture

🔒 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 12:18:57 +01:00

7.3 KiB

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:

# 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

  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>
    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:

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:

# 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:

# 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