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
- 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
5.4 KiB
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:
- Create new forward migration
- Implement reverse logic in
up()method - 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
- ✅ Document why safe: Always comment why a migration is SafelyReversible
- ✅ Test rollback cycle: Test
up() → down() → up()in development - ✅ Default to forward-only: Only add SafelyReversible if certain
- ❌ Never rollback in production: Even "safe" rollbacks should be avoided
- ✅ Use fix-forward: Prefer new migrations over rollback
- ✅ Backup before rollback: Always backup database before rolling back
- ✅ Check for data: Verify column is empty before making it SafelyReversible
Links
- 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)