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>
This commit is contained in:
root
2025-11-13 19:10:02 +00:00
parent fc494c1e08
commit 77b4d10af8
28155 changed files with 2191860 additions and 12967 deletions

View File

@@ -211,6 +211,81 @@
"created_at": "2025-10-29T03:49:34+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe add_soft_deletes_to_core_tables"
},
"2025_11_02_063218_rename_file_tables_for_storage_attachment_refactor.php": {
"created_at": "2025-11-02T06:32:18+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe rename_file_tables_for_storage_attachment_refactor"
},
"2025_11_02_065329_add_metadata_fields_to_file_attachments.php": {
"created_at": "2025-11-02T06:53:29+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe add_metadata_fields_to_file_attachments"
},
"2025_11_02_065347_create_file_thumbnails_table.php": {
"created_at": "2025-11-02T06:53:47+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_file_thumbnails_table"
},
"2025_11_02_070055_create_search_indexes_table.php": {
"created_at": "2025-11-02T07:00:55+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_search_indexes_table"
},
"2025_11_02_162826_add_dimensions_to_file_attachments.php": {
"created_at": "2025-11-02T16:28:26+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe add_dimensions_to_file_attachments"
},
"2025_11_04_011033_add_name_and_phone_columns_to_users_table.php": {
"created_at": "2025-11-04T01:10:33+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe Add name and phone columns to users table"
},
"2025_11_04_011050_create_user_profiles_table.php": {
"created_at": "2025-11-04T01:10:50+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe Create user profiles table"
},
"2025_11_04_014825_add_session_id_to_file_attachments_table.php": {
"created_at": "2025-11-04T01:48:25+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe add_session_id_to_file_attachments_table"
},
"2025_11_04_051746_create_login_users_table.php": {
"created_at": "2025-11-04T05:17:46+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_login_users_table"
},
"2025_11_04_051828_refactor_site_users_to_users_table.php": {
"created_at": "2025-11-04T05:18:28+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe refactor_site_users_to_users_table"
},
"2025_11_04_051907_update_sessions_table_for_login_user_id.php": {
"created_at": "2025-11-04T05:19:07+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe update_sessions_table_for_login_user_id"
},
"2025_11_04_051935_update_user_profiles_foreign_key.php": {
"created_at": "2025-11-04T05:19:35+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe update_user_profiles_foreign_key"
},
"2025_11_04_181832_add_invite_columns_to_users_table.php": {
"created_at": "2025-11-04T18:18:32+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe add_invite_columns_to_users_table"
},
"2025_11_05_012345_make_login_user_id_nullable_in_users_table.php": {
"created_at": "2025-11-05T01:23:45+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe Make login_user_id nullable in users table"
},
"2025_11_05_184039_add_is_verified_to_login_user_table.php": {
"created_at": "2025-11-05T18:40:39+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe add_is_verified_to_login_user_table"
}
}
}

View File

