Files
rspade_system/app/RSpade/man/migrations.txt
root 77b4d10af8 Refactor filename naming system and apply convention-based renames
Standardize settings file naming and relocate documentation files
Fix code quality violations from rsx:check
Reorganize user_management directory into logical subdirectories
Move Quill Bundle to core and align with Tom Select pattern
Simplify Site Settings page to focus on core site information
Complete Phase 5: Multi-tenant authentication with login flow and site selection
Add route query parameter rule and synchronize filename validation logic
Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs
Implement filename convention rule and resolve VS Code auto-rename conflict
Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns
Implement RPC server architecture for JavaScript parsing
WIP: Add RPC server infrastructure for JS parsing (partial implementation)
Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation
Add JQHTML-CLASS-01 rule and fix redundant class names
Improve code quality rules and resolve violations
Remove legacy fatal error format in favor of unified 'fatal' error type
Filter internal keys from window.rsxapp output
Update button styling and comprehensive form/modal documentation
Add conditional fly-in animation for modals
Fix non-deterministic bundle compilation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 19:10:02 +00:00

349 lines
13 KiB
Plaintext
Executable File

MIGRATIONS(7) RSX Framework Manual MIGRATIONS(7)
NAME
migrations - Database migration system with raw SQL enforcement
SYNOPSIS
php artisan make:migration:safe <name>
php artisan migrate:begin
php artisan migrate [--production]
php artisan migrate:commit
php artisan migrate:rollback
DESCRIPTION
The RSX framework enforces a forward-only migration strategy using raw SQL
statements. Laravel's Schema builder is prohibited to ensure clarity,
auditability, and prevent hidden behaviors.
PHILOSOPHY
1. Forward-only migrations - No rollbacks, no down() methods
2. Raw SQL only - Direct MySQL statements, no abstractions
3. Fail loud - Migrations must succeed or fail with clear errors
4. Snapshot safety - Development requires database snapshots before migrating
MIGRATION RULES
Schema Builder Prohibition
All migrations MUST use DB::statement() with raw SQL. The following are prohibited:
• Schema::create()
• Schema::table()
• Schema::drop()
• Schema::dropIfExists()
• Schema::rename()
• Blueprint class usage
• $table-> method chains
The migration validator automatically checks for these patterns and will prevent
migrations from running if violations are found.
Required Table Structure
ALL tables MUST have:
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
This is non-negotiable. Every table needs this exact ID column (SIGNED for
easier future migrations).
Data Type Standards - What You Need to Know
The framework automatically normalizes data types during migration, so you can
use simpler types and let the system handle optimization:
What You Can Use (System Auto-Converts):
• INT → automatically becomes BIGINT
• TEXT → automatically becomes LONGTEXT
• FLOAT → automatically becomes DOUBLE
• Any charset → automatically becomes UTF8MB4
• created_at/updated_at → automatically added with proper defaults
• created_by/updated_by → automatically added
• deleted_by → automatically added for soft-delete tables
What You MUST Be Careful About:
• Foreign key columns - Must match the referenced column type exactly
Example: If users.id is BIGINT, then orders.user_id must be BIGINT
• TINYINT(1) - Preserved for boolean values, won't be converted
• Column names ending in _id are assumed to be foreign keys
Recommended for Simplicity:
• Just use INT for integers (becomes BIGINT automatically)
• Just use TEXT for long content (becomes LONGTEXT automatically)
• Just use FLOAT for decimals (becomes DOUBLE automatically)
• Don't add created_at/updated_at (added automatically)
• Don't add created_by/updated_by (added automatically)
down() Method Removal
The migration system automatically removes down() methods from migration files.
Migrations are forward-only - database changes should never be reversed.
AUTOMATIC NORMALIZATION
What migrate:normalize_schema Does For You
After migrations run, the normalize_schema command automatically:
1. Type Conversions:
• INT columns → BIGINT (except TINYINT(1) for booleans)
• BIGINT UNSIGNED → BIGINT SIGNED
• TEXT → LONGTEXT
• FLOAT → DOUBLE
• All text columns → UTF8MB4 character set
2. Required Columns Added:
• created_at TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3)
• updated_at TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE
• created_by INT(11) NULL
• updated_by INT(11) NULL
• deleted_by INT(11) NULL (only for soft-delete tables)
3. Indexes Added:
• INDEX on created_at
• INDEX on updated_at
• INDEX on site_id (for models extending Rsx_Site_Model_Abstract)
• INDEX on id+version (for Versionable models)
4. Model-Specific Columns:
• site_id BIGINT - for models extending Rsx_Site_Model_Abstract
• version INT(11) DEFAULT 1 - for Versionable/Ajaxable models
5. Precision Upgrades:
• All DATETIME/TIMESTAMP columns → precision (3) for milliseconds
This means you can write simpler migrations and let the system handle the
optimization and standardization. The only time you need to be explicit about
types is when creating foreign key columns that must match their referenced
column exactly.
VALIDATION SYSTEM
Automatic Validation
When running migrations in non-production mode, the system automatically:
1. Validates all pending migrations for Schema builder usage
2. Removes down() methods if present
3. Reports violations with colored output and remediation advice
4. Stops at the first violation to allow correction
Validation Output
When a violation is detected, you'll see:
❌ Migration Validation Failed
File: 2025_09_30_create_example_table.php
Line: 28
Violation: Found forbidden Schema builder usage: Schema::create
Code Preview:
────────────────────────────────────────
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
});
────────────────────────────────────────
Remediation: Use DB::statement("CREATE TABLE...") instead
Example:
DB::statement('CREATE TABLE users (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
created_at TIMESTAMP NULL DEFAULT NULL
)');
Bypassing Validation
In production mode (--production flag or APP_ENV=production), validation is
skipped. This should only be used when absolutely necessary.
MIGRATION WORKFLOW
Development Workflow
1. Create snapshot: php artisan migrate:begin
2. Create migration: php artisan make:migration:safe <name>
3. Write migration using raw SQL
4. Run migrations: php artisan migrate
5. If successful: php artisan migrate:commit
6. If failed: System auto-rollbacks to snapshot
Production Workflow
1. Create migration: php artisan make:migration:safe <name>
2. Write migration using raw SQL
3. Test thoroughly in development/staging
4. Run migrations: php artisan migrate --production
Note: No snapshot protection in production mode. Ensure migrations are
thoroughly tested before running in production.
MIGRATION EXAMPLES
Creating a Table (Simple Version - Recommended)
public function up()
{
// You can write this simple version - system auto-normalizes types
DB::statement("
CREATE TABLE products (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -- becomes BIGINT
name VARCHAR(255) NOT NULL,
description TEXT, -- becomes LONGTEXT
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
stock_quantity INT NOT NULL DEFAULT 0, -- becomes BIGINT
is_active TINYINT(1) NOT NULL DEFAULT 1, -- stays TINYINT(1)
category_id INT NULL, -- becomes BIGINT
INDEX idx_category (category_id),
INDEX idx_active (is_active)
-- No need for created_at/updated_at - added automatically
)
");
}
Creating a Table (Explicit Version - If You Prefer)
public function up()
{
// Or be explicit about types if you prefer
DB::statement("
CREATE TABLE products (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description LONGTEXT,
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
stock_quantity BIGINT NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
category_id BIGINT NULL,
created_at TIMESTAMP NULL DEFAULT NULL,
updated_at TIMESTAMP NULL DEFAULT NULL,
INDEX idx_category (category_id),
INDEX idx_active (is_active),
INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
}
Adding Columns
public function up()
{
DB::statement("ALTER TABLE users ADD COLUMN age BIGINT NULL AFTER email");
DB::statement("ALTER TABLE users ADD INDEX idx_age (age)");
}
Modifying Columns
public function up()
{
// Change column type
DB::statement("ALTER TABLE products MODIFY COLUMN price DECIMAL(12,2)");
// Rename column
DB::statement("ALTER TABLE users CHANGE COLUMN username user_name VARCHAR(100)");
// Add default value
DB::statement("ALTER TABLE posts ALTER COLUMN status SET DEFAULT 'draft'");
}
Managing Indexes
public function up()
{
// Add index
DB::statement("CREATE INDEX idx_email ON users (email)");
// Add unique index
DB::statement("CREATE UNIQUE INDEX idx_unique_slug ON posts (slug)");
// Add composite index
DB::statement("CREATE INDEX idx_user_status ON orders (user_id, status)");
// Drop index
DB::statement("DROP INDEX idx_old_index ON table_name");
}
Foreign Keys (IMPORTANT - Match Types Exactly)
public function up()
{
// CRITICAL: Foreign key columns must match referenced column type
// If users.id is BIGINT, orders.user_id must also be BIGINT
// First, ensure the column has correct type (if not already created)
DB::statement("ALTER TABLE orders ADD COLUMN user_id BIGINT NULL");
// Then add the foreign key constraint
DB::statement("
ALTER TABLE orders
ADD CONSTRAINT orders_user_fk
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
");
// To drop a foreign key
DB::statement("ALTER TABLE orders DROP FOREIGN KEY orders_user_fk");
}
// Note: After normalization, all id columns are BIGINT, so foreign keys
// should always use BIGINT to avoid type mismatches
Data Migrations
public function up()
{
// Simple update
DB::statement("UPDATE users SET role = 'member' WHERE role IS NULL");
// Complex migration with temporary column
DB::statement("ALTER TABLE orders ADD COLUMN total_new DECIMAL(10,2)");
DB::statement("UPDATE orders SET total_new = quantity * price");
DB::statement("ALTER TABLE orders DROP COLUMN total");
DB::statement("ALTER TABLE orders CHANGE total_new total DECIMAL(10,2)");
}
ERROR MESSAGES
"Migration validation failed: Schema builder usage detected"
Your migration uses Laravel's Schema builder. Rewrite using DB::statement()
with raw SQL.
"Migration mode not active!"
You're in development mode and haven't created a snapshot. Run:
php artisan migrate:begin
"Unauthorized migrations detected!"
Migration files exist that weren't created via make:migration:safe.
Recreate them using the proper command.
SECURITY CONSIDERATIONS
SQL Injection
When using dynamic values in migrations, always use parameter binding:
✅ CORRECT:
DB::statement("UPDATE users SET status = ? WHERE created_at < ?", ['active', '2025-01-01']);
❌ WRONG:
DB::statement("UPDATE users SET status = '$status' WHERE created_at < '$date'");
Production Safety
• Always test migrations in development/staging first
• Keep migrations small and focused
• Never reference models or services in migrations
• Migrations must be self-contained and idempotent where possible
DEBUGGING
Viewing Pending Migrations
php artisan migrate:status
Testing a Migration
1. Create snapshot: php artisan migrate:begin
2. Run migration: php artisan migrate
3. If it fails, automatic rollback occurs
4. Fix the migration file
5. Try again: php artisan migrate
Common Issues
• "Class not found" - Don't reference models in migrations
• "Syntax error" - Check your SQL syntax, test in MySQL client first
• "Foreign key constraint" - Ensure referenced table/column exists
• "Duplicate column" - Check if column already exists before adding
SEE ALSO
rsx:man database - Database system overview
rsx:man coding_standards - General coding standards
rsx:man error_handling - Error handling patterns
AUTHORS
RSX Framework Team
RSX Framework September 2025 MIGRATIONS(7)