Files
michaelschiemer/docs/features/database/migrations.md
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

5.4 KiB

Migration System Quick Reference

TL;DR

Default: Migrations sind forward-only (nur up() Methode). Optional: Implementiere SafelyReversible nur wenn Rollback OHNE Datenverlust möglich ist.

Quick Decision Tree

Is rollback safe (no data loss)?
│
├─ YES (e.g., create table, add nullable column, create index)
│  └─ Implement: Migration, SafelyReversible
│
└─ NO (e.g., drop column, transform data, delete data)
   └─ Implement: Migration only

Code Templates

Forward-Only Migration (Default)

use App\Framework\Database\Migration\Migration;
use App\Framework\Database\Migration\MigrationVersion;
use App\Framework\Database\ConnectionInterface;
use App\Framework\Database\Schema\Schema;

final readonly class YourMigration implements Migration
{
    public function up(ConnectionInterface $connection): void
    {
        $schema = new Schema($connection);
        // Your migration logic
        $schema->execute();
    }

    public function getVersion(): MigrationVersion
    {
        return MigrationVersion::fromTimestamp("2024_12_20_100000");
    }

    public function getDescription(): string
    {
        return 'Description of what this migration does';
    }

    public function getDomain(): string
    {
        return "YourDomain";
    }
}

Safe Rollback Migration

use App\Framework\Database\Migration\{Migration, SafelyReversible};
use App\Framework\Database\Migration\MigrationVersion;
use App\Framework\Database\ConnectionInterface;
use App\Framework\Database\Schema\Schema;

/**
 * This migration is safely reversible because:
 * - [Explain why rollback is safe, e.g., "Creates new empty table"]
 */
final readonly class YourSafeMigration implements Migration, SafelyReversible
{
    public function up(ConnectionInterface $connection): void
    {
        $schema = new Schema($connection);
        // Your migration logic
        $schema->execute();
    }

    public function down(ConnectionInterface $connection): void
    {
        $schema = new Schema($connection);
        // Reverse the changes safely
        $schema->execute();
    }

    public function getVersion(): MigrationVersion
    {
        return MigrationVersion::fromTimestamp("2024_12_20_100000");
    }

    public function getDescription(): string
    {
        return 'Description of what this migration does';
    }

    public function getDomain(): string
    {
        return "YourDomain";
    }
}

Common Operations

Create Migration

php console.php make:migration CreateYourTable

Run Migrations

php console.php db:migrate

Rollback (Only SafelyReversible)

# Rollback last migration
php console.php db:rollback

# Rollback last 3 migrations
php console.php db:rollback 3

Check Status

php console.php db:status

Safe vs Unsafe Cheatsheet

Operation Safe? Implements
Create table Migration, SafelyReversible
Drop table (empty) Migration, SafelyReversible
Drop table (with data) Migration only
Add nullable column Migration, SafelyReversible
Add NOT NULL column (with default) ⚠️ Case by case
Drop column (empty) Migration, SafelyReversible
Drop column (with data) Migration only
Rename column Migration, SafelyReversible
Change column type Migration only
Create index Migration, SafelyReversible
Drop index Migration, SafelyReversible
Add foreign key Migration, SafelyReversible
Drop foreign key Migration, SafelyReversible
Transform data Migration only
Delete data Migration only
Merge tables Migration only

Error Handling

Rollback Failed (Not SafelyReversible)

❌ Rollback failed: Migration 2024_12_20_100000 does not support safe rollback

💡 Recommendation:
   Create a new forward migration to undo the changes instead:
   php console.php make:migration FixYourChanges

What to do:

  1. Create new forward migration
  2. Implement reverse logic in up() method
  3. Run php console.php db:migrate

Testing Rollback

# Test cycle in development
php console.php db:migrate
php console.php db:rollback 1
php console.php db:migrate  # Should succeed again

Best Practices

  1. Document why safe: Always comment why a migration is SafelyReversible
  2. Test rollback cycle: Test up() → down() → up() in development
  3. Default to forward-only: Only add SafelyReversible if certain
  4. Never rollback in production: Even "safe" rollbacks should be avoided
  5. Use fix-forward: Prefer new migrations over rollback
  6. Backup before rollback: Always backup database before rolling back
  7. Check for data: Verify column is empty before making it SafelyReversible
  • Full Examples: docs/claude/examples/migrations/SafeVsUnsafeMigrations.md
  • Database Patterns: docs/claude/database-patterns.md
  • Migration Interface: src/Framework/Database/Migration/Migration.php
  • SafelyReversible Interface: src/Framework/Database/Migration/SafelyReversible.php

Framework Compliance

Readonly classes: final readonly class Composition over inheritance: Interface-based Explicit contracts: SafelyReversible is opt-in Type safety: Strong typing throughout No primitive obsession: Uses Value Objects (MigrationVersion)