# Configuration Management System

## Overview

The configuration management system provides a safe, automated way to merge new configuration keys from version-controlled `.example` files into active configuration files during deployments. This system is essential for white-label installations where each deployment has custom configuration values that must be preserved across updates.

### The Problem It Solves

In a white-label Laravel application with multiple installations:
- **Active config files** (`config/timebank_cc.php`, `config/timebank-default.php`, `config/themes.php`) contain installation-specific custom values
- **Example config files** (`config/*.php.example`) are tracked in git and receive updates with new features
- During deployment, new configuration keys must be added **without overwriting existing custom values**
- Manual merging is error-prone and doesn't scale across multiple installations

### How It Works

The system uses a **deep merge algorithm** that:
1. Recursively compares active configs with their `.example` counterparts
2. Identifies new keys that don't exist in the active config
3. Adds only the new keys while preserving ALL existing custom values
4. Creates automatic timestamped backups before any changes
5. Validates the merged configuration can be loaded successfully

**Key Principle**: Existing values are NEVER overwritten. Only new keys are added.

### Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                        Deployment Flow                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  1. deploy.sh runs                                               │
│  2. Git pulls latest code (includes updated .example files)      │
│  3. Config merge check runs                                      │
│     ├─ Compares: config/file.php vs config/file.php.example     │
│     ├─ Detects: New keys in .example                            │
│     └─ Prompts: "Merge new keys? (y/N)"                         │
│  4. If user confirms:                                            │
│     ├─ Creates backup: storage/config-backups/file.php.backup.* │
│     ├─ Deep merges: Adds new keys, preserves existing values    │
│     ├─ Validates: Ensures merged config is valid PHP            │
│     └─ Logs: Records merge to Laravel log                       │
│  5. Deployment continues                                         │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘
```

### Files Managed

The system manages three configuration files:

| Config File | Purpose | Custom Values Example |
|------------|---------|----------------------|
| `config/themes.php` | Theme definitions and color schemes | Custom brand colors, font choices |
| `config/timebank-default.php` | Default platform configuration | Transaction limits, validation rules |
| `config/timebank_cc.php` | Installation-specific overrides | Platform name, currency, feature flags |

Each has a corresponding `.example` file tracked in git:
- `config/themes.php.example`
- `config/timebank-default.php.example`
- `config/timebank_cc.php.example`

## Setup Instructions

### Initial Installation

When setting up a new installation, the deployment script automatically creates active config files from examples if they don't exist:

```bash
# During first deployment, deploy.sh automatically runs:
for config_file in config/themes.php config/timebank-default.php config/timebank_cc.php; do
  if [ ! -f "$config_file" ] && [ -f "${config_file}.example" ]; then
    cp "${config_file}.example" "$config_file"
  fi
done
```

### Customizing Configuration

After initial setup, customize your active config files:

```php
// config/timebank_cc.php

return [
    'platform_name' => 'My TimeBank',  // Custom installation name
    'currency' => 'hours',              // Custom currency name

    'wirechat' => [
        'disappearing_messages' => [
            'duration' => 720,          // Custom: 12 hours instead of default 6
        ],
    ],

    'transactions' => [
        'limits' => [
            'user' => 1000,             // Custom: higher limit than default
        ],
    ],
];
```

**Important**: Never edit `.example` files for installation-specific changes. Always edit the active config files.

### Backup System

The system automatically manages backups:

- **Location**: `storage/config-backups/`
- **Format**: `{filename}.backup.{YYYY-MM-DD_HHmmss}`
- **Retention**: Last 5 backups per file (older ones auto-deleted)
- **Created**: Before every merge operation

Example backup files:
```
storage/config-backups/
├── timebank_cc.php.backup.2026-01-06_143022
├── timebank_cc.php.backup.2026-01-05_091534
├── timebank_cc.php.backup.2026-01-03_164411
├── themes.php.backup.2026-01-06_143022
└── themes.php.backup.2026-01-04_102357
```

## Updating Configuration / New Deploys

### Automatic Merge During Deployment

When running `deploy.sh`, the system automatically detects configuration updates:

```bash
./deploy.sh
```

**What happens**:

1. **Detection Phase**:
   ```
   ═══════════════════════════════════════════════════════════
   CHECKING FOR CONFIGURATION UPDATES
   ═══════════════════════════════════════════════════════════
   New configuration keys available in .example files
   Review changes with: php artisan config:merge --all --dry-run

   Would you like to merge new keys now? (y/N)
   ```

2. **If you press 'y'**:
   - Creates automatic backup
   - Merges new keys
   - Preserves all existing values
   - Shows summary of changes

3. **If you press 'N'**:
   - Deployment continues
   - You can merge manually later

### Manual Configuration Merge

You can merge configurations manually at any time:

#### Preview Changes (Dry-Run Mode)

**Recommended first step**: Always preview changes before applying:

```bash
# Preview all config files
php artisan config:merge --all --dry-run

