# MotoVaultPro GitLab CI/CD Deployment Guide

Complete guide for deploying MotoVaultPro using GitLab CI/CD with shell executor runners.

## Table of Contents

1. [Prerequisites](#prerequisites)
2. [GitLab Runner Setup](#gitlab-runner-setup)
3. [CI/CD Variables Configuration](#cicd-variables-configuration)
4. [Secrets Architecture](#secrets-architecture)
5. [Pipeline Overview](#pipeline-overview)
6. [Deployment Process](#deployment-process)
7. [Rollback Procedure](#rollback-procedure)
8. [Troubleshooting](#troubleshooting)

---

## Prerequisites

### Server Requirements

- Linux server with Docker Engine installed
- Docker Compose v2 (plugin version)
- GitLab Runner installed and registered
- Git installed
- curl installed (for health checks)

### GitLab Requirements

- GitLab 18.6+ (tested with 18.6.2)
- Project with CI/CD enabled
- Protected `main` branch
- Maintainer access for CI/CD variable configuration

---

## GitLab Runner Setup

### 1. Verify Runner Registration

```bash
sudo gitlab-runner verify
```

Expected output should show your runner as active with shell executor.

### 2. Verify Docker Permissions

The `gitlab-runner` user must have Docker access:

```bash
# Add gitlab-runner to docker group (if not already done)
sudo usermod -aG docker gitlab-runner

# Verify access
sudo -u gitlab-runner docker info
sudo -u gitlab-runner docker compose version
```

### 3. Verify Deployment Directory

Ensure the deployment directory exists and is accessible:

```bash
# Create deployment directory
sudo mkdir -p /opt/motovaultpro
sudo chown gitlab-runner:gitlab-runner /opt/motovaultpro

# Clone repository (first time only)
sudo -u gitlab-runner git clone <repository-url> /opt/motovaultpro
```

---

## CI/CD Variables Configuration

Navigate to **Settings > CI/CD > Variables** in your GitLab project.

### Secrets (File Type Variables)

These variables use GitLab's **File** type, which writes the value to a temporary file and provides the path as the environment variable. This replicates the Kubernetes secrets pattern used by the application.

| Variable Name | Type | Protected | Masked | Description |
|--------------|------|-----------|--------|-------------|
| `POSTGRES_PASSWORD` | File | Yes | Yes | PostgreSQL database password |
| `AUTH0_CLIENT_SECRET` | File | Yes | Yes | Auth0 client secret for backend |
| `GOOGLE_MAPS_API_KEY` | File | Yes | Yes | Google Maps API key |
| `GOOGLE_MAPS_MAP_ID` | File | Yes | No | Google Maps Map ID |
| `CF_DNS_API_TOKEN` | File | Yes | Yes | Cloudflare API token for Let's Encrypt DNS challenge |

### Configuration Variables

| Variable Name | Type | Protected | Masked | Value |
|--------------|------|-----------|--------|-------|
| `VITE_AUTH0_DOMAIN` | Variable | No | No | `motovaultpro.us.auth0.com` |
| `VITE_AUTH0_CLIENT_ID` | Variable | No | No | Your Auth0 client ID |
| `VITE_AUTH0_AUDIENCE` | Variable | No | No | `https://api.motovaultpro.com` |

Note: `DEPLOY_PATH` is automatically set in `.gitlab-ci.yml` using `GIT_CLONE_PATH` for a stable path.

### Creating Cloudflare API Token

The `CF_DNS_API_TOKEN` is required for automatic SSL certificate generation via Let's Encrypt DNS-01 challenge.

1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com/profile/api-tokens)
2. Click **Create Token**
3. Use template: **Edit zone DNS**
4. Configure permissions:
   - **Permissions**: Zone > DNS > Edit
   - **Zone Resources**: Include > Specific zone > `motovaultpro.com`
5. Click **Continue to summary** then **Create Token**
6. Copy the token value immediately (it won't be shown again)
7. Add as `CF_DNS_API_TOKEN` File variable in GitLab

### Setting Up a File Type Variable

1. Go to **Settings > CI/CD > Variables**
2. Click **Add variable**
3. Enter the variable key (e.g., `POSTGRES_PASSWORD`)
4. Enter the secret value in the **Value** field
5. Set **Type** to **File**
6. Enable **Protect variable** (recommended)
7. Enable **Mask variable** (for sensitive data)
8. Click **Add variable**

---

## Secrets Architecture

MotoVaultPro uses a Kubernetes-style secrets pattern where secrets are mounted as files at `/run/secrets/` inside containers.

### How It Works

1. **GitLab stores secrets** as File type CI/CD variables
2. **During pipeline execution**, GitLab writes each secret to a temporary file
3. **The `inject-secrets.sh` script** copies these files to `secrets/app/` directory
4. **Docker Compose** mounts these files to `/run/secrets/` in containers
5. **Application code** reads secrets from the filesystem (not environment variables)

### Secret Files

```
secrets/app/
  postgres-password.txt       -> /run/secrets/postgres-password
  auth0-client-secret.txt     -> /run/secrets/auth0-client-secret
  google-maps-api-key.txt     -> /run/secrets/google-maps-api-key
  google-maps-map-id.txt      -> /run/secrets/google-maps-map-id
  cloudflare-dns-token.txt    -> /run/secrets/cloudflare-dns-token
```

### Security Benefits

- Secrets never appear as environment variables (not visible in `env` or `printenv`)
- File permissions (600) restrict access
- Masked variables prevent accidental log exposure
- Protected variables only available on protected branches

---

## Pipeline Overview

The CI/CD pipeline consists of four stages:

### Stage 1: Validate

Verifies deployment prerequisites:
- Docker is accessible
- Docker Compose is available
- Deployment directory exists

### Stage 2: Build

Builds Docker images:
- Pulls latest code from repository
- Builds all service images with `--no-cache`

### Stage 3: Deploy

Deploys the application:
1. Injects secrets from GitLab variables
2. Stops existing services gracefully
3. Pulls base images
4. Starts database services (PostgreSQL, Redis)
5. Runs database migrations
6. Starts all services

### Stage 4: Verify

Validates deployment health:
- Checks all containers are running
- Tests backend health endpoint
- Reports deployment status

### Pipeline Diagram

```
[Validate] -> [Build] -> [Deploy] -> [Verify]
     |            |          |           |
   Check       Build      Inject      Health
  prereqs     images     secrets      checks
                            |
                         Migrate
                            |
                         Start
                        services
```

---

## Deployment Process

### Automatic Deployment

Deployments are triggered automatically when:
- Code is pushed to the `main` branch
- A merge request is merged into `main`

### Manual Deployment

To trigger a manual deployment:

1. Go to **CI/CD > Pipelines**
2. Click **Run pipeline**
3. Select the `main` branch
4. Click **Run pipeline**

### Deployment Steps (What Happens)

1. **Secrets Injection**
   - `inject-secrets.sh` copies GitLab File variables to `secrets/app/`
   - Permissions are set to 600 for security

2. **Service Shutdown**
   - Existing containers are stopped gracefully (30s timeout)
   - Volumes are preserved

3. **Database Startup**
   - PostgreSQL and Redis start first
   - 15-second wait for database readiness

4. **Migrations**
   - Backend container runs database migrations
   - Ensures schema is up-to-date

5. **Full Service Startup**
   - All services start via `docker compose up -d`
   - Traefik routes traffic automatically

6. **Health Verification**
   - Container status checks
   - Backend health endpoint validation

---

## Rollback Procedure

### Automatic Rollback

If the verify stage fails, the pipeline will report failure but services remain running. Manual intervention is required.

### Manual Rollback

Use the rollback script:

```bash
# SSH to server
ssh user@server

# Run rollback to previous commit
cd /opt/motovaultpro
./scripts/rollback.sh HEAD~1

# Or rollback to specific tag/commit
./scripts/rollback.sh v1.0.0
```

### Rollback Script Details

The script performs:
1. Stops all current services
2. Checks out the specified version
3. Rebuilds images
4. Starts services

### Emergency Recovery

If rollback fails:

```bash
cd /opt/motovaultpro

# Stop everything
docker compose down

# Check git history
git log --oneline -10

# Checkout known working version
git checkout <commit-hash>

# Rebuild and start
docker compose build
docker compose up -d

# Verify
docker compose ps
```

---

## Troubleshooting

### Pipeline Fails at Validate Stage

**Symptom**: `DEPLOY_PATH not found`

**Solution**:
```bash
# Create directory on runner server
sudo mkdir -p /opt/motovaultpro
sudo chown gitlab-runner:gitlab-runner /opt/motovaultpro
```

### Pipeline Fails at Build Stage

**Symptom**: Docker build errors

**Solutions**:
1. Check Dockerfile syntax
2. Verify network connectivity for npm/package downloads
3. Check disk space: `df -h`
4. Clear Docker cache: `docker system prune -a`

### Pipeline Fails at Deploy Stage

**Symptom**: Secrets injection fails

**Solutions**:
1. Verify CI/CD variables are configured correctly
2. Check variable types are set to **File** for secrets
3. Ensure variables are not restricted to specific environments

**Symptom**: Migration fails

**Solutions**:
1. Check database connectivity
2. Verify PostgreSQL is healthy: `docker logs mvp-postgres`
3. Run migrations manually:
   ```bash
   docker compose exec mvp-backend npm run migrate
   ```

### Pipeline Fails at Verify Stage

**Symptom**: Container not running

**Solutions**:
1. Check container logs: `docker logs <container-name>`
2. Verify secrets are correctly mounted
3. Check for port conflicts

**Symptom**: Health check fails

**Solutions**:
1. Wait longer (service might be starting)
2. Check backend logs: `docker logs mvp-backend`
3. Verify database connection

### Services Start But Application Doesn't Work

**Check secrets are mounted**:
```bash
docker compose exec mvp-backend ls -la /run/secrets/
```

**Check configuration**:
```bash
docker compose exec mvp-backend cat /app/config/production.yml
```

**Check network connectivity**:
```bash
docker network ls
docker network inspect motovaultpro_backend
```

### Viewing Logs

```bash
# All services
docker compose logs -f

# Specific service
docker compose logs -f mvp-backend

# Last 100 lines
docker compose logs --tail 100 mvp-backend
```

---

## Maintenance

### Updating Secrets

1. Update the CI/CD variable in GitLab
2. Trigger a new pipeline (push or manual)
3. The new secrets will be injected during deployment

### Database Backups

Backups should be configured separately. Recommended approach:

```bash
# Manual backup
docker compose exec mvp-postgres pg_dump -U postgres motovaultpro > backup.sql

# Automated backup (add to cron)
0 2 * * * cd /opt/motovaultpro && docker compose exec -T mvp-postgres pg_dump -U postgres motovaultpro > /backups/mvp-$(date +\%Y\%m\%d).sql
```

### Monitoring

Consider adding:
- Prometheus metrics (Traefik already configured)
- Health check alerts
- Log aggregation

---

## Quick Reference

### Common Commands

```bash
# View pipeline status
# GitLab UI: CI/CD > Pipelines

# SSH to server
ssh user@your-server

# Navigate to project
cd /opt/motovaultpro

# View running containers
docker compose ps

# View logs
docker compose logs -f

# Restart a service
docker compose restart mvp-backend

# Run migrations manually
docker compose exec mvp-backend npm run migrate

# Access database
docker compose exec mvp-postgres psql -U postgres motovaultpro

# Health check
curl http://localhost:3001/health
```

### Important Paths

| Path | Description |
|------|-------------|
| `$CI_BUILDS_DIR/motovaultpro` | Application root (stable clone path) |
| `$CI_BUILDS_DIR/motovaultpro/secrets/app/` | Secrets directory |
| `$CI_BUILDS_DIR/motovaultpro/data/documents/` | Document storage |
| `$CI_BUILDS_DIR/motovaultpro/config/` | Configuration files |

Note: `CI_BUILDS_DIR` is typically `/opt/gitlab-runner/builds` for shell executors.

### Container Names

| Container | Purpose |
|-----------|---------|
| `mvp-traefik` | Reverse proxy, TLS termination |
| `mvp-frontend` | React SPA |
| `mvp-backend` | Node.js API |
| `mvp-postgres` | PostgreSQL database |
| `mvp-redis` | Redis cache |
