Fix bin/publish: copy docs.dist from project root

Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

162
app/Console/Commands/CLAUDE.md Executable file
View File

@@ -0,0 +1,162 @@
# Console Commands Directory Documentation
This directory contains Artisan console commands used for maintenance, utilities, and administrative functions within the RSpade application.
## CLAUDE.md File Standards
Each CLAUDE.md file in the project follows these standards:
1. **Purpose**: The file begins with a brief synopsis of the directory's purpose and role in the application.
2. **File Index**: Contains a list of important files with their sizes and last modified dates.
- When visiting a directory, always run `ls -la` to get current file sizes
- If a file's current size differs from what's documented in CLAUDE.md, the file has changed
- Before trusting information about a changed file, first read the current version and update the CLAUDE.md documentation
3. **File Documentation**: For each important file, includes:
- Short description of purpose and functionality
- Key points of information necessary for understanding the file
- Important implementation details or architectural considerations
4. **Selective Coverage**: Only documents important files that contribute to understanding the codebase
- Images, temporary files, and generated content are typically not documented
- Configuration files, models, controllers, and other architectural components are always documented
5. **Additional Context**: May include other critical information about the directory's role in the system
Always check file sizes against the current state before relying on the documentation in CLAUDE.md files.
## Important Files
### Database Safety Guardrails
- **RestrictedDatabaseCommand.php** (2838 bytes) - Base class for restricted commands
- Provides standardized messaging for disabled database operations
- Enforces forward-only migration policy
- Offers guidance on alternative approaches
- Ensures safety for automated systems and AI agents
- **Database/WipeCommand.php** (946 bytes) - Override for db:wipe
- Prevents complete database destruction
- Protects against accidental data loss
- **Migrate/FreshCommand.php** (1528 bytes) - Override for migrate:fresh
- Prevents dropping and recreating all tables
- Maintains data integrity
- **Migrate/ResetCommand.php** (1109 bytes) - Override for migrate:reset
- Prevents rollback of all migrations
- Ensures forward-only migration strategy
- **Migrate/RefreshCommand.php** (1316 bytes) - Override for migrate:refresh
- Prevents reset and re-run of migrations
- Protects existing data
- **Migrate/RollbackCommand.php** (1343 bytes) - Override for migrate:rollback
- Prevents rollback of migrations
- Enforces schema evolution through new migrations only
### Schema Maintenance Commands
- **Maint_Migrate.php** (3482 bytes) - Enhanced migration command
- Extends Laravel's migrate command with additional maintenance steps
- Runs required table column checks
- Regenerates model constants
- Exports constants to JavaScript
- Usage: `php artisan maint:migrate`
- **Migrate/MigrateNormalizeSchema.php** - Normalizes database schema to framework standards
- Standardizes data types (INT→BIGINT, TEXT→LONGTEXT, FLOAT→DOUBLE)
- Converts character encoding to UTF8MB4 for full Unicode/emoji support
- Adds required columns (created_at, updated_at, created_by, updated_by)
- Adds indexes on timestamp columns
- Updates datetime precision to milliseconds
- Usage: `php artisan migrate:normalize_schema`
- **Note**: Automatically called during migrations - manual execution rarely needed
### Code Generation Commands
- **Migrate/MigrateRegenerateConstants.php** - Model constant generation
- Scans model files for static $enums properties
- Generates class constants for enum values
- Updates PHPDoc comments with property and method tags
- Adds $dates property with datetime columns
- Validates enum definitions for consistency
- Updates model files in-place with constants and docblocks
- Usage: `php artisan migrate:regenerate_constants`
- **Note**: Automatically called during migrations - manual execution rarely needed
### Content Management Commands
- **CreateSampleKnowledgeBase.php** (14626 bytes) - Sample content generation
- Creates sample knowledge base articles for testing
- Generates categories and content hierarchy
- Adds formatted content with Markdown
- Creates content relationships and metadata
- Usage: `php artisan create:sample-kb`
- **FeatureKnowledgeBaseArticles.php** (1594 bytes) - Content curation
- Selects and features knowledge base articles
- Updates featured status for homepage display
- Manages featured article ordering
- Usage: `php artisan feature:kb-articles`
### Utility Commands
- **GenerateSitemap.php** (4206 bytes) - SEO sitemap generation
- Creates XML sitemap for search engines
- Includes all public routes and content pages
- Sets priority and change frequency
- Optimizes for search engine indexing
- Usage: `php artisan generate:sitemap`
- **GetEnvironment.php** (579 bytes) - Environment diagnostic
- Displays current application environment
- Shows configuration values for debugging
- Helps with environment-specific troubleshooting
- Usage: `php artisan env:get`
## Command Categories
The commands are organized into several functional categories:
1. **Maintenance Commands** (prefix: `maint:`)
- Database and schema maintenance
- Model code generation
- System consistency checks
2. **Utility Commands** (prefix: `utility:`)
- Helper functions for development
- Code generation utilities
- Export functionality
3. **Content Commands** (no standard prefix)
- Sample content generation
- Content management and curation
- Seeding and fixture creation
4. **Diagnostic Commands** (usually prefixed with the subsystem name)
- System status and health checks
- Configuration validation
- Performance diagnostics
## Important Concepts
1. **Enum System Integration**: Several commands work with the model enum system, generating constants and JavaScript exports.
2. **Database Schema Management**: Commands ensure consistent schema structure and features across tables.
3. **Code Generation**: Commands generate code and documentation to reduce manual work and ensure consistency.
4. **Content Management**: Commands facilitate content seeding and management for testing and initial setup.
## Usage in Development Workflow
These commands are typically used in the following scenarios:
1. After database migrations to ensure schema consistency
2. During development to keep model constants in sync with enum definitions
3. For generating test data and sample content
4. As part of deployment processes to prepare the application
The commands can be run manually or as part of automated scripts, and many are integrated with Laravel's migration system to run automatically when migrations are executed.

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
/**
* Base class for framework developer commands
*
* Commands extending this class will be hidden from the artisan command list
* unless IS_FRAMEWORK_DEVELOPER=true is set in the .env file.
*
* These commands can still be called directly, but are hidden to avoid
* confusion for end users who shouldn't need to use them.
*/
abstract class FrameworkDeveloperCommand extends Command
{
/**
* Hide command from list unless framework developer mode is enabled
*
* @var bool
*/
protected $hidden = false;
/**
* Create a new command instance
*/
public function __construct()
{
parent::__construct();
// Hide command unless IS_FRAMEWORK_DEVELOPER flag is set
$this->hidden = !env('IS_FRAMEWORK_DEVELOPER', false);
}
/**
* Get the console command description with framework developer indicator
*
* @return string
*/
public function getDescription(): string
{
$description = parent::getDescription();
// Add prefix if in framework developer mode
if (env('IS_FRAMEWORK_DEVELOPER', false)) {
return "[Framework Dev] {$description}";
}
return $description;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* CODING CONVENTION:
* This file follows the coding convention where variable_names and function_names
* use snake_case (underscore_wherever_possible).
*/
namespace App\Console\Commands;
use Illuminate\Console\Command;
class GetEnvironment extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'env';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get the current application environment';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->line(app()->environment());
return 0;
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Encryption\Encrypter;
/**
* Override Laravel's key:generate to prevent accidental key regeneration
*
* This command replaces the default key:generate behavior with a safer version
* that requires explicit --force flag when a key already exists.
*/
class KeyGenerateOverride extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'key:generate
{--show : Display the key instead of modifying files}
{--force : Force the operation even if key exists}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Set the application key (requires --force if key exists)';
/**
* Execute the console command.
*/
public function handle()
{
$current_key = config('app.key');
// Check if key already exists and --force not provided
if ($current_key && !$this->option('force')) {
$this->error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
$this->error(' APPLICATION KEY ALREADY EXISTS');
$this->error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
$this->newLine();
$this->line('Current key: <fg=yellow>' . substr($current_key, 0, 20) . '...</>');
$this->newLine();
$this->warn('⚠️ Regenerating the application key will cause:');
$this->warn(' • All existing encrypted data becomes unreadable');
$this->warn(' • All user sessions invalidated (everyone logged out)');
$this->warn(' • All password reset tokens invalidated');
$this->warn(' • All remember-me cookies invalidated');
$this->newLine();
$this->error('If you really need to regenerate (THIS IS DESTRUCTIVE):');
$this->line(' <fg=red>php artisan key:generate --force</>');
$this->newLine();
$this->info('For first-time setup (when key is empty):');
$this->line(' <fg=green>php artisan key:generate</>');
$this->newLine();
$this->error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
return 1;
}
// If --force provided with existing key, show additional warning
if ($current_key && $this->option('force')) {
$this->warn('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
$this->warn(' DESTRUCTIVE OPERATION - REGENERATING APPLICATION KEY');
$this->warn('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
$this->newLine();
$this->error('This will DESTROY all encrypted data and invalidate all sessions!');
$this->newLine();
if (!$this->confirm('Are you absolutely sure you want to continue?', false)) {
$this->info('Operation cancelled.');
return 0;
}
$this->newLine();
}
// Generate new key
$key = $this->generate_random_key();
if ($this->option('show')) {
$this->line('<comment>' . $key . '</comment>');
return 0;
}
// Set key in .env file
if (!$this->set_key_in_environment_file($key)) {
$this->error('Failed to write key to .env file');
return 1;
}
$this->laravel['config']['app.key'] = $key;
$this->info('Application key set successfully.');
return 0;
}
/**
* Generate a random key for the application.
*/
protected function generate_random_key(): string
{
return 'base64:' . base64_encode(
Encrypter::generateKey($this->laravel['config']['app.cipher'])
);
}
/**
* Set the application key in the environment file.
*/
protected function set_key_in_environment_file(string $key): bool
{
$env_file = $this->laravel->environmentFilePath();
$current_key = $this->laravel['config']['app.key'];
if (strlen($current_key) !== 0) {
// Replace existing key
$replaced = preg_replace(
$this->key_replacement_pattern(),
'APP_KEY=' . $key,
$input = file_get_contents($env_file)
);
if ($replaced === $input || $replaced === null) {
$this->error('Unable to set application key. Manual setting required.');
return false;
}
} else {
// Add new key
$replaced = file_get_contents($env_file) . PHP_EOL . 'APP_KEY=' . $key . PHP_EOL;
}
file_put_contents($env_file, $replaced);
return true;
}
/**
* Get a regex pattern that will match APP_KEY with any random key.
*/
protected function key_replacement_pattern(): string
{
$escaped = preg_quote('=' . $this->laravel['config']['app.key'], '/');
return "/^APP_KEY{$escaped}/m";
}
}

View File

@@ -0,0 +1,128 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Encryption\Encrypter;
use Illuminate\Support\Str;
class KeyGenerateSafe extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'key:generate:safe
{--show : Display the key instead of modifying files}
{--force : Force the operation to run when in production}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate application key only if one does not exist (prevents accidental regeneration)';
/**
* Execute the console command.
*/
public function handle()
{
$current_key = config('app.key');
// Check if key already exists
if ($current_key) {
$this->error('Application key already exists!');
$this->newLine();
$this->line('Current key: ' . $current_key);
$this->newLine();
$this->warn('Regenerating the application key will:');
$this->warn(' - Invalidate all existing sessions');
$this->warn(' - Break all encrypted data');
$this->warn(' - Require all users to log in again');
$this->newLine();
$this->error('If you really need to regenerate, use: php artisan key:generate --force');
$this->newLine();
return 1;
}
// Generate new key
$key = $this->generate_random_key();
if ($this->option('show')) {
$this->line('<comment>' . $key . '</comment>');
return 0;
}
// Check if .env file exists
$env_file = $this->laravel->environmentFilePath();
if (!file_exists($env_file)) {
$this->error('.env file not found at: ' . $env_file);
return 1;
}
// Set key in .env file
if (!$this->set_key_in_environment_file($key)) {
$this->error('Failed to write key to .env file');
return 1;
}
$this->laravel['config']['app.key'] = $key;
$this->info('Application key set successfully.');
return 0;
}
/**
* Generate a random key for the application.
*/
protected function generate_random_key(): string
{
return 'base64:' . base64_encode(
Encrypter::generateKey($this->laravel['config']['app.cipher'])
);
}
/**
* Set the application key in the environment file.
*/
protected function set_key_in_environment_file(string $key): bool
{
$env_file = $this->laravel->environmentFilePath();
$current_key = $this->laravel['config']['app.key'];
if (strlen($current_key) !== 0) {
// Replace existing key
$replaced = preg_replace(
$this->key_replacement_pattern(),
'APP_KEY=' . $key,
$input = file_get_contents($env_file)
);
if ($replaced === $input || $replaced === null) {
$this->error('Unable to set application key. Manual setting required.');
return false;
}
} else {
// Add new key
$replaced = file_get_contents($env_file) . PHP_EOL . 'APP_KEY=' . $key . PHP_EOL;
}
file_put_contents($env_file, $replaced);
return true;
}
/**
* Get a regex pattern that will match APP_KEY with any random key.
*/
protected function key_replacement_pattern(): string
{
$escaped = preg_quote('=' . $this->laravel['config']['app.key'], '/');
return "/^APP_KEY{$escaped}/m";
}
}

View File

@@ -0,0 +1,105 @@
<?php
/**
* CODING CONVENTION:
* This file follows the coding convention where variable_names and function_names
* use snake_case (underscore_wherever_possible).
*/
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Log;
/**
* Session Cleanup Command
* ========================
*
* PURPOSE:
* This command performs routine cleanup of expired and abandoned sessions from
* the database to prevent unbounded growth of the sessions table.
*
* CLEANUP RULES:
* 1. Guest sessions (user_id = null, site_id = null) older than 24 hours
* 2. Any sessions older than 3 years (regardless of user/site association)
*
* IMPLEMENTATION:
* - Uses raw DB::statement() for efficiency
* - Runs hourly via Laravel scheduler
* - Tracks deletion counts for monitoring
*
* WHY RAW SQL:
* - More efficient for bulk deletions
* - Clear audit trail in logs
* - Avoids ORM overhead for maintenance tasks
*
* INDEXING:
* The sessions table has indexes on:
* - user_id
* - site_id
* - updated_at
* - (updated_at, user_id) composite
* These indexes ensure efficient query execution.
*/
class SessionCleanupCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'session:cleanup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clean up expired and abandoned sessions from the database';
/**
* Execute the console command.
*/
public function handle()
{
$start_time = microtime(true);
// Delete guest sessions older than 24 hours
// Using MySQL date functions for accuracy and performance
$guest_count = DB::delete('
DELETE FROM sessions
WHERE updated_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND user_id IS NULL
AND site_id IS NULL
');
// Delete any sessions older than 3 years
$old_count = DB::delete('
DELETE FROM sessions
WHERE updated_at < DATE_SUB(NOW(), INTERVAL 1 YEAR)
');
$total_deleted = $guest_count + $old_count;
$execution_time = round(microtime(true) - $start_time, 3);
// Log results
if ($total_deleted > 0) {
$this->info('Session cleanup completed:');
$this->info(" • Guest sessions (>24h): {$guest_count} deleted");
$this->info(" • Old sessions (>3y): {$old_count} deleted");
$this->info(" • Total: {$total_deleted} sessions removed");
$this->info(" • Execution time: {$execution_time}s");
// Also log to Laravel log for monitoring
Log::info("Session cleanup: {$total_deleted} sessions deleted", [
'guest_sessions' => $guest_count,
'old_sessions' => $old_count,
'execution_time' => $execution_time,
]);
} else {
$this->info("No sessions to clean up (execution time: {$execution_time}s)");
}
return 0;
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* CODING CONVENTION:
* This file follows the coding convention where variable_names and function_names
* use snake_case (underscore_wherever_possible).
*/
namespace App\Console\Commands\Temp;
use Illuminate\Console\Command;
use App\RSpade\Core\Build_Manager;
class ClearCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'temp:clear
{--older-than=0 : Clear files older than N hours}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clear temporary files';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$older_than = (int) $this->option('older-than');
if ($older_than > 0) {
$count = Build_Manager::clear_temp($older_than);
$this->info("Cleared $count temporary files older than $older_than hours.");
} else {
$count = Build_Manager::clear_temp();
$this->info("Cleared all $count temporary files.");
}
return 0;
}
}

75
app/Console/Kernel.php Executable file
View File

@@ -0,0 +1,75 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// Run task scheduler every minute
$schedule->command('task:scheduler')
->everyMinute()
->runInBackground()
->withoutOverlapping();
// Generate sitemap every 3 hours
$schedule->command('sitemap:generate --queue')
->cron('0 */3 * * *')
->runInBackground()
->withoutOverlapping();
// Run task cleanup daily
$schedule->command('task:scheduler --cleanup')
->daily()
->at('02:00')
->runInBackground()
->withoutOverlapping();
// Run session cleanup every hour
$schedule->command('session:cleanup')
->hourly()
->runInBackground()
->withoutOverlapping();
// Process geocoding tasks hourly
$schedule->command('geocoding:process --limit=20')
->hourly()
->runInBackground()
->withoutOverlapping();
// Process email queue every minute
$schedule->command('email:process --batch=10')
->everyMinute()
->runInBackground()
->withoutOverlapping();
// Process document conversions every 5 minutes
$schedule->command('documents:process --limit=10')
->everyFiveMinutes()
->runInBackground()
->withoutOverlapping();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands'); // Application commands
$this->load(__DIR__.'/../RSpade/Commands'); // Framework commands
require base_path('routes/console.php');
}
}