# Funnelz — Backup & Restore Procedure

## Backup

Backups are created daily by `cron/backup.php`. Each backup is:
- A full MySQL dump (all tables, structure + data)
- Encrypted with the app's `ENCRYPTION_KEY` using libsodium `crypto_secretbox`
- Stored in `storage/backups/` with a 7-day rolling retention

### Manual backup

```bash
php cron/backup.php
```

---

## Restore

### 1. Locate the backup file

```bash
ls storage/backups/
# backup-2025-01-15-020000.sql.enc
```

### 2. Decrypt the backup

```php
<?php
require_once 'vendor/autoload.php';
use Config\Env;
Env::load('.env');

$key      = base64_decode(Env::require('ENCRYPTION_KEY'), true);
$encoded  = file_get_contents('storage/backups/backup-YYYY-MM-DD-HHMMSS.sql.enc');
$decoded  = base64_decode($encoded, true);
$nonce    = substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher   = substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$sql      = sodium_crypto_secretbox_open($cipher, $nonce, $key);
file_put_contents('restore.sql', $sql);
echo "Decrypted to restore.sql\n";
```

### 3. Import the SQL

Using a MySQL client (e.g. phpMyAdmin, TablePlus, or MySQL CLI if available):

```sql
SOURCE /path/to/restore.sql;
```

Or via phpMyAdmin: Import → select `restore.sql`.

### 4. Verify

- Log in to the application and confirm data is present
- Check `storage/logs/` for any errors
- Delete `restore.sql` after confirming the restore was successful

---

## Important notes

- The `ENCRYPTION_KEY` in `.env` must match the key used when the backup was created
- If the key has been rotated, you must use the old key to decrypt old backups
- Store a copy of your `ENCRYPTION_KEY` securely outside the server (e.g. a password manager)
- Test the restore procedure periodically — an untested backup is not a backup
