--- name: migrations description: RSX database migrations with raw SQL enforcement, forward-only philosophy, and automatic normalization. Use when creating database tables, understanding migration workflow, or troubleshooting Schema builder violations. --- # RSX Database Migrations ## Philosophy RSX enforces a forward-only migration strategy with raw SQL: 1. **Forward-only** - No rollbacks, no `down()` methods 2. **Raw SQL only** - Direct MySQL statements, no Schema builder 3. **Fail loud** - Migrations must succeed or fail with clear errors 4. **Snapshot safety** - Development requires database snapshots --- ## Schema Builder is Prohibited All migrations **must** use `DB::statement()` with raw SQL: ```php // ✅ CORRECT DB::statement("CREATE TABLE products ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, price DECIMAL(10,2) NOT NULL DEFAULT 0.00 )"); // ❌ WRONG - Schema builder prohibited Schema::create('products', function (Blueprint $table) { $table->id(); $table->string('name'); }); ``` **Prohibited**: `Schema::create()`, `Schema::table()`, `Schema::drop()`, `Blueprint`, `$table->` chains --- ## Development Workflow ```bash # 1. Create snapshot (required) php artisan migrate:begin # 2. Create migration php artisan make:migration:safe create_products_table # 3. Write migration with raw SQL # 4. Run migrations php artisan migrate # 5. If successful php artisan migrate:commit # 6. If failed - auto-rollback to snapshot ``` --- ## Automatic Normalization The system auto-normalizes types after migration. You can write simpler SQL: | You Write | System Converts To | |-----------|-------------------| | `INT` | `BIGINT` | | `TEXT` | `LONGTEXT` | | `FLOAT` | `DOUBLE` | | `TINYINT(1)` | Preserved (boolean) | **Auto-added columns** (don't include manually): - `created_at TIMESTAMP(3)` - `updated_at TIMESTAMP(3)` - `created_by BIGINT` - `updated_by BIGINT` --- ## Migration Examples ### Simple Table (Recommended) ```php public function up() { DB::statement(" CREATE TABLE products ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, price DECIMAL(10,2) NOT NULL DEFAULT 0.00, stock_quantity INT NOT NULL DEFAULT 0, is_active TINYINT(1) NOT NULL DEFAULT 1, category_id INT NULL, INDEX idx_category (category_id), INDEX idx_active (is_active) ) "); } ``` **Notes**: - `INT` becomes `BIGINT` automatically - `TEXT` becomes `LONGTEXT` automatically - `created_at`/`updated_at` added automatically - `TINYINT(1)` preserved for booleans ### Adding Columns ```php public function up() { DB::statement(" ALTER TABLE products ADD COLUMN sku VARCHAR(50) NULL AFTER name, ADD COLUMN weight DECIMAL(8,2) NULL, ADD INDEX idx_sku (sku) "); } ``` ### Foreign Keys ```php public function up() { DB::statement(" ALTER TABLE orders ADD CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE "); } ``` --- ## Required Table Structure **Every table MUST have**: ```sql id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ``` This is non-negotiable. Use SIGNED (not UNSIGNED) for easier future migrations. --- ## Foreign Key Columns Foreign key columns **must match** the referenced column type exactly: ```sql -- If users.id is BIGINT, then: user_id BIGINT NULL -- ✅ Matches -- Column names ending in _id are assumed to be foreign keys ``` --- ## Production Workflow ```bash # No snapshot protection in production php artisan migrate --production ``` Ensure migrations are thoroughly tested in development/staging first. --- ## Validation The migration validator automatically checks for: - Schema builder usage - `down()` methods (auto-removed) - Proper SQL syntax Violations show clear error messages with remediation advice. --- ## Troubleshooting | Error | Solution | |-------|----------| | "Found forbidden Schema builder usage" | Replace with `DB::statement()` | | "Validation failed" | Check migration for prohibited patterns | | Foreign key constraint fails | Ensure column types match exactly | ## More Information Details: `php artisan rsx:man migrations`