Files
gridpilot.gg/scripts/MIGRATION_GUIDE.md
2025-12-31 15:39:28 +01:00

4.9 KiB

Media Reference Migration Guide

This guide explains how to migrate existing seeded data from old URL formats to the new MediaReference format.

Problem

Old seeded data stores media references as URL strings:

  • /api/avatar/{driverId}
  • /api/media/teams/{teamId}/logo
  • /api/media/leagues/{leagueId}/logo

New format uses MediaReference objects:

{
  "type": "system-default",
  "variant": "avatar",
  "avatarVariant": "male"
}

Solutions

Option 1: Migration Script (Preserve Data)

Best for: Production databases or when you need to preserve existing data

# Test what would change (dry run)
npm run migrate:media:test

# Execute the migration
npm run migrate:media:exec

What it does:

  • Converts /api/avatar/{id}system-default with deterministic variant
  • Converts /api/media/teams/{id}/logogenerated
  • Converts /api/media/leagues/{id}/logogenerated
  • Handles unknown formats → none
  • Skips already-migrated entries

Environment variables:

  • GRIDPILOT_API_PERSISTENCE=postgres|inmemory (default: postgres)
  • DATABASE_URL (required for postgres)

Option 2: Wipe and Reseed (Clean Slate)

Best for: Development/testing when you don't care about existing data

# Stop services and remove all volumes
npm run docker:dev:clean

# Rebuild and start fresh
npm run docker:dev:build

What it does:

  • Deletes all existing data
  • Runs fresh seed with correct MediaReference format
  • No migration needed

Migration Script Details

Supported Old Formats

Old Format New Reference Example
/api/avatar/{id} system-default (deterministic) /api/avatar/driver-1male/female/neutral
/api/media/teams/{id}/logo generated /api/media/teams/team-1/logogenerated:team-team-1
/api/media/leagues/{id}/logo generated /api/media/leagues/league-1/logogenerated:league-league-1
/images/avatars/male-default-avatar.jpg system-default (male) Static files → system-default
https://external.com/... none External URLs → none
Empty/null none Missing values → none

Deterministic Avatar Selection

Driver avatars use a hash-based selection for consistency:

const hash = hashCode(driverId);
const variantIndex = Math.abs(hash) % 3;
// 0 → male, 1 → female, 2 → neutral

This ensures the same driver ID always gets the same avatar variant.

What Gets Updated

Driver entities:

  • avatarRef field (JSONB column)

Team entities:

  • logoRef field (JSONB column)

League entities:

  • logoRef field (JSONB column)

Safety Features

  1. Dry Run Mode: Default behavior shows changes without applying them
  2. Validation: Only updates entries with invalid or missing references
  3. Error Handling: Continues on individual errors, reports all failures
  4. Idempotent: Safe to run multiple times

Testing the Migration

Test the migration logic without touching real data:

# Run test script
npm run migrate:media:test

This will show you:

  • How each URL format is parsed
  • What MediaReference it becomes
  • Deterministic avatar variants for sample IDs

When to Use Each Option

Use Migration Script When:

  • You have production data to preserve
  • You want to see what changes will be made
  • You need a controlled, reversible process
  • You're migrating a live database

Use Wipe and Reseed When:

  • You're in development/testing
  • You don't care about existing data
  • You want the fastest path to a clean state
  • You're setting up a new environment

Troubleshooting

Migration fails with "DATABASE_URL required"

Set the environment variable:

export DATABASE_URL=postgresql://user:pass@localhost:5432/dbname

Some entries weren't migrated

Check the error output. Common issues:

  • Invalid URL format (will be converted to none)
  • Already valid MediaReference (skipped)
  • Database connection issues

Want to rollback

The migration only updates entries that need it. To rollback:

  1. Restore from database backup
  2. Or manually revert the avatarRef/logoRef fields

Example Migration Output

[INFO] Starting media reference migration in DRY RUN mode
[INFO] Persistence mode: postgres
[INFO] Connecting to PostgreSQL database...
[INFO] Database connection established
[INFO] Found 150 drivers to migrate
[INFO] Found 25 teams to migrate
[INFO] Found 5 leagues to migrate
[INFO] Migration completed: 150 drivers, 25 teams, 5 leagues updated

=== Migration Summary ===
Mode: DRY RUN
Processed: 150 drivers, 25 teams, 5 leagues
Updated: 150 drivers, 25 teams, 5 leagues

✅ Dry run completed successfully. Run with --execute to apply changes.

Next Steps

After migration:

  1. Verify data integrity in the database
  2. Test that avatars and logos render correctly
  3. Update any hardcoded URL references in the frontend
  4. Remove any legacy URL construction code