# Preview specific config
php artisan config:merge timebank_cc --dry-run
```

**Example output**:
```
─────────────────────────────────────────────────────
Config: timebank_cc
─────────────────────────────────────────────────────
Found 3 new configuration key(s):

  + wirechat.notifications.sound_enabled
    true
  + wirechat.notifications.desktop_enabled
    true
  + footer.sections.2.links.3
    [route: static-contact, title: Contact, order: 3, visible: true]
```

#### Apply Changes

```bash
# Merge all configs (with confirmation prompts)
php artisan config:merge --all

# Merge specific config
php artisan config:merge timebank_cc
php artisan config:merge timebank-default
php artisan config:merge themes

# Merge without confirmation (automated deployments)
php artisan config:merge --all --force
```

**Interactive merge process**:
```
─────────────────────────────────────────────────────
Config: timebank_cc
─────────────────────────────────────────────────────
Found 3 new configuration key(s):

  + wirechat.notifications.sound_enabled
    true
  + wirechat.notifications.desktop_enabled
    true
  + footer.tagline
    "Your time is currency"

Merge these keys into timebank_cc? (yes/no) [no]:
> yes

  Backup created: storage/config-backups/timebank_cc.php.backup.2026-01-06_143022
✓ timebank_cc: Successfully merged 3 new keys
```

### Restoring from Backup

If you need to rollback a configuration change:

```bash
php artisan config:merge --restore
```

**Interactive restore process**:
```
Available backups:

timebank_cc.php
  1. 2026-01-06 14:30:22
  2. 2026-01-05 09:15:34
  3. 2026-01-03 16:44:11

themes.php
  4. 2026-01-06 14:30:22
  5. 2026-01-04 10:23:57

Enter backup number to restore (or 0 to cancel):
> 1

Restore timebank_cc.php from backup? (yes/no) [no]:
> yes

Current config backed up to: storage/config-backups/timebank_cc.php.backup.2026-01-06_144512
✓ Successfully restored timebank_cc.php
```

## Command Reference

### php artisan config:merge

Merge new configuration keys from `.example` files into active configs.

**Syntax**:
```bash
php artisan config:merge [file] [options]
```

**Arguments**:
- `file` - Specific config to merge: `themes`, `timebank-default`, or `timebank_cc` (optional)

**Options**:
- `--all` - Merge all config files
- `--dry-run` - Preview changes without applying
- `--force` - Skip confirmation prompts
- `--restore` - Restore from backup (interactive)

**Examples**:

```bash
# Preview all changes
php artisan config:merge --all --dry-run

# Merge all with confirmation
php artisan config:merge --all

# Merge specific file
php artisan config:merge timebank_cc

# Automated merge (no prompts)
php artisan config:merge --all --force

# Restore from backup
php artisan config:merge --restore
```

**Exit Codes**:
- `0` - Success (changes applied or no changes needed)
- `1` - Error (invalid file, backup failed, etc.)

## Deep Merge Algorithm

### How It Works

The deep merge algorithm recursively processes configuration arrays:

```php
function deepMergeNewKeys(current, example):
    result = current  // Start with existing config

    for each key, value in example:
        if key does NOT exist in current:
            // NEW KEY - Add it
            result[key] = value

        else if value is array AND current[key] is array:
            // Both are arrays - RECURSE
            result[key] = deepMergeNewKeys(current[key], value)

        else:
            // Key exists and not both arrays - PRESERVE current value
            // Do nothing - keep current[key] unchanged

    return result
```

### Merge Examples

#### Example 1: Adding New Top-Level Keys

**Current config**:
```php
[
    'platform_name' => 'My TimeBank',  // Custom value
    'currency' => 'hours',             // Custom value
]
```

**Example config** (from git update):
```php
[
    'platform_name' => 'TimeBank CC',  // Default value
    'currency' => 'time',              // Default value
    'timezone' => 'UTC',               // NEW KEY
]
```

**Result after merge**:
```php
[
    'platform_name' => 'My TimeBank',  // PRESERVED - custom value kept
    'currency' => 'hours',             // PRESERVED - custom value kept
    'timezone' => 'UTC',               // ADDED - new key
]
```

#### Example 2: Adding Nested Keys

**Current config**:
```php
[
    'wirechat' => [
        'disappearing_messages' => [
            'duration' => 720,  // Custom: 12 hours
        ],
    ],
]
```

**Example config** (from git update):
```php
[
    'wirechat' => [
        'disappearing_messages' => [
            'duration' => 360,          // Default: 6 hours
            'cleanup_schedule' => 'hourly',  // NEW KEY
        ],
        'notifications' => [            // NEW NESTED SECTION
            'sound_enabled' => true,
            'desktop_enabled' => true,
        ],
    ],
]
```

**Result after merge**:
```php
[
    'wirechat' => [
        'disappearing_messages' => [
            'duration' => 720,              // PRESERVED - custom value kept
            'cleanup_schedule' => 'hourly', // ADDED - new key
        ],
        'notifications' => [                // ADDED - entire new section
            'sound_enabled' => true,
            'desktop_enabled' => true,
        ],
    ],
]
```

#### Example 3: Array Values

**Current config**:
```php
[
    'allowed_types' => ['user', 'organization'],  // Custom list
]
```

**Example config** (from git update):
```php
[
    'allowed_types' => ['user', 'organization', 'bank'],  // Updated list
]
```

**Result after merge**:
```php
[
    'allowed_types' => ['user', 'organization'],  // PRESERVED - arrays not merged
]
```

**Note**: Array values are treated as complete values, not merged element-by-element. If you need the new array values, update them manually after reviewing the diff.

## Best Practices

### 1. Always Preview First

Before applying configuration merges, especially in production:

```bash
# See exactly what will change
php artisan config:merge --all --dry-run
```

### 2. Review Changes in Detail

When new keys are detected:
1. Review what each new key does (check git commit messages)
2. Verify default values are appropriate for your installation
3. Adjust values after merge if needed

### 3. Test After Merging

After merging configuration changes:

```bash
# Verify config can be loaded
php artisan config:cache

