Framework updates

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-02-01 05:16:45 +00:00
parent f48cda006a
commit 0efdcd4cde
27 changed files with 2970 additions and 153 deletions

View File

@@ -396,6 +396,26 @@
"created_at": "2026-01-29T08:19:02+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_notifications_table"
},
"2026_01_29_180540_create_portal_users_table.php": {
"created_at": "2026-01-29T18:05:40+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_portal_users_table"
},
"2026_01_29_180545_create_portal_invitations_table.php": {
"created_at": "2026-01-29T18:05:45+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_portal_invitations_table"
},
"2026_01_29_180545_create_portal_sessions_table.php": {
"created_at": "2026-01-29T18:05:45+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_portal_sessions_table"
},
"2026_01_29_184331_create_portal_password_resets_table.php": {
"created_at": "2026-01-29T18:43:31+00:00",
"created_by": "root",
"command": "php artisan make:migration:safe create_portal_password_resets_table"
}
}
}

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.
*
* Portal users are external users (customers, clients, vendors) who access
* a site through the client portal. They are completely separate from
* internal system users (login_users).
*
* Key differences from login_users:
* - Site-scoped (no multi-tenant access)
* - Simpler auth model (no multi-site switching)
* - Invite-only registration
* - No remember_token (portal sessions are simpler)
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE portal_users (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
site_id BIGINT NOT NULL,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
is_verified TINYINT(1) NOT NULL DEFAULT 0,
status_id BIGINT NOT NULL DEFAULT 1,
metadata JSON 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_portal_users_site_email (site_id, email),
KEY idx_portal_users_site_id (site_id),
KEY idx_portal_users_email (email),
KEY idx_portal_users_status_id (status_id),
KEY idx_portal_users_is_verified (is_verified),
KEY idx_portal_users_created_at (created_at),
KEY idx_portal_users_last_login (last_login),
FOREIGN KEY (site_id) REFERENCES sites(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.
*
* Portal invitations are single-use codes that allow external users
* to register for portal access. The invitation flow:
*
* 1. Admin creates invitation with email + optional metadata
* 2. System sends email with unique invitation code
* 3. User clicks link, lands on portal registration page
* 4. User sets password, account created with email verified
* 5. Invitation marked as used (used_at set)
*
* Metadata allows linking portal user to business entities
* (e.g., contact_id, client_id) - application-specific.
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE portal_invitations (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
site_id BIGINT NOT NULL,
email VARCHAR(255) NOT NULL,
invitation_code VARCHAR(64) NOT NULL,
metadata JSON NULL,
expires_at TIMESTAMP(3) NOT NULL,
used_at 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_portal_invitations_code (invitation_code),
KEY idx_portal_invitations_site_id (site_id),
KEY idx_portal_invitations_email (email),
KEY idx_portal_invitations_site_email (site_id, email),
KEY idx_portal_invitations_expires_at (expires_at),
KEY idx_portal_invitations_used_at (used_at),
FOREIGN KEY (site_id) REFERENCES sites(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,53 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* Portal sessions are completely separate from internal sessions.
* This ensures:
* - Different cookie names (no session bleeding)
* - Independent session management
* - Simpler structure (no experience_id, no multi-site)
*
* Portal sessions are site-scoped - a portal user can only
* be logged into one site at a time with a given session.
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE portal_sessions (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
site_id BIGINT NOT NULL,
portal_user_id BIGINT NULL,
session_token VARCHAR(64) NOT NULL,
csrf_token VARCHAR(64) NULL,
ip_address VARCHAR(45) NOT NULL,
user_agent VARCHAR(255) NULL,
last_active TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
created_at TIMESTAMP(3) NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at TIMESTAMP(3) NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
UNIQUE KEY uk_portal_sessions_token (session_token),
KEY idx_portal_sessions_site_id (site_id),
KEY idx_portal_sessions_portal_user_id (portal_user_id),
KEY idx_portal_sessions_last_active (last_active),
KEY idx_portal_sessions_site_user (site_id, portal_user_id),
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE,
FOREIGN KEY (portal_user_id) REFERENCES portal_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,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*
* Portal password reset tokens allow users to reset their password.
* Tokens are single-use and expire after a configurable time period.
*
* Flow:
* 1. User requests password reset with their email
* 2. System creates token and sends email with reset link
* 3. User clicks link, lands on password reset page
* 4. User sets new password
* 5. Token marked as used (used_at set)
*
* @return void
*/
public function up()
{
DB::statement("
CREATE TABLE portal_password_resets (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
site_id BIGINT NOT NULL,
portal_user_id BIGINT NOT NULL,
token VARCHAR(128) NOT NULL,
expires_at TIMESTAMP(3) NOT NULL,
used_at 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),
UNIQUE KEY uk_portal_password_resets_token (token),
KEY idx_portal_password_resets_site_id (site_id),
KEY idx_portal_password_resets_portal_user_id (portal_user_id),
KEY idx_portal_password_resets_expires_at (expires_at),
KEY idx_portal_password_resets_used_at (used_at),
FOREIGN KEY (site_id) REFERENCES sites(id) ON DELETE CASCADE,
FOREIGN KEY (portal_user_id) REFERENCES portal_users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
}
};