@@ -2,22 +2,23 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
return new class extends Migration
{
/**
* Run the migrations.
*
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement() with raw SQL
* Schema::create() with Blueprint
*
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
@@ -27,7 +28,7 @@ return new class extends Migration
// Create admin test user using environment variables or defaults
$email = env('RSPADE_DEFAULT_EMAIL', 'admin@test.com');
$password = env('RSPADE_DEFAULT_PASSWORD', 'admintest99');
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
$hashed_password = Hash::make($password);
DB::statement("
INSERT INTO users (

View File

@@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN age BIGINT")
* Schema::table() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Rename file_hashes table to file_storage
DB::statement("RENAME TABLE file_hashes TO file_storage");
// Drop unnecessary columns from file_storage
DB::statement("ALTER TABLE file_storage DROP COLUMN mime_type");
DB::statement("ALTER TABLE file_storage DROP COLUMN created_by");
DB::statement("ALTER TABLE file_storage DROP COLUMN updated_by");
// Rename files table to file_attachments
DB::statement("RENAME TABLE files TO file_attachments");
// Rename file_hash_id to file_storage_id in file_attachments
DB::statement("ALTER TABLE file_attachments CHANGE COLUMN file_hash_id file_storage_id BIGINT NOT NULL");
// Drop file_size column from file_attachments (size is stored in file_storage)
DB::statement("ALTER TABLE file_attachments DROP COLUMN file_size");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE file_attachments ADD COLUMN new_field VARCHAR(255)")
* Schema::table() with Blueprint
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Add metadata fields to file_attachments table
DB::statement("ALTER TABLE file_attachments ADD COLUMN fileable_type_meta VARCHAR(255) NULL AFTER fileable_category");
DB::statement("ALTER TABLE file_attachments ADD COLUMN fileable_meta TEXT NULL AFTER fileable_order");
// Add index for fileable_type_meta for efficient querying
DB::statement("CREATE INDEX idx_file_attachments_type_meta ON file_attachments(fileable_type_meta)");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,52 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement() with raw SQL
* Schema::create() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE file_thumbnails (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
source_storage_id BIGINT NOT NULL,
thumbnail_storage_id BIGINT NOT NULL,
params TEXT NOT NULL,
detected_mime_type VARCHAR(255) NOT NULL,
created_at TIMESTAMP NULL DEFAULT NULL,
updated_at TIMESTAMP NULL DEFAULT NULL,
created_by BIGINT NULL,
updated_by BIGINT NULL,
INDEX idx_source_storage (source_storage_id),
INDEX idx_thumbnail_storage (thumbnail_storage_id),
INDEX idx_source_params (source_storage_id, detected_mime_type(50)),
FOREIGN KEY (source_storage_id) REFERENCES file_storage(id) ON DELETE CASCADE,
FOREIGN KEY (thumbnail_storage_id) REFERENCES file_storage(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement() with raw SQL
* Schema::create() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE search_indexes (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
indexable_type VARCHAR(255) NOT NULL,
indexable_id BIGINT NOT NULL,
content LONGTEXT,
metadata JSON,
indexed_at TIMESTAMP NULL,
extraction_method VARCHAR(100),
language VARCHAR(10),
site_id BIGINT NOT NULL,
created_at TIMESTAMP NULL DEFAULT NULL,
updated_at TIMESTAMP NULL DEFAULT NULL,
created_by BIGINT NULL,
updated_by BIGINT NULL,
FULLTEXT INDEX ft_content (content),
INDEX idx_indexable (indexable_type, indexable_id),
INDEX idx_site (site_id),
INDEX idx_language (language),
INDEX idx_indexed_at (indexed_at),
UNIQUE KEY unique_indexable (indexable_type, indexable_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* Add dimension and metadata fields to file_attachments table for storing
* extracted media properties (width, height, duration, animation detection).
*
* These fields are populated automatically during file upload by the
* File_Attachment_Model::process_file() method using ImageMagick.
*
* @return void
*/
public function up()
{
// Image/Video dimensions (using BIGINT as per framework standards)
// Note: COMMENT must come before AFTER in MySQL syntax
DB::statement("ALTER TABLE file_attachments ADD COLUMN width BIGINT NULL COMMENT 'Width in pixels for images/videos' AFTER file_type_id");
DB::statement("ALTER TABLE file_attachments ADD COLUMN height BIGINT NULL COMMENT 'Height in pixels for images/videos' AFTER width");
// Video/Animation duration in seconds
DB::statement("ALTER TABLE file_attachments ADD COLUMN duration BIGINT NULL COMMENT 'Duration in seconds for videos/animated images' AFTER height");
// Animated image detection
DB::statement("ALTER TABLE file_attachments ADD COLUMN is_animated TINYINT(1) DEFAULT 0 COMMENT 'Whether this is an animated image (GIF, WebP, APNG)' AFTER duration");
// Frame count for animated images
DB::statement("ALTER TABLE file_attachments ADD COLUMN frame_count BIGINT NULL COMMENT 'Number of frames in animated images' AFTER is_animated");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN new_field VARCHAR(255)")
* Schema::table() with Blueprint
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
DB::statement("ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL AFTER email");
DB::statement("ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL AFTER first_name");
DB::statement("ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL AFTER last_name");
DB::statement("ALTER TABLE users ADD INDEX idx_first_name (first_name)");
DB::statement("ALTER TABLE users ADD INDEX idx_last_name (last_name)");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement() with raw SQL
* Schema::create() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE user_profiles (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
title VARCHAR(100) NULL,
department VARCHAR(100) NULL,
bio TEXT NULL,
created_at TIMESTAMP(3) NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at TIMESTAMP(3) NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
created_by BIGINT NULL,
updated_by BIGINT NULL,
INDEX idx_user_id (user_id),
CONSTRAINT fk_user_profiles_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* Add session_id column to file_attachments table for attachment assignment security.
* Users can only assign attachments that were uploaded in their current session.
*
* @return void
*/
public function up()
{
DB::statement("ALTER TABLE file_attachments ADD COLUMN session_id VARCHAR(255) NULL AFTER site_id");
DB::statement("ALTER TABLE file_attachments ADD INDEX idx_session_id (session_id)");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,75 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement() with raw SQL
* Schema::create() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Create login_users table (authentication identity)
// This holds email, password, verification status - the login credentials
// Profile data (first_name, last_name, phone) will be on site-specific users table
DB::statement("
CREATE TABLE login_users (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
is_activated TINYINT(1) NOT NULL DEFAULT 0,
is_verified TINYINT(1) NOT NULL DEFAULT 0,
status_id BIGINT NOT NULL DEFAULT 1,
remember_token VARCHAR(100) DEFAULT NULL,
last_login TIMESTAMP(3) NULL DEFAULT NULL,
created_at TIMESTAMP(3) NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at TIMESTAMP(3) NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
created_by BIGINT DEFAULT NULL,
updated_by BIGINT DEFAULT NULL,
UNIQUE KEY uk_login_users_email (email),
KEY idx_login_users_is_activated (is_activated),
KEY idx_login_users_is_verified (is_verified),
KEY idx_login_users_status_id (status_id),
KEY idx_login_users_created_at (created_at),
KEY idx_login_users_updated_at (updated_at),
KEY idx_login_users_last_login (last_login)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
// Migrate data from users table to login_users table
// Copy: id, email, password, activation/verification, status, tokens, timestamps
// EXCLUDE: first_name, last_name, phone, user_role_id (these move to site-specific users table)
DB::statement("
INSERT INTO login_users (
id, email, password, is_activated, is_verified, status_id,
remember_token, last_login, created_at, updated_at, created_by, updated_by
)
SELECT
id, email, password, is_activated, is_verified, status_id,
remember_token, last_login, created_at, updated_at, created_by, updated_by
FROM users
");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,117 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN new_field VARCHAR(255)")
* Schema::table() with Blueprint
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Step 1: Drop existing foreign key constraints BEFORE renaming
DB::statement("ALTER TABLE site_users DROP FOREIGN KEY site_users_ibfk_1"); // user_id → users
DB::statement("ALTER TABLE site_users DROP FOREIGN KEY site_users_ibfk_2"); // site_id → sites
// Step 2: Drop unique constraint (will recreate with new column name)
DB::statement("ALTER TABLE site_users DROP INDEX uk_site_users_user_site");
// Step 3: Rename site_users to users_new (temporary)
DB::statement("RENAME TABLE site_users TO users_new");
// Step 4: Rename user_id column to login_user_id
DB::statement("ALTER TABLE users_new CHANGE COLUMN user_id login_user_id BIGINT NOT NULL");
// Step 5: Add new columns for site-specific user profile data
DB::statement("
ALTER TABLE users_new
ADD COLUMN phone VARCHAR(20) DEFAULT NULL AFTER last_name,
ADD COLUMN user_role_id BIGINT NOT NULL DEFAULT 2 AFTER is_enabled,
ADD COLUMN email VARCHAR(255) DEFAULT NULL AFTER user_role_id
");
// Step 6: Add indexes for new columns
DB::statement("ALTER TABLE users_new ADD INDEX idx_users_phone (phone)");
DB::statement("ALTER TABLE users_new ADD INDEX idx_users_user_role_id (user_role_id)");
DB::statement("ALTER TABLE users_new ADD INDEX idx_users_email (email)");
// Step 7: Recreate unique constraint with new column name
DB::statement("ALTER TABLE users_new ADD UNIQUE KEY uk_users_login_user_site (login_user_id, site_id)");
// Step 8: Add foreign key constraints with new column names
DB::statement("
ALTER TABLE users_new
ADD CONSTRAINT fk_users_login_user_id
FOREIGN KEY (login_user_id) REFERENCES login_users(id) ON DELETE CASCADE
");
DB::statement("
ALTER TABLE users_new
ADD CONSTRAINT fk_users_site_id
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE
");
// Step 9: Populate users_new with data from old users table
// For each user in old users table, create a site-specific user record with site_id=1
DB::statement("
INSERT INTO users_new (
login_user_id, site_id, first_name, last_name, phone,
role_id, is_enabled, user_role_id, email,
created_at, updated_at, created_by, updated_by
)
SELECT
u.id as login_user_id,
1 as site_id,
u.first_name,
u.last_name,
u.phone,
CASE
WHEN u.user_role_id >= 5 THEN 1 -- ROOT_ADMIN OWNER
WHEN u.user_role_id >= 3 THEN 2 -- ADMIN ADMIN
ELSE 3 -- STANDARD/READ_ONLY MEMBER
END as role_id,
1 as is_enabled,
u.user_role_id,
NULL as email,
u.created_at,
u.updated_at,
u.created_by,
u.updated_by
FROM users u
");
// Step 10: Drop foreign key constraints from other tables that reference users
DB::statement("ALTER TABLE user_invites DROP FOREIGN KEY user_invites_ibfk_1");
DB::statement("ALTER TABLE user_profiles DROP FOREIGN KEY fk_user_profiles_user_id");
// Step 11: Drop the old users table (data now in login_users and users_new)
DB::statement("DROP TABLE users");
// Step 12: Rename users_new to users (final name)
DB::statement("RENAME TABLE users_new TO users");
// Step 13: Recreate foreign keys for tables that should reference login_users
// user_invites should reference login_users (invitations are to login identities)
DB::statement("
ALTER TABLE user_invites
ADD CONSTRAINT fk_user_invites_user_id
FOREIGN KEY (user_id) REFERENCES login_users(id) ON DELETE CASCADE
");
// Note: user_profiles FK will be recreated in the next migration to reference new users table
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN age BIGINT")
* Schema::table() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Rename user_id to login_user_id in sessions table
// Sessions track the authentication identity (login_user), not the site-specific user
// Step 1: Drop existing indexes on user_id
DB::statement("ALTER TABLE sessions DROP INDEX sessions_user_id_index");
DB::statement("ALTER TABLE sessions DROP INDEX sessions_user_id_active_index");
// Step 2: Rename column
DB::statement("ALTER TABLE sessions CHANGE COLUMN user_id login_user_id BIGINT DEFAULT NULL");
// Step 3: Recreate indexes with new column name
DB::statement("CREATE INDEX idx_sessions_login_user_id ON sessions(login_user_id)");
DB::statement("CREATE INDEX idx_sessions_login_user_id_active ON sessions(login_user_id, active)");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,56 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN age BIGINT")
* Schema::table() with Blueprint
*
* REQUIRED: ALL tables MUST have: id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
* No exceptions - every table needs this exact ID column (SIGNED for easier migrations)
*
* Integer types: Use BIGINT for all integers, TINYINT(1) for booleans only
* Never use unsigned - all integers should be signed
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Update user_profiles foreign key to reference new users table (site-specific)
// Previously: user_id → old users table (login identity)
// Now: user_id → new users table (site-specific profile)
//
// Note: The FK was already dropped in the previous migration (refactor_site_users_to_users_table)
// Step 1: Update existing user_profiles records to reference new users.id
// The old users.id becomes login_users.id
// We need to find the corresponding site-specific users.id
// For single-site setup (site_id=1), there's a 1:1 mapping
DB::statement("
UPDATE user_profiles up
INNER JOIN users u ON u.login_user_id = up.user_id AND u.site_id = 1
SET up.user_id = u.id
");
// Step 2: Add new foreign key constraint
DB::statement("
ALTER TABLE user_profiles
ADD CONSTRAINT fk_user_profiles_user_id
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,62 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN new_field VARCHAR(255)")
* Schema::table() with Blueprint
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Add invite-related columns to users table
// These support the Slack-style invitation workflow where invitations
// are represented as users records in a pending state
// invite_code: Unique code used in acceptance URL (/accept-invite/{code})
DB::statement("
ALTER TABLE users
ADD COLUMN invite_code VARCHAR(100) DEFAULT NULL,
ADD UNIQUE KEY uk_users_invite_code (invite_code)
");
// invite_accepted_at: NULL until user accepts invite
// When user accepts, this is set and login_user_id is populated
DB::statement("
ALTER TABLE users
ADD COLUMN invite_accepted_at TIMESTAMP(3) NULL DEFAULT NULL,
ADD INDEX idx_users_invite_accepted_at (invite_accepted_at)
");
// invite_expires_at: Default 7 days from creation (configurable)
// Invites cannot be accepted after expiration
DB::statement("
ALTER TABLE users
ADD COLUMN invite_expires_at TIMESTAMP(3) NULL DEFAULT NULL,
ADD INDEX idx_users_invite_expires_at (invite_expires_at)
");
// For existing users (already accepted), set accepted_at to created_at
// This marks them as accepted vs pending invites
DB::statement("
UPDATE users
SET invite_accepted_at = created_at
WHERE login_user_id IS NOT NULL
");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* IMPORTANT: Use raw MySQL queries for clarity and auditability
* DB::statement("ALTER TABLE users ADD COLUMN new_field VARCHAR(255)")
* Schema::table() with Blueprint
*
* Migrations must be self-contained - no Model/Service references
*
* @return void
*/
public function up()
{
// Make login_user_id nullable to support invitation flow
// Users invited to a site don't have a login_user record until they accept the invite
DB::statement("ALTER TABLE users MODIFY COLUMN login_user_id BIGINT NULL");
}
/**
* down() method is prohibited in RSpade framework
* Migrations should only move forward, never backward
* You may remove this comment as soon as you see it and understand.
*/
};