# Clear and rebuild cache
php artisan optimize:clear
php artisan optimize

# Test critical functionality
php artisan test
```

### 4. Keep Backups

The system keeps 5 backups automatically, but for major updates:

```bash
# Create manual backup before major changes
cp config/timebank_cc.php config/timebank_cc.php.manual-backup-$(date +%Y%m%d)
```

### 5. Document Custom Changes

Add comments to your active config files explaining why values differ from defaults:

```php
return [
    'transactions' => [
        'limits' => [
            // Custom: Increased from 500 to 1000 for high-volume community
            'user' => 1000,
        ],
    ],
];
```

### 6. Staged Deployments

For multi-server deployments:
1. Test config merge on staging server first
2. Verify application functionality
3. Then deploy to production with `--force` flag

```bash
# Staging (with prompts)
./deploy.sh

# Production (automated)
./deploy.sh --force
```

## Troubleshooting

### Config Merge Shows No Changes But I Know There Are Updates

**Cause**: The active config may already have the keys (possibly added manually).

**Solution**:
```bash
# Compare files manually
diff config/timebank_cc.php config/timebank_cc.php.example
```

### Merge Failed - Config Invalid

**Symptom**: Error message "Merged config is invalid"

**Cause**: Syntax error in merged configuration.

**Solution**: Automatic rollback occurs. Check Laravel log for details:
```bash
tail -50 storage/logs/laravel.log | grep "config:merge"
```

### Backup Directory Not Writable

**Symptom**: "Failed to create backup"

**Solution**: Ensure storage directory is writable:
```bash
chmod -R 775 storage
chown -R www-data:www-data storage  # Adjust user/group as needed
```

### Need to Restore But Backups Are Missing

**Cause**: Backups older than 5 merges were auto-deleted.

**Solution**:
- If config is in git-ignored files, check git stash
- Restore from server backups
- Manually recreate configuration

**Prevention**: Create manual backups before major updates.

### Config Merge Hangs During Deployment

**Cause**: Waiting for user input in automated environment.

**Solution**: Use `--force` flag in automated deployments:
```bash
# In deploy.sh for automated servers
php artisan config:merge --all --force
```

## Integration with CI/CD

### Automated Deployments

For CI/CD pipelines, use non-interactive mode:

```bash
# In deployment script
php artisan config:merge --all --force || {
    echo "Config merge failed - check logs"
    exit 1
}
```

### Pre-Deployment Validation

Check for config updates before deployment:

```bash
# In CI pipeline
if php artisan config:merge --all --dry-run | grep -q "Found [0-9]"; then
    echo "⚠️  Configuration updates detected - review required"
    php artisan config:merge --all --dry-run
fi
```

### Post-Deployment Verification

Verify config after deployment:

```bash
# Ensure config is valid
php artisan config:cache || {
    echo "Config cache failed - configuration may be invalid"
    exit 1
}

# Run config-dependent tests
php artisan test --filter ConfigTest
```

## Logging and Auditing

All configuration merges are logged to Laravel's log system:

```bash
# View recent config merges
tail -100 storage/logs/laravel.log | grep "Config merged"
```

**Log entry example**:
```json
{
    "level": "info",
    "message": "Config merged",
    "context": {
        "file": "timebank_cc",
        "path": "config/timebank_cc.php",
        "new_keys": [
            "wirechat.notifications.sound_enabled",
            "wirechat.notifications.desktop_enabled",
            "footer.tagline"
        ],
        "new_key_count": 3,
        "backup": "storage/config-backups/timebank_cc.php.backup.2026-01-06_143022"
    },
    "timestamp": "2026-01-06 14:30:22"
}
```

This provides a complete audit trail of all configuration changes.
