# Product Updates Storage Migration Guide

> **For:** Developers and System Administrators  
> **Last Updated:** January 2025  
> **Status:** Production Ready

---

## Overview

This guide provides step-by-step instructions for migrating Product Updates data and images from volatile `/tmp/` storage to persistent storage locations. This migration is **critical** if your system is currently using `/tmp/` storage, as data and images will be lost on server restart.

---

## Table of Contents

1. [Quick Diagnosis](#quick-diagnosis)
2. [Pre-Migration Checklist](#pre-migration-checklist)
3. [Step-by-Step Migration](#step-by-step-migration)
4. [Troubleshooting](#troubleshooting)
5. [Rollback Procedures](#rollback-procedures)
6. [Best Practices for Production](#best-practices-for-production)
7. [Post-Migration Verification](#post-migration-verification)

---

## Quick Diagnosis

### Check Current Storage Status

**Option 1: Admin Panel**

1. Log into admin panel: `/produkt-updates-admin`
2. Navigate to **Settings** section
3. Check **Storage Status** card
4. Look for warnings about volatile storage

**Option 2: Diagnostics Endpoint**
Visit: `/v2/api/produkt-updates-server-investigation.php`

Look for:

- `using_volatile_storage: true` → Migration needed
- `critical_issues` array → Lists specific problems
- `recommendations` array → Action items

**Option 3: Health Check**
Visit: `/v2/api/produkt-updates-storage-health.php`

Check `status` field:

- `ok` → No migration needed
- `warning` → Review issues
- `critical` → Migration required immediately

---

## Pre-Migration Checklist

Before starting migration, verify:

- [ ] Admin panel is accessible and functional
- [ ] Current data location identified (check diagnostics)
- [ ] Backup of current data file created (if exists)
- [ ] Target persistent location is writable
- [ ] Sufficient disk space available
- [ ] No active content editing in progress

### Verify Target Locations Are Writable

**For Data File:**

```bash
# Check if v2/data/ is writable
ls -la v2/data/
# Should show writable permissions (drwxrwxr-x or similar)

# If not writable, fix permissions:
chmod 755 v2/data/
chown www-data:www-data v2/data/  # Adjust user/group as needed
```

**For Images (canonical only):**

```bash
# Single canonical location - no fallbacks
mkdir -p wp-content/uploads/produkt-updates/
chmod 755 wp-content/uploads/produkt-updates/
chown www-data:www-data wp-content/uploads/produkt-updates/
```

---

## Proxy-to-Direct URL Migration (JSON Only)

**Script:** `scripts/migrate-produkt-updates-to-direct-paths.php`

Updates `featured_image` and inline `<img src>` in the JSON from proxy URLs to direct wp-content paths. **Does not copy or move image files.**

- **Proxy URL + file exists in wp-content** → Replace with direct URL
- **Proxy URL + file missing** → Clear (re-upload from admin as needed)
- **Already direct URL** → Leave as-is

```bash
php scripts/migrate-produkt-updates-to-direct-paths.php --dry-run  # Preview
php scripts/migrate-produkt-updates-to-direct-paths.php          # Execute
```

---

## Step-by-Step Migration

### Phase 1: Data File Migration

#### Step 1.1: Check Current State

Visit: `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=check`

Review the response:

- `migration_needed`: Should be `true` if data is in `/tmp/`
- `migration_possible`: Should be `true` if target is writable
- `warnings`: Read any warnings carefully

#### Step 1.2: Create Backup

**Manual Backup:**

```bash
# If data exists in /tmp/
cp /tmp/produkt_updates.json v2/data/backups/produkt_updates_backup_$(date +%Y%m%d_%H%M%S).json

# If data exists in v2/data/
cp v2/data/produkt_updates.json v2/data/backups/produkt_updates_backup_$(date +%Y%m%d_%H%M%S).json
```

**Automatic Backup:**
The migration script creates automatic backups before migration.

#### Step 1.3: Perform Migration

Visit: `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=migrate`

**Expected Response:**

```json
{
  "success": true,
  "message": "Migration completed successfully",
  "data": {
    "source": "/tmp/produkt_updates.json",
    "destination": "/path/to/v2/data/produkt_updates.json",
    "backup": "/path/to/backup/file.json",
    "file_size": 12345,
    "months_count": 2,
    "current_month": "november-2025"
  }
}
```

#### Step 1.4: Verify Migration

1. **Check Admin Panel:**

   - Log into admin panel
   - Navigate to Dashboard
   - Verify features/improvements are visible
   - Check Settings > Storage Status shows persistent location

2. **Check Public Pages:**

   - Visit `/produkt-updates`
   - Verify content displays correctly
   - Check monthly pages load properly

3. **Verify File Location:**
   ```bash
   ls -la v2/data/produkt_updates.json
   # Should show file exists and is readable
   ```

---

### Phase 2: Image Migration

#### Step 2.1: Check Current State

Visit: `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=check`

Review the response:

- `images_to_migrate`: Array of images to migrate
- `total_images`: Count of images to migrate
- `total_size`: Total size of images
- `migration_possible`: Should be `true` if target is writable

#### Step 2.2: Perform Migration

Visit: `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=migrate&cleanup=0`

**Note:** Set `cleanup=0` initially to keep old files for safety.

**Expected Response:**

```json
{
  "success": true,
  "message": "Migration completed: 5 migrated, 0 failed, 0 skipped, 5 JSON references updated, 0 cleaned up",
  "data": {
    "migrated": [...],
    "failed": [],
    "skipped": [],
    "json_updates": [...],
    "cleaned_up": []
  }
}
```

#### Step 2.3: Verify Images

Visit: `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=verify`

**Expected Response:**

```json
{
  "success": true,
  "message": "Verification completed: 5/5 images accessible",
  "data": {
    "total_references": 5,
    "accessible": 5,
    "missing": 0
  }
}
```

#### Step 2.4: Test Image Display

1. **Admin Panel:**

   - Edit a feature with an image
   - Verify image displays in editor
   - Save and verify image persists

2. **Public Pages:**
   - Visit feature pages with images
   - Verify images load correctly
   - Check image URLs point to proxy endpoint

#### Step 2.5: Cleanup (Optional)

After verifying everything works:

Visit: `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=migrate&cleanup=1`

This removes old image files from `/tmp/` location.

**Warning:** Only run cleanup after verifying all images work correctly!

---

## Troubleshooting

### Issue: Migration Script Returns "Unauthorized"

**Solution:**

1. Log into admin panel first: `/produkt-updates-admin`
2. Keep session active
3. Open migration script in new tab/window
4. Script will use existing session

---

### Issue: "Target directory is not writable"

**Symptoms:**

- Migration script returns error about writable directory
- Diagnostics show target location not writable

**Solution:**

**For Data Directory:**

```bash
# Check current permissions
ls -la v2/data/

# Fix permissions
chmod 755 v2/data/
chown www-data:www-data v2/data/  # Adjust user/group

# Verify
ls -la v2/data/
```

**For Image Directory:**

```bash
# Create directory if doesn't exist
mkdir -p v2/data/images/produkt-updates/

# Fix permissions
chmod 755 v2/data/images/produkt-updates/
chown www-data:www-data v2/data/images/produkt-updates/

# Verify
ls -la v2/data/images/produkt-updates/
```

**Alternative:** If you cannot change permissions, use `v2/temp/` or `v2/cache/` directories (they should be writable).

---

### Issue: "Data file not found in /tmp/"

**Symptoms:**

- Migration script says no data to migrate
- Admin panel shows empty
- But public pages still show content

**Analysis:**
This indicates data might be in persistent location but admin panel is reading from wrong location.

**Solution:**

1. **Check all locations:**

   ```bash
   # Check persistent location
   ls -la v2/data/produkt_updates.json

   # Check temp location
   ls -la /tmp/produkt_updates.json
   ```

2. **Verify path resolution:**

   - Visit: `/v2/api/produkt-updates-data-location-check.php`
   - Check `writable_location` vs `readable_location`
   - If they differ, path resolution needs fixing

3. **Fix path resolution:**
   - Ensure `v2/data/` is writable
   - Clear any `/tmp/` files
   - Restart PHP/web server if needed
   - System should now use persistent location

---

### Issue: Images Not Displaying After Migration

**Symptoms:**

- Images migrated successfully
- But images don't display on website
- Image URLs return 404

**Solution:**

1. **Check Image Proxy Endpoint:**

   - Visit: `/v2/api/serve-produkt-updates-image.php?file=test.jpg`
   - Should return image or "Image not found"
   - If 404, check file exists in target location

2. **Verify Image Paths in JSON:**

   - Check JSON data file
   - Verify image paths use proxy endpoint format: `/v2/api/serve-produkt-updates-image.php?file=filename.jpg`
   - If paths are wrong, re-run migration with `action=verify`

3. **Check File Permissions:**

   ```bash
   ls -la v2/data/images/produkt-updates/
   # Files should be readable (644 permissions)
   ```

4. **Re-run Migration:**
   - Migration script updates JSON references automatically
   - If references weren't updated, re-run migration
   - Check `json_updates` array in response

---

### Issue: Admin Panel Shows Empty After Migration

**Symptoms:**

- Migration completed successfully
- But admin panel shows no entries
- Public pages still show content

**Analysis:**
This suggests admin panel is reading from different location than where data was migrated.

**Solution:**

1. **Check Current Locations:**

   - Visit: `/v2/api/produkt-updates-data-location-check.php`
   - Compare `writable_location` and `readable_location`

2. **Verify Data File:**

   ```bash
   # Check if data exists in persistent location
   cat v2/data/produkt_updates.json | head -20
   # Should show JSON content
   ```

3. **Clear Cache:**

   - Clear browser cache
   - Clear PHP opcache if enabled
   - Restart web server if needed

4. **Check File Permissions:**
   ```bash
   ls -la v2/data/produkt_updates.json
   # Should be readable (644 permissions)
   ```

---

### Issue: "JSON data file is corrupted"

**Symptoms:**

- Migration script reports invalid JSON
- Diagnostics show JSON error

**Solution:**

1. **Check JSON File:**

   ```bash
   # Validate JSON syntax
   php -r "json_decode(file_get_contents('v2/data/produkt_updates.json')); echo json_last_error() === JSON_ERROR_NONE ? 'Valid' : json_last_error_msg();"
   ```

2. **Restore from Backup:**

   - Check `v2/data/backups/` directory
   - Find most recent backup
   - Restore: `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=rollback&backup=/path/to/backup.json`

3. **Manual Fix:**
   - Open JSON file in text editor
   - Fix syntax errors
   - Validate JSON online: https://jsonlint.com/
   - Save and verify

---

## Rollback Procedures

### Rollback Data Migration

If migration caused issues, rollback data:

**Option 1: Via Script**
Visit: `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=rollback`

Script will:

- Find most recent backup
- Restore backup to primary location
- Verify restored data is valid

**Option 2: Manual Rollback**

```bash
# Find backup file
ls -lt v2/data/backups/produkt_updates_*.json | head -1

# Restore backup
cp v2/data/backups/produkt_updates_YYYYMMDD_HHMMSS.json v2/data/produkt_updates.json

# Verify
cat v2/data/produkt_updates.json | head -20
```

### Rollback Image Migration

Image migration doesn't delete originals by default (`cleanup=0`), so rollback is simple:

1. **Check Original Location:**

   ```bash
   ls -la /tmp/produkt-updates-images/
   # Original images should still be there
   ```

2. **Revert JSON References:**

   - Restore JSON file from backup (see data rollback)
   - Or manually update image paths in JSON

3. **Re-run Migration:**
   - If needed, re-run migration with different target location

---

## Best Practices for Production

### Pre-Deploy Checklist (REQUIRED)

**Single canonical location:** Product Updates uses only `wp-content/uploads/produkt-updates/` for images. No fallbacks. If this directory is not writable, uploads will fail.

**Before every deployment:**

```bash
# Create wp-content/uploads/produkt-updates/ if missing
mkdir -p wp-content/uploads/produkt-updates/
chmod 755 wp-content/uploads/produkt-updates/
chown www-data:www-data wp-content/uploads/produkt-updates/  # Adjust for your web server user (e.g. apache, nginx)

# Verify writability
touch wp-content/uploads/produkt-updates/.test && rm wp-content/uploads/produkt-updates/.test && echo "Writable OK"
```

**Migration (one-time):** If JSON contains proxy URLs, run the migration script. It updates URLs only (no file copy). Missing images are cleared; re-upload from admin.
```bash
php scripts/migrate-produkt-updates-to-direct-paths.php --dry-run  # Preview
php scripts/migrate-produkt-updates-to-direct-paths.php          # Execute
```

### Production Image Storage Checklist (CRITICAL)

**Canonical location:** `wp-content/uploads/produkt-updates/` is the only supported image storage. Images are served directly (no proxy). Fallback locations have been removed.

**Before deployment:**

```bash
# Create and ensure wp-content/uploads/produkt-updates/ exists and is writable
mkdir -p wp-content/uploads/produkt-updates/
chmod 755 wp-content/uploads/produkt-updates/
chown www-data:www-data wp-content/uploads/produkt-updates/  # Adjust for your web server user

# Verify
touch wp-content/uploads/produkt-updates/.test && rm wp-content/uploads/produkt-updates/.test && echo "Writable OK"
```

If uploads fail with "Upload directory is not writable", run the diagnostics endpoint and fix permissions.

### Directory Permissions

**Recommended Permissions:**

```bash
# Data directory
chmod 755 v2/data/
chown www-data:www-data v2/data/

# Data file
chmod 644 v2/data/produkt_updates.json
chown www-data:www-data v2/data/produkt_updates.json

# Image directory (canonical - no fallbacks)
mkdir -p wp-content/uploads/produkt-updates/
chmod 755 wp-content/uploads/produkt-updates/
chown www-data:www-data wp-content/uploads/produkt-updates/
```

### Regular Backups

**Automated Backup Script:**

```bash
#!/bin/bash
# Backup product updates data daily
BACKUP_DIR="v2/data/backups"
DATE=$(date +%Y%m%d_%H%M%S)
cp v2/data/produkt_updates.json "$BACKUP_DIR/produkt_updates_$DATE.json"
# Keep only last 30 days
find "$BACKUP_DIR" -name "produkt_updates_*.json" -mtime +30 -delete
```

**Add to Cron:**

```cron
# Daily backup at 2 AM
0 2 * * * /path/to/backup-script.sh
```

### Monitoring

**Health Check Endpoint:**
Set up monitoring to check: `/v2/api/produkt-updates-storage-health.php`

**Alert Conditions:**

- `status: "critical"` → Immediate action required
- `using_volatile_storage: true` → Migration needed
- `data_sync_issue: true` → Path resolution issue

**Example Monitoring Script:**

```bash
#!/bin/bash
HEALTH=$(curl -s https://www.ordio.com/v2/api/produkt-updates-storage-health.php)
STATUS=$(echo $HEALTH | jq -r '.status')

if [ "$STATUS" != "ok" ]; then
    echo "ALERT: Product Updates storage health check failed"
    echo "$HEALTH" | mail -s "Storage Health Alert" admin@ordio.com
fi
```

### Disk Space Monitoring

**Check Disk Usage:**

```bash
# Check data file size
du -h v2/data/produkt_updates.json

# Check image directory size
du -sh v2/data/images/produkt-updates/

# Set up alerts if usage exceeds threshold
```

---

## Post-Migration Verification

### Verification Checklist

After migration, verify:

- [ ] **Admin Panel:**

  - [ ] Dashboard shows correct statistics
  - [ ] Features list displays correctly
  - [ ] Improvements list displays correctly
  - [ ] Can create new features/improvements
  - [ ] Can edit existing items
  - [ ] Settings > Storage Status shows persistent location
  - [ ] No warnings about volatile storage

- [ ] **Public Pages:**

  - [ ] Main page (`/produkt-updates`) loads correctly
  - [ ] Monthly pages load correctly
  - [ ] Individual feature posts load correctly
  - [ ] Images display correctly
  - [ ] Navigation links work

- [ ] **Storage:**

  - [ ] Data file exists in `v2/data/produkt_updates.json`
  - [ ] Images exist in `v2/data/images/produkt-updates/`
  - [ ] File permissions are correct
  - [ ] Health check returns `status: "ok"`

- [ ] **Functionality:**
  - [ ] Can upload new images
  - [ ] Can delete images
  - [ ] Can save edits
  - [ ] No errors in browser console
  - [ ] No errors in server logs

### Verification Commands

```bash
# Check data file
ls -lh v2/data/produkt_updates.json
cat v2/data/produkt_updates.json | jq '.months | keys | length'
# Should show number of months

# Check images
ls -lh v2/data/images/produkt-updates/ | wc -l
# Should show image count

# Check health
curl -s https://www.ordio.com/v2/api/produkt-updates-storage-health.php | jq '.status'
# Should return "ok"

# Check diagnostics
curl -s https://www.ordio.com/v2/api/produkt-updates-server-investigation.php | jq '.summary.using_volatile_storage'
# Should return false
```

---

## Quick Reference

### Migration URLs

- **Check Data:** `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=check`
- **Migrate Data:** `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=migrate`
- **Rollback Data:** `/v2/admin/produkt-updates/migrate-to-persistent-storage.php?action=rollback`
- **Check Images:** `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=check`
- **Migrate Images:** `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=migrate&cleanup=0`
- **Verify Images:** `/v2/admin/produkt-updates/migrate-images-to-persistent.php?action=verify`

### Diagnostic URLs

- **Server Investigation:** `/v2/api/produkt-updates-server-investigation.php`
- **Data Location Check:** `/v2/api/produkt-updates-data-location-check.php`
- **Image Investigation:** `/v2/api/produkt-updates-image-investigation.php`
- **Storage Health:** `/v2/api/produkt-updates-storage-health.php`
- **Diagnostics:** `/v2/api/produkt-updates-diagnostics.php`

### Storage Locations

**Data File:**

- Primary: `v2/data/produkt_updates.json`
- Fallback: `/tmp/produkt_updates.json` (volatile)

**Images:**

- Primary: `v2/data/images/produkt-updates/`
- Secondary: `v2/temp/produkt-updates/`
- Tertiary: `v2/cache/produkt-updates/`
- Fallback: `/tmp/produkt-updates-images/` (volatile)

---

## Support

If you encounter issues not covered in this guide:

1. Check diagnostics endpoints for detailed error information
2. Review server error logs
3. Check browser console for client-side errors
4. Verify file permissions and ownership
5. Contact system administrator for permission issues

---

## Related Documentation

- **Path Resolution:** `v2/includes/produkt-updates-paths.php` (source code documentation)
- **Admin Panel Guide:** See Notion documentation for product updates system
- **API Documentation:** See individual endpoint files for detailed API